Skip to main content

gluesql_core/translate/
error.rs

1use {serde::Serialize, std::fmt::Debug, strum_macros::Display, thiserror::Error};
2
3/// `CREATE TABLE` clauses that `GlueSQL` does not support yet.
4///
5/// Carried by [`TranslateError::UnsupportedCreateTableOption`] so callers
6/// can match exhaustively on every currently-rejected clause instead of
7/// inspecting a free-form string.
8#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
9pub enum CreateTableOption {
10    /// `CREATE TEMPORARY TABLE ...`
11    #[strum(to_string = "TEMPORARY clause")]
12    Temporary,
13
14    /// `CREATE TABLE ... LIKE <table>`
15    #[strum(to_string = "LIKE clause")]
16    Like,
17
18    /// `CREATE TABLE ... CLONE <table>`
19    #[strum(to_string = "CLONE clause")]
20    CloneTable,
21}
22
23/// `CREATE INDEX` clauses that `GlueSQL` does not support yet.
24///
25/// Carried by [`TranslateError::UnsupportedCreateIndexOption`] so callers
26/// can match exhaustively on every currently-rejected clause instead of
27/// inspecting a free-form string.
28#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
29pub enum CreateIndexOption {
30    /// `CREATE UNIQUE INDEX ...`
31    #[strum(to_string = "UNIQUE keyword")]
32    Unique,
33
34    /// `CREATE INDEX CONCURRENTLY ...`
35    #[strum(to_string = "CONCURRENTLY keyword")]
36    Concurrently,
37
38    /// `CREATE INDEX IF NOT EXISTS ...`
39    #[strum(to_string = "IF NOT EXISTS clause")]
40    IfNotExists,
41
42    /// `CREATE INDEX ... USING <method> ...`
43    #[strum(to_string = "USING clause")]
44    Using,
45
46    /// `CREATE INDEX ... INCLUDE (...)`
47    #[strum(to_string = "INCLUDE clause")]
48    Include,
49
50    /// `CREATE INDEX ... NULLS [NOT] DISTINCT`
51    #[strum(to_string = "NULLS DISTINCT clause")]
52    NullsDistinct,
53
54    /// `CREATE INDEX ... WITH (...)`
55    #[strum(to_string = "WITH clause")]
56    With,
57
58    /// `CREATE INDEX ... WHERE <predicate>`
59    #[strum(to_string = "WHERE clause")]
60    Where,
61}
62
63/// `INSERT` clauses that `GlueSQL` does not support yet.
64///
65/// Carried by [`TranslateError::UnsupportedInsertOption`] so callers can
66/// match exhaustively on every currently-rejected clause instead of
67/// inspecting a free-form string.
68#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
69pub enum InsertOption {
70    /// `INSERT ... RETURNING ...`
71    #[strum(to_string = "RETURNING clause")]
72    Returning,
73
74    /// `INSERT ... ON CONFLICT ...`
75    #[strum(to_string = "ON CONFLICT clause")]
76    OnConflict,
77
78    /// `INSERT INTO <table> AS <alias> ...`
79    #[strum(to_string = "table alias")]
80    TableAlias,
81
82    /// `INSERT INTO <table> PARTITION (...) ...`
83    #[strum(to_string = "PARTITION clause")]
84    Partition,
85
86    /// `INSERT OVERWRITE TABLE <table> ...`
87    #[strum(to_string = "OVERWRITE clause")]
88    Overwrite,
89
90    /// `INSERT TABLE <table> ...` (the `TABLE` keyword form)
91    #[strum(to_string = "TABLE keyword")]
92    TableKeyword,
93}
94
95/// `UPDATE` clauses that `GlueSQL` does not support yet.
96///
97/// Carried by [`TranslateError::UnsupportedUpdateOption`] so callers can
98/// match exhaustively on every currently-rejected clause instead of
99/// inspecting a free-form string.
100#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
101pub enum UpdateOption {
102    /// `UPDATE ... FROM ...`
103    #[strum(to_string = "FROM clause")]
104    From,
105
106    /// `UPDATE ... RETURNING ...`
107    #[strum(to_string = "RETURNING clause")]
108    Returning,
109}
110
111/// `DELETE` clauses that `GlueSQL` does not support yet.
112///
113/// Carried by [`TranslateError::UnsupportedDeleteOption`] so callers can
114/// match exhaustively on every currently-rejected clause instead of
115/// inspecting a free-form string.
116#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
117pub enum DeleteOption {
118    /// `DELETE ... USING ...`
119    #[strum(to_string = "USING clause")]
120    Using,
121
122    /// `DELETE ... RETURNING ...`
123    #[strum(to_string = "RETURNING clause")]
124    Returning,
125
126    /// `DELETE ... ORDER BY ...`
127    #[strum(to_string = "ORDER BY clause")]
128    OrderBy,
129
130    /// `DELETE ... LIMIT ...`
131    #[strum(to_string = "LIMIT clause")]
132    Limit,
133}
134
135/// Transaction statement (`START TRANSACTION`/`COMMIT`/`ROLLBACK`) clauses
136/// that `GlueSQL` does not support yet.
137///
138/// Carried by [`TranslateError::UnsupportedTransactionOption`] so callers can
139/// match exhaustively on every currently-rejected clause instead of
140/// inspecting a free-form string.
141#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
142pub enum TransactionOption {
143    /// `START TRANSACTION READ ONLY | READ WRITE | ISOLATION LEVEL ...`
144    #[strum(to_string = "transaction mode")]
145    Mode,
146
147    /// `BEGIN DEFERRED | IMMEDIATE | EXCLUSIVE` (`SQLite`)
148    #[strum(to_string = "transaction modifier")]
149    Modifier,
150
151    /// `COMMIT AND CHAIN` / `ROLLBACK AND CHAIN`
152    #[strum(to_string = "AND CHAIN clause")]
153    Chain,
154
155    /// `ROLLBACK TO [SAVEPOINT] <name>`
156    #[strum(to_string = "TO SAVEPOINT clause")]
157    Savepoint,
158}
159
160/// Query-level (`WITH`/`FETCH`/locking) clauses that `GlueSQL` does not
161/// support yet.
162///
163/// Carried by [`TranslateError::UnsupportedQueryOption`] so callers can
164/// match exhaustively on every currently-rejected clause instead of
165/// inspecting a free-form string.
166#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
167pub enum QueryOption {
168    /// `WITH <cte> ... SELECT ...`
169    #[strum(to_string = "WITH clause")]
170    With,
171
172    /// `SELECT ... FETCH FIRST ...`
173    #[strum(to_string = "FETCH clause")]
174    Fetch,
175
176    /// `SELECT ... FOR UPDATE` / other row-locking clauses
177    #[strum(to_string = "LOCK clause")]
178    Lock,
179}
180
181/// `SELECT` clauses that `GlueSQL` does not support yet.
182///
183/// Carried by [`TranslateError::UnsupportedSelectOption`] so callers can
184/// match exhaustively on every currently-rejected clause instead of
185/// inspecting a free-form string.
186#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
187pub enum SelectOption {
188    /// `SELECT ... INTO <table> ...`
189    #[strum(to_string = "INTO clause")]
190    Into,
191
192    /// `SELECT ... WINDOW <name> AS (...)`
193    #[strum(to_string = "WINDOW clause")]
194    Window,
195}
196
197/// `JOIN` constraint forms that `GlueSQL` does not support yet.
198///
199/// Carried by [`TranslateError::UnsupportedJoinConstraint`] so callers can
200/// match exhaustively on every currently-rejected form instead of
201/// inspecting a free-form string.
202#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
203pub enum JoinConstraintReason {
204    /// `... JOIN ... USING (...)`
205    #[strum(to_string = "USING")]
206    Using,
207
208    /// `... NATURAL JOIN ...`
209    #[strum(to_string = "NATURAL")]
210    Natural,
211}
212
213/// Serializes a `strum::Display`-backed enum as its display string, keeping
214/// JSON output identical to the pre-refactor `&'static str`/`String` fields
215/// without duplicating each variant's text in a second `#[serde(rename)]`.
216macro_rules! serialize_via_display {
217    ($($ty:ty),+ $(,)?) => {
218        $(
219            impl Serialize for $ty {
220                fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
221                    serializer.collect_str(self)
222                }
223            }
224        )+
225    };
226}
227
228serialize_via_display!(
229    CreateIndexOption,
230    CreateTableOption,
231    InsertOption,
232    UpdateOption,
233    DeleteOption,
234    TransactionOption,
235    QueryOption,
236    SelectOption,
237    JoinConstraintReason,
238);
239
240#[derive(Error, Serialize, Debug, PartialEq, Eq)]
241pub enum TranslateError {
242    #[error("unimplemented - select on two or more than tables are not supported")]
243    TooManyTables,
244
245    #[error("unimplemented - SELECT DISTINCT ON is not supported")]
246    SelectDistinctOnNotSupported,
247
248    #[error("unimplemented - composite index is not supported")]
249    CompositeIndexNotSupported,
250
251    #[error("unimplemented - join on update not supported")]
252    JoinOnUpdateNotSupported,
253
254    #[error("unimplemented - compound identifier on update not supported: {0}")]
255    CompoundIdentOnUpdateNotSupported(String),
256
257    #[error("unimplemented - tuple assigment on update is not supported: {0}")]
258    TupleAssignmentOnUpdateNotSupported(String),
259
260    #[error("too many params in drop index")]
261    TooManyParamsInDropIndex,
262
263    #[error("invalid params in drop index, expected: table_name.index_name")]
264    InvalidParamsInDropIndex,
265
266    #[error("function args.length not matching: {name}, expected: {expected}, found: {found}")]
267    FunctionArgsLengthNotMatching {
268        name: String,
269        expected: usize,
270        found: usize,
271    },
272
273    #[error("function {name} requires at least {expected_minimum} argument(s), found: {found}")]
274    FunctionArgsLengthNotMatchingMin {
275        name: String,
276        expected_minimum: usize,
277        found: usize,
278    },
279
280    #[error(
281        "function args.length not matching: {name}, expected: {expected_minimum} ~ {expected_maximum}, found: {found}"
282    )]
283    FunctionArgsLengthNotWithinRange {
284        name: String,
285        expected_minimum: usize,
286        expected_maximum: usize,
287        found: usize,
288    },
289
290    #[error("named function arg is not supported")]
291    NamedFunctionArgNotSupported,
292
293    #[error("unnamed function arg is not supported")]
294    UnNamedFunctionArgNotSupported,
295
296    #[error("subquery function arg is not supported")]
297    UnreachableSubqueryFunctionArgNotSupported,
298
299    #[error("INSERT INTO {0} DEFAULT VALUES is not supported")]
300    DefaultValuesOnInsertNotSupported(String),
301
302    #[error("empty function body is not supported")]
303    UnsupportedEmptyFunctionBody,
304
305    #[error("unsupported unnamed index")]
306    UnsupportedUnnamedIndex,
307
308    #[error("unsupported INSERT option: {0}")]
309    UnsupportedInsertOption(InsertOption),
310
311    #[error("unsupported CREATE TABLE option: {0}")]
312    UnsupportedCreateTableOption(CreateTableOption),
313
314    #[error("unsupported CREATE INDEX option: {0}")]
315    UnsupportedCreateIndexOption(CreateIndexOption),
316
317    #[error("unsupported UPDATE option: {0}")]
318    UnsupportedUpdateOption(UpdateOption),
319
320    #[error("unsupported DELETE option: {0}")]
321    UnsupportedDeleteOption(DeleteOption),
322
323    #[error("unsupported transaction option: {0}")]
324    UnsupportedTransactionOption(TransactionOption),
325
326    #[error("unsupported query option: {0}")]
327    UnsupportedQueryOption(QueryOption),
328
329    #[error("unsupported SELECT option: {0}")]
330    UnsupportedSelectOption(SelectOption),
331
332    #[error(
333        "unsupported trim chars: expected: `TRIM((BOTH | LEADING | TRAILING) <text> FROM <expr>)`, got: `TRIM(<expr> [<chars>, ..])` syntax"
334    )]
335    UnsupportedTrimChars,
336
337    #[error("unsupported CAST format: {0}")]
338    UnsupportedCastFormat(String),
339
340    #[error("TRY_CAST(..) is not supported")]
341    TryCastNotSupported,
342
343    #[error("SAFE_CAST(..) is not supported")]
344    SafeCastNotSupported,
345
346    #[error(
347        "unsupported multiple alter table operations, expected: `ALTER TABLE <table> <operation>`, got: `ALTER TABLE <table> <operation>, <operation>, ..`"
348    )]
349    UnsupportedMultipleAlterTableOperations,
350
351    #[error("unreachable empty alter table operation")]
352    UnreachableEmptyAlterTableOperation,
353
354    #[error("unsupported `GROUP BY (ALL)`")]
355    UnsupportedGroupByAll,
356
357    #[error("wildcard function arg is not accepted")]
358    WildcardFunctionArgNotAccepted,
359
360    #[error("qualified wildcard is not supported - COUNT({0})")]
361    QualifiedWildcardInCountNotSupported(String),
362
363    #[error("order by - NULLS (FIRST | LAST) is not supported")]
364    OrderByNullsFirstOrLastNotSupported,
365
366    #[error("unsupported SHOW VARIABLE keyword: {0}")]
367    UnsupportedShowVariableKeyword(String),
368
369    #[error("unsupported SHOW VARIABLE statement: {0}")]
370    UnsupportedShowVariableStatement(String),
371
372    #[error("unsupported statement: {0}")]
373    UnsupportedStatement(String),
374
375    #[error("unsupported expr: {0}")]
376    UnsupportedExpr(String),
377
378    #[error("unsupported data type: {0}")]
379    UnsupportedDataType(String),
380
381    #[error("unsupported datetime field: {0}")]
382    UnsupportedDateTimeField(String),
383
384    #[error("unsupported literal: {0}")]
385    UnsupportedLiteral(String),
386
387    #[error("failed to decode hex string: {0}")]
388    FailedToDecodeHexString(String),
389
390    #[error("unreachable unary operator: {0}")]
391    UnreachableUnaryOperator(String),
392
393    #[error("unreachable empty ident")]
394    UnreachableEmptyIdent,
395
396    #[error("unsupported binary operator: {0}")]
397    UnsupportedBinaryOperator(String),
398
399    #[error("unsupported query set expr: {0}")]
400    UnsupportedQuerySetExpr(String),
401
402    #[error("unsupported query table factor: {0}")]
403    UnsupportedQueryTableFactor(String),
404
405    #[error("unsupported join constraint: {0}")]
406    UnsupportedJoinConstraint(JoinConstraintReason),
407
408    #[error("unsupported join operator: {0}")]
409    UnsupportedJoinOperator(String),
410
411    #[error("unsupported column option: {0}")]
412    UnsupportedColumnOption(String),
413
414    #[error("unsupported alter table operation: {0}")]
415    UnsupportedAlterTableOperation(String),
416
417    #[error("unsupported table factor: {0}")]
418    UnsupportedTableFactor(String),
419
420    #[error("Every derived table must have its own alias")]
421    LackOfAlias,
422
423    #[error("Series should have size")]
424    LackOfArgs,
425
426    #[error("unreachable empty object")]
427    UnreachableEmptyObject,
428
429    #[error("unreachable empty table")]
430    UnreachableEmptyTable,
431
432    #[error("unreachable - FROM cannot be ommitted in DELETE statement")]
433    UnreachableOmittingFromInDelete,
434
435    #[error("unimplemented - compound object is supported: {0}")]
436    CompoundObjectNotSupported(String),
437
438    #[error("cannot create index with reserved name: {0}")]
439    ReservedIndexName(String),
440
441    #[error("cannot drop primary index")]
442    CannotDropPrimary,
443
444    #[error("unreachable - empty columns")]
445    UnreachableForeignKeyColumns(String),
446
447    #[error("unsupported constraint: {0}")]
448    UnsupportedConstraint(String),
449
450    #[error("parameter index {index} is out of range (total parameters: {len})")]
451    ParameterIndexOutOfRange { index: usize, len: usize },
452
453    #[error("invalid parameter placeholder: {placeholder}")]
454    InvalidPlaceholder { placeholder: String },
455}