-
Notifications
You must be signed in to change notification settings - Fork 496
/
MySqlTypeResolver.kt
106 lines (100 loc) · 4.41 KB
/
MySqlTypeResolver.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package app.cash.sqldelight.dialects.mysql
import app.cash.sqldelight.dialect.api.IntermediateType
import app.cash.sqldelight.dialect.api.PrimitiveType
import app.cash.sqldelight.dialect.api.PrimitiveType.ARGUMENT
import app.cash.sqldelight.dialect.api.PrimitiveType.BLOB
import app.cash.sqldelight.dialect.api.PrimitiveType.INTEGER
import app.cash.sqldelight.dialect.api.PrimitiveType.REAL
import app.cash.sqldelight.dialect.api.PrimitiveType.TEXT
import app.cash.sqldelight.dialect.api.TypeResolver
import app.cash.sqldelight.dialect.api.encapsulatingType
import app.cash.sqldelight.dialects.mysql.MySqlType.BIG_INT
import app.cash.sqldelight.dialects.mysql.MySqlType.SMALL_INT
import app.cash.sqldelight.dialects.mysql.MySqlType.TINY_INT
import app.cash.sqldelight.dialects.mysql.grammar.psi.MySqlExtensionExpr
import app.cash.sqldelight.dialects.mysql.grammar.psi.MySqlTypeName
import com.alecstrong.sql.psi.core.psi.SqlExpr
import com.alecstrong.sql.psi.core.psi.SqlFunctionExpr
import com.alecstrong.sql.psi.core.psi.SqlTypeName
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
class MySqlTypeResolver(
private val parentResolver: TypeResolver,
) : TypeResolver by parentResolver {
override fun resolvedType(expr: SqlExpr): IntermediateType {
return when (expr) {
is MySqlExtensionExpr -> encapsulatingType(
PsiTreeUtil.findChildrenOfType(expr.ifExpr, SqlExpr::class.java).drop(1),
INTEGER,
REAL,
TEXT,
BLOB,
)
else -> parentResolver.resolvedType(expr)
}
}
override fun argumentType(parent: PsiElement, argument: SqlExpr): IntermediateType {
when (parent) {
is MySqlExtensionExpr -> {
return if (argument == parent.ifExpr?.children?.first()) IntermediateType(PrimitiveType.BOOLEAN)
else IntermediateType(ARGUMENT)
}
}
return parentResolver.argumentType(parent, argument)
}
override fun functionType(functionExpr: SqlFunctionExpr): IntermediateType? {
return functionExpr.mySqlFunctionType() ?: parentResolver.functionType(functionExpr)
}
private fun SqlFunctionExpr.mySqlFunctionType() = when (functionName.text.lowercase()) {
"greatest" -> encapsulatingType(exprList, INTEGER, REAL, TEXT, BLOB)
"concat" -> encapsulatingType(exprList, TEXT)
"last_insert_id" -> IntermediateType(INTEGER)
"row_count" -> IntermediateType(INTEGER)
"microsecond", "second", "minute", "hour", "day", "week", "month", "year" -> IntermediateType(
INTEGER,
)
"sin", "cos", "tan" -> IntermediateType(REAL)
"coalesce", "ifnull" -> encapsulatingType(exprList, TINY_INT, SMALL_INT, MySqlType.INTEGER, INTEGER, BIG_INT, REAL, TEXT, BLOB)
"max" -> encapsulatingType(exprList, TINY_INT, SMALL_INT, MySqlType.INTEGER, INTEGER, BIG_INT, REAL, TEXT, BLOB).asNullable()
"min" -> encapsulatingType(exprList, BLOB, TEXT, TINY_INT, SMALL_INT, INTEGER, MySqlType.INTEGER, BIG_INT, REAL).asNullable()
"unix_timestamp" -> IntermediateType(TEXT)
"to_seconds" -> IntermediateType(INTEGER)
"json_arrayagg" -> IntermediateType(TEXT)
"date_add", "date_sub" -> IntermediateType(TEXT)
else -> null
}
override fun definitionType(typeName: SqlTypeName): IntermediateType = with(typeName) {
check(this is MySqlTypeName)
return IntermediateType(
when {
approximateNumericDataType != null -> REAL
binaryDataType != null -> BLOB
dateDataType != null -> {
when (dateDataType!!.firstChild.text) {
"DATE" -> MySqlType.DATE
"TIME" -> MySqlType.TIME
"DATETIME" -> MySqlType.DATETIME
"TIMESTAMP" -> MySqlType.TIMESTAMP
"YEAR" -> TEXT
else -> throw IllegalArgumentException("Unknown date type ${dateDataType!!.text}")
}
}
tinyIntDataType != null -> if (tinyIntDataType!!.text == "BOOLEAN") {
MySqlType.TINY_INT_BOOL
} else {
TINY_INT
}
smallIntDataType != null -> SMALL_INT
mediumIntDataType != null -> MySqlType.INTEGER
intDataType != null -> MySqlType.INTEGER
bigIntDataType != null -> BIG_INT
fixedPointDataType != null -> MySqlType.NUMERIC
jsonDataType != null -> TEXT
enumSetType != null -> TEXT
characterType != null -> TEXT
bitDataType != null -> MySqlType.BIT
else -> throw IllegalArgumentException("Unknown kotlin type for sql type ${this.text}")
},
)
}
}