Skip to content

Commit

Permalink
Type-safe date fields and inline classes kdocs
Browse files Browse the repository at this point in the history
  • Loading branch information
alllex committed Oct 3, 2023
1 parent e580a04 commit 83fa5db
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 19 deletions.
47 changes: 32 additions & 15 deletions buildSrc/src/main/kotlin/me/alllex/tbot/apigen/BotApiGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,55 +105,65 @@ val methodVariations = listOf(
data class ValueType(
val name: String,
val backingType: String,
val docString: String? = null,
val fieldPredicate: (type: BotApiElementName, field: BotApiElement.Field) -> Boolean
)

val valueTypes = listOf(
ValueType("ChatId", "Long") { type, field ->
ValueType("ChatId", "Long", "Chat identifier.") { type, field ->
(type.value == "Chat" && field.serialName == "id") || field.serialName.endsWith("chat_id")
},
ValueType("UserId", "Long") { type, field ->
ValueType("UserId", "Long", "User identifier.") { type, field ->
(type.value == "User" && field.serialName == "id") || field.serialName.endsWith("user_id")
},
ValueType("MessageId", "Long") { _, field ->
ValueType("MessageId", "Long", "Opaque message identifier.") { _, field ->
!field.serialName.endsWith("inline_message_id") && field.serialName.endsWith("message_id")
},
ValueType("InlineMessageId", "String") { _, field ->
ValueType("InlineMessageId", "String", "Opaque inline message identifier.") { _, field ->
field.serialName.endsWith("inline_message_id")
},
ValueType("MessageThreadId", "Long") { _, field ->
ValueType("MessageThreadId", "Long", "Opaque message thread identifier.") { _, field ->
field.serialName.endsWith("message_thread_id")
},
ValueType("CallbackQueryId", "String") { type, field ->
ValueType("CallbackQueryId", "String", "Opaque [CallbackQuery] identifier.") { type, field ->
(type.value == "CallbackQuery" && field.serialName == "id") || field.serialName.endsWith("callback_query_id")
},
ValueType("InlineQueryId", "String") { type, field ->
ValueType("InlineQueryId", "String", "Opaque [InlineQuery] identifier.") { type, field ->
(type.value == "InlineQuery" && field.serialName == "id") || field.serialName.endsWith("inline_query_id")
},
ValueType("InlineQueryResultId", "String") { type, field ->
ValueType("InlineQueryResultId", "String", "Opaque [InlineQueryResult] identifier.") { type, field ->
(type.value.startsWith("InlineQuery") && field.serialName == "id") ||
(type.value == "ChosenInlineResult" && field.serialName == "result_id")
},
ValueType("FileId", "String") { _, field ->
ValueType("FileId", "String", "Identifier for a file, which can be used to download or reuse the file.") { _, field ->
field.serialName.endsWith("file_id")
},
ValueType("FileUniqueId", "String") { _, field ->
ValueType(
"FileUniqueId",
"String",
"Unique identifier for a file, which is supposed to be the same over time and for different bots.\n\nIt can't be used to download or reuse the file."
) { _, field ->
field.serialName.endsWith("file_unique_id")
},
ValueType("ShippingQueryId", "String") { type, field ->
ValueType("ShippingQueryId", "String", "Opaque [ShippingQuery] identifier.") { type, field ->
(type.value == "ShippingQuery" && field.serialName == "id") || field.serialName.endsWith("shipping_query_id")
},
ValueType("WebAppQueryId", "String") { _, field ->
ValueType("WebAppQueryId", "String", "Opaque web-app query identifier.") { _, field ->
field.serialName.endsWith("web_app_query_id")
},
ValueType("CustomEmojiId", "String") { _, field ->
ValueType("CustomEmojiId", "String", "Opaque custom emoji identifier.") { _, field ->
field.serialName.endsWith("custom_emoji_id")
},
ValueType("Seconds", "Long") { _, field ->
ValueType("Seconds", "Long", "Duration in seconds.") { _, field ->
field.serialName in setOf("cache_time", "duration", "life_period", "open_period", "timeout", "retry_after")
},
ValueType("UnixTimestamp", "Long") { _, field ->
ValueType(
"UnixTimestamp",
"Long",
"Unix time - **number of seconds** that have elapsed since 00:00:00 UTC on 1 January 1970.",
) { _, field ->
field.serialName in setOf(
"date",
"last_error_date",
"last_synchronization_error_date",
"emoji_status_expiration_date",
Expand Down Expand Up @@ -698,6 +708,13 @@ class BotApiGenerator {
}

private fun generateValueTypeSourceCode(valueType: ValueType): String = buildString {
valueType.docString?.let {
appendLine("/**")
it.lines().forEach { line ->
appendLine(" * $line")
}
appendLine(" */")
}
appendLine("@Serializable")
appendLine("@JvmInline")
appendLine("value class ${valueType.name}(val value: ${valueType.backingType}) {")
Expand Down
53 changes: 50 additions & 3 deletions src/main/generated-kotlin/me/alllex/tbot/api/model/Types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ data class Chat(
@Serializable
data class Message(
val messageId: MessageId,
val date: Long,
val date: UnixTimestamp,
val chat: Chat,
val messageThreadId: MessageThreadId? = null,
val from: User? = null,
Expand Down Expand Up @@ -1546,7 +1546,7 @@ data class ChatMemberBanned(
data class ChatMemberUpdated(
val chat: Chat,
val from: User,
val date: Long,
val date: UnixTimestamp,
val oldChatMember: ChatMember,
val newChatMember: ChatMember,
val inviteLink: ChatInviteLink? = null,
Expand All @@ -1569,7 +1569,7 @@ data class ChatJoinRequest(
val chat: Chat,
val from: User,
val userChatId: ChatId,
val date: Long,
val date: UnixTimestamp,
val bio: String? = null,
val inviteLink: ChatInviteLink? = null,
) {
Expand Down Expand Up @@ -3353,90 +3353,137 @@ object ReplyMarkupSerializer : JsonContentPolymorphicSerializer<ReplyMarkup>(Rep
}
}

/**
* Chat identifier.
*/
@Serializable
@JvmInline
value class ChatId(val value: Long) {
override fun toString(): String = "ChatId(${quoteWhenWhitespace(value)})"
}

/**
* User identifier.
*/
@Serializable
@JvmInline
value class UserId(val value: Long) {
override fun toString(): String = "UserId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque message identifier.
*/
@Serializable
@JvmInline
value class MessageId(val value: Long) {
override fun toString(): String = "MessageId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque inline message identifier.
*/
@Serializable
@JvmInline
value class InlineMessageId(val value: String) {
override fun toString(): String = "InlineMessageId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque message thread identifier.
*/
@Serializable
@JvmInline
value class MessageThreadId(val value: Long) {
override fun toString(): String = "MessageThreadId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque [CallbackQuery] identifier.
*/
@Serializable
@JvmInline
value class CallbackQueryId(val value: String) {
override fun toString(): String = "CallbackQueryId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque [InlineQuery] identifier.
*/
@Serializable
@JvmInline
value class InlineQueryId(val value: String) {
override fun toString(): String = "InlineQueryId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque [InlineQueryResult] identifier.
*/
@Serializable
@JvmInline
value class InlineQueryResultId(val value: String) {
override fun toString(): String = "InlineQueryResultId(${quoteWhenWhitespace(value)})"
}

/**
* Identifier for a file, which can be used to download or reuse the file.
*/
@Serializable
@JvmInline
value class FileId(val value: String) {
override fun toString(): String = "FileId(${quoteWhenWhitespace(value)})"
}

/**
* Unique identifier for a file, which is supposed to be the same over time and for different bots.
*
* It can't be used to download or reuse the file.
*/
@Serializable
@JvmInline
value class FileUniqueId(val value: String) {
override fun toString(): String = "FileUniqueId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque [ShippingQuery] identifier.
*/
@Serializable
@JvmInline
value class ShippingQueryId(val value: String) {
override fun toString(): String = "ShippingQueryId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque web-app query identifier.
*/
@Serializable
@JvmInline
value class WebAppQueryId(val value: String) {
override fun toString(): String = "WebAppQueryId(${quoteWhenWhitespace(value)})"
}

/**
* Opaque custom emoji identifier.
*/
@Serializable
@JvmInline
value class CustomEmojiId(val value: String) {
override fun toString(): String = "CustomEmojiId(${quoteWhenWhitespace(value)})"
}

/**
* Duration in seconds.
*/
@Serializable
@JvmInline
value class Seconds(val value: Long) {
override fun toString(): String = "Seconds(${quoteWhenWhitespace(value)})"
}

/**
* Unix time - **number of seconds** that have elapsed since 00:00:00 UTC on 1 January 1970.
*/
@Serializable
@JvmInline
value class UnixTimestamp(val value: Long) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/me/alllex/tbot/api/model/Helpers.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.alllex.tbot.api.model

import me.alllex.tbot.api.client.TelegramBotApiClient
import java.time.Instant
import kotlin.time.Duration


Expand All @@ -12,6 +13,8 @@ val Duration.asSeconds get() = Seconds(this.inWholeSeconds)

val User.usernameOrId: String get() = "@" + (username ?: id.value.toString())

fun UnixTimestamp.toInstant(): Instant = Instant.ofEpochMilli(value * 1000)

val MessageEntity.isBotCommand get(): Boolean = type == "bot_command"

fun Message.findLeadCommand(): MessageEntity? {
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.1
0.4.0-SNAPSHOT

0 comments on commit 83fa5db

Please sign in to comment.