mirror of https://github.com/AMT-Cheif/drift.git
Support current time literals in the sql parser
This commit is contained in:
parent
f9424470a5
commit
fbe061c84d
|
@ -4,6 +4,7 @@
|
|||
- __Breaking__: Removed the `enableJson1` parameter on `EngineOptions`. Add a `Json1Extension` instance
|
||||
to `enabledExtensions` instead.
|
||||
- Parse `rowid` as a valid reference when needed (`SELECT rowid FROM tbl` is now parsed correctly)
|
||||
- Parse `CURRENT_TIME`, `CURRENT_DATE` and `CURRENT_TIMESTAMP`
|
||||
|
||||
## 0.6.0
|
||||
|
||||
|
|
|
@ -161,6 +161,8 @@ class TypeResolver {
|
|||
} else if (l is NullLiteral) {
|
||||
return const ResolveResult(
|
||||
ResolvedType(type: BasicType.nullType, nullable: true));
|
||||
} else if (l is TimeConstantLiteral) {
|
||||
return const ResolveResult(ResolvedType(type: BasicType.text));
|
||||
}
|
||||
|
||||
throw StateError('Unknown literal $l');
|
||||
|
|
|
@ -144,21 +144,22 @@ class TypeResolver extends RecursiveVisitor<TypeExpectation, void> {
|
|||
@override
|
||||
void visitLiteral(Literal e, TypeExpectation arg) {
|
||||
ResolvedType type;
|
||||
var nullable = false;
|
||||
|
||||
if (e is NullLiteral) {
|
||||
type = const ResolvedType(type: BasicType.nullType, nullable: true);
|
||||
session._hintNullability(e, true);
|
||||
nullable = true;
|
||||
} else if (e is StringLiteral) {
|
||||
type = e.isBinary ? const ResolvedType(type: BasicType.blob) : _textType;
|
||||
session._hintNullability(e, false);
|
||||
} else if (e is BooleanLiteral) {
|
||||
type = const ResolvedType.bool();
|
||||
session._hintNullability(e, false);
|
||||
} else if (e is NumericLiteral) {
|
||||
type = e.isInt ? _intType : _realType;
|
||||
session._hintNullability(e, false);
|
||||
} else if (e is TimeConstantLiteral) {
|
||||
type = _textType;
|
||||
}
|
||||
|
||||
session._hintNullability(e, nullable);
|
||||
session._checkAndResolve(e, type, arg);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,3 +89,24 @@ class StringLiteral extends Literal {
|
|||
return other.isBinary == isBinary && other.value == value;
|
||||
}
|
||||
}
|
||||
|
||||
enum TimeConstantKind { currentTime, currentDate, currentTimestamp }
|
||||
|
||||
class TimeConstantLiteral extends Literal {
|
||||
final TimeConstantKind kind;
|
||||
|
||||
TimeConstantLiteral(this.kind, Token keyword) : super(keyword);
|
||||
|
||||
@override
|
||||
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||
return visitor.visitTimeConstantLiteral(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contentEquals(TimeConstantLiteral other) {
|
||||
return other.kind == kind;
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic get value => throw UnimplementedError('TimeConstantLiteral.value');
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ abstract class AstVisitor<A, R> {
|
|||
R visitNullLiteral(NullLiteral e, A arg);
|
||||
R visitBooleanLiteral(BooleanLiteral e, A arg);
|
||||
R visitStringLiteral(StringLiteral e, A arg);
|
||||
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg);
|
||||
|
||||
R visitCastExpression(CastExpression e, A arg);
|
||||
R visitBinaryExpression(BinaryExpression e, A arg);
|
||||
|
@ -325,6 +326,11 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
|
|||
return visitLiteral(e, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitTimeConstantLiteral(TimeConstantLiteral e, A arg) {
|
||||
return visitLiteral(e, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R visitReference(Reference e, A arg) {
|
||||
return visitExpression(e, arg);
|
||||
|
|
|
@ -265,7 +265,18 @@ mixin ExpressionParser on ParserBase {
|
|||
if (_matchOne(TokenType.$false)) {
|
||||
return BooleanLiteral.withFalse(token);
|
||||
}
|
||||
// todo CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP
|
||||
|
||||
const timeLiterals = {
|
||||
TokenType.currentTime: TimeConstantKind.currentTime,
|
||||
TokenType.currentDate: TimeConstantKind.currentDate,
|
||||
TokenType.currentTimestamp: TimeConstantKind.currentTimestamp,
|
||||
};
|
||||
|
||||
if (_match(timeLiterals.keys)) {
|
||||
final token = _previous;
|
||||
return TimeConstantLiteral(timeLiterals[token.type], token);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ Map<String, ResolveResult> _types = {
|
|||
const ResolveResult(ResolvedType(type: BasicType.text)),
|
||||
'SELECT (3 * 4) = ?': const ResolveResult(ResolvedType(type: BasicType.int)),
|
||||
'SELECT (3 / 4) = ?': const ResolveResult(ResolvedType(type: BasicType.int)),
|
||||
'SELECT CURRENT_TIME = ?':
|
||||
const ResolveResult(ResolvedType(type: BasicType.text)),
|
||||
};
|
||||
|
||||
void main() {
|
||||
|
|
|
@ -29,6 +29,7 @@ const Map<String, ResolvedType> _types = {
|
|||
'SELECT CAST(3 AS TEXT) = ?': ResolvedType(type: BasicType.text),
|
||||
'SELECT (3 * 4) = ?': ResolvedType(type: BasicType.int),
|
||||
'SELECT (3 / 4) = ?': ResolvedType(type: BasicType.int),
|
||||
'SELECT CURRENT_TIMESTAMP = ?': ResolvedType(type: BasicType.text),
|
||||
};
|
||||
|
||||
SqlEngine _spawnEngine() {
|
||||
|
|
|
@ -146,6 +146,12 @@ final Map<String, Expression> _testCases = {
|
|||
),
|
||||
'foo ISNULL': IsNullExpression(Reference(columnName: 'foo')),
|
||||
'foo NOTNULL': IsNullExpression(Reference(columnName: 'foo'), true),
|
||||
'CURRENT_TIME': TimeConstantLiteral(
|
||||
TimeConstantKind.currentTime, token(TokenType.currentTime)),
|
||||
'CURRENT_TIMESTAMP': TimeConstantLiteral(
|
||||
TimeConstantKind.currentTimestamp, token(TokenType.currentTimestamp)),
|
||||
'CURRENT_DATE': TimeConstantLiteral(
|
||||
TimeConstantKind.currentDate, token(TokenType.currentDate)),
|
||||
};
|
||||
|
||||
void main() {
|
||||
|
|
Loading…
Reference in New Issue