1
- package org.partiql.planner
1
+ package org.partiql.planner.internal
2
2
3
3
import org.partiql.errors.ProblemDetails
4
4
import org.partiql.errors.ProblemSeverity
@@ -13,21 +13,45 @@ import org.partiql.types.StaticType
13
13
* This information can be used to generate end-user readable error messages and is also easy to assert
14
14
* equivalence in unit tests.
15
15
*/
16
- public sealed class PlanningProblemDetails (
16
+ internal open class PlanningProblemDetails (
17
17
override val severity : ProblemSeverity ,
18
- public val messageFormatter : () -> String ,
18
+ val messageFormatter : () -> String ,
19
19
) : ProblemDetails {
20
20
21
+ companion object {
22
+ private fun quotationHint (caseSensitive : Boolean ) =
23
+ if (caseSensitive) {
24
+ // Individuals that are new to SQL often try to use double quotes for string literals.
25
+ // Let's help them out a bit.
26
+ " Hint: did you intend to use single-quotes (') here? Remember that double-quotes (\" ) denote " +
27
+ " quoted identifiers and single-quotes denote strings."
28
+ } else {
29
+ " "
30
+ }
31
+
32
+ private fun Identifier.sql (): String = when (this ) {
33
+ is Identifier .Qualified -> this .sql()
34
+ is Identifier .Symbol -> this .sql()
35
+ }
36
+
37
+ private fun Identifier.Qualified.sql (): String = root.sql() + " ." + steps.joinToString(" ." ) { it.sql() }
38
+
39
+ private fun Identifier.Symbol.sql (): String = when (caseSensitivity) {
40
+ Identifier .CaseSensitivity .SENSITIVE -> " \" $symbol \" "
41
+ Identifier .CaseSensitivity .INSENSITIVE -> symbol
42
+ }
43
+ }
44
+
21
45
override fun toString (): String = message
22
46
override val message: String get() = messageFormatter()
23
47
24
- public data class ParseError (val parseErrorMessage : String ) :
48
+ data class ParseError (val parseErrorMessage : String ) :
25
49
PlanningProblemDetails (ProblemSeverity .ERROR , { parseErrorMessage })
26
50
27
- public data class CompileError (val errorMessage : String ) :
51
+ data class CompileError (val errorMessage : String ) :
28
52
PlanningProblemDetails (ProblemSeverity .ERROR , { errorMessage })
29
53
30
- public data class UndefinedVariable (val id : BindingPath ) :
54
+ data class UndefinedVariable (val id : BindingPath ) :
31
55
PlanningProblemDetails (
32
56
ProblemSeverity .ERROR ,
33
57
{
@@ -37,7 +61,7 @@ public sealed class PlanningProblemDetails(
37
61
}
38
62
)
39
63
40
- public data class UndefinedDmlTarget (val variableName : String , val caseSensitive : Boolean ) :
64
+ data class UndefinedDmlTarget (val variableName : String , val caseSensitive : Boolean ) :
41
65
PlanningProblemDetails (
42
66
ProblemSeverity .ERROR ,
43
67
{
@@ -47,25 +71,25 @@ public sealed class PlanningProblemDetails(
47
71
}
48
72
)
49
73
50
- public data class VariablePreviouslyDefined (val variableName : String ) :
74
+ data class VariablePreviouslyDefined (val variableName : String ) :
51
75
PlanningProblemDetails (
52
76
ProblemSeverity .ERROR ,
53
77
{ " The variable '$variableName ' was previously defined." }
54
78
)
55
79
56
- public data class UnimplementedFeature (val featureName : String ) :
80
+ data class UnimplementedFeature (val featureName : String ) :
57
81
PlanningProblemDetails (
58
82
ProblemSeverity .ERROR ,
59
83
{ " The syntax at this location is valid but utilizes unimplemented PartiQL feature '$featureName '" }
60
84
)
61
85
62
- public object InvalidDmlTarget :
86
+ object InvalidDmlTarget :
63
87
PlanningProblemDetails (
64
88
ProblemSeverity .ERROR ,
65
89
{ " Expression is not a valid DML target. Hint: only table names are allowed here." }
66
90
)
67
91
68
- public object InsertValueDisallowed :
92
+ object InsertValueDisallowed :
69
93
PlanningProblemDetails (
70
94
ProblemSeverity .ERROR ,
71
95
{
@@ -74,7 +98,7 @@ public sealed class PlanningProblemDetails(
74
98
}
75
99
)
76
100
77
- public object InsertValuesDisallowed :
101
+ object InsertValuesDisallowed :
78
102
PlanningProblemDetails (
79
103
ProblemSeverity .ERROR ,
80
104
{
@@ -83,27 +107,32 @@ public sealed class PlanningProblemDetails(
83
107
}
84
108
)
85
109
86
- public data class UnexpectedType (
110
+ data class UnexpectedType (
87
111
val actualType : StaticType ,
88
112
val expectedTypes : Set <StaticType >,
89
113
) : PlanningProblemDetails(ProblemSeverity .ERROR , {
90
114
" Unexpected type $actualType , expected one of ${expectedTypes.joinToString()} "
91
115
})
92
116
93
- public data class UnknownFunction (
117
+ data class UnknownFunction (
94
118
val identifier : String ,
95
119
val args : List <StaticType >,
96
120
) : PlanningProblemDetails(ProblemSeverity .ERROR , {
97
121
val types = args.joinToString { " <${it.toString().lowercase()} >" }
98
122
" Unknown function `$identifier ($types )"
99
123
})
100
124
101
- public object ExpressionAlwaysReturnsNullOrMissing : PlanningProblemDetails(
125
+ data class ExpressionAlwaysReturnsMissing (val reason : String? = null ) : PlanningProblemDetails(
126
+ severity = ProblemSeverity .ERROR ,
127
+ messageFormatter = { " Expression always returns null or missing: caused by $reason " }
128
+ )
129
+
130
+ object ExpressionAlwaysReturnsNullOrMissing : PlanningProblemDetails(
102
131
severity = ProblemSeverity .ERROR ,
103
132
messageFormatter = { " Expression always returns null or missing." }
104
133
)
105
134
106
- public data class InvalidArgumentTypeForFunction (
135
+ data class InvalidArgumentTypeForFunction (
107
136
val functionName : String ,
108
137
val expectedType : StaticType ,
109
138
val actualType : StaticType ,
@@ -113,7 +142,7 @@ public sealed class PlanningProblemDetails(
113
142
messageFormatter = { " Invalid argument type for $functionName . Expected $expectedType but got $actualType " }
114
143
)
115
144
116
- public data class IncompatibleTypesForOp (
145
+ data class IncompatibleTypesForOp (
117
146
val actualTypes : List <StaticType >,
118
147
val operator : String ,
119
148
) :
@@ -122,31 +151,9 @@ public sealed class PlanningProblemDetails(
122
151
messageFormatter = { " ${actualTypes.joinToString()} is/are incompatible data types for the '$operator ' operator." }
123
152
)
124
153
125
- public data class UnresolvedExcludeExprRoot (val root : String ) :
154
+ data class UnresolvedExcludeExprRoot (val root : String ) :
126
155
PlanningProblemDetails (
127
156
ProblemSeverity .ERROR ,
128
157
{ " Exclude expression given an unresolvable root '$root '" }
129
158
)
130
159
}
131
-
132
- private fun quotationHint (caseSensitive : Boolean ) =
133
- if (caseSensitive) {
134
- // Individuals that are new to SQL often try to use double quotes for string literals.
135
- // Let's help them out a bit.
136
- " Hint: did you intend to use single-quotes (') here? Remember that double-quotes (\" ) denote " +
137
- " quoted identifiers and single-quotes denote strings."
138
- } else {
139
- " "
140
- }
141
-
142
- private fun Identifier.sql (): String = when (this ) {
143
- is Identifier .Qualified -> this .sql()
144
- is Identifier .Symbol -> this .sql()
145
- }
146
-
147
- private fun Identifier.Qualified.sql (): String = root.sql() + " ." + steps.joinToString(" ." ) { it.sql() }
148
-
149
- private fun Identifier.Symbol.sql (): String = when (caseSensitivity) {
150
- Identifier .CaseSensitivity .SENSITIVE -> " \" $symbol \" "
151
- Identifier .CaseSensitivity .INSENSITIVE -> symbol
152
- }
0 commit comments