mirror of https://github.com/AMT-Cheif/drift.git
Improve table analysis, parse key ordering (#1007)
This commit is contained in:
parent
1ff10f47c2
commit
5ff74c7bcb
|
@ -1062,7 +1062,7 @@ class Mytable extends Table with TableInfo<Mytable, MytableData> {
|
||||||
late final GeneratedIntColumn someid = _constructSomeid();
|
late final GeneratedIntColumn someid = _constructSomeid();
|
||||||
GeneratedIntColumn _constructSomeid() {
|
GeneratedIntColumn _constructSomeid() {
|
||||||
return GeneratedIntColumn('someid', $tableName, false,
|
return GeneratedIntColumn('someid', $tableName, false,
|
||||||
declaredAsPrimaryKey: true, $customConstraints: 'NOT NULL PRIMARY KEY');
|
$customConstraints: 'NOT NULL');
|
||||||
}
|
}
|
||||||
|
|
||||||
final VerificationMeta _sometextMeta = const VerificationMeta('sometext');
|
final VerificationMeta _sometextMeta = const VerificationMeta('sometext');
|
||||||
|
@ -1136,6 +1136,8 @@ class Mytable extends Table with TableInfo<Mytable, MytableData> {
|
||||||
return Mytable(_db, alias);
|
return Mytable(_db, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> get customConstraints => const ['PRIMARY KEY (someid DESC)'];
|
||||||
@override
|
@override
|
||||||
bool get dontWriteConstraints => true;
|
bool get dontWriteConstraints => true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,11 @@ create table config (
|
||||||
CREATE INDEX IF NOT EXISTS value_idx ON config (config_value);
|
CREATE INDEX IF NOT EXISTS value_idx ON config (config_value);
|
||||||
|
|
||||||
CREATE TABLE mytable (
|
CREATE TABLE mytable (
|
||||||
someid INTEGER NOT NULL PRIMARY KEY,
|
someid INTEGER NOT NULL,
|
||||||
sometext TEXT,
|
sometext TEXT,
|
||||||
is_inserting BOOLEAN,
|
is_inserting BOOLEAN,
|
||||||
somedate DATETIME
|
somedate DATETIME,
|
||||||
|
PRIMARY KEY (someid DESC)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE VIRTUAL TABLE email USING fts5(sender, title, body) AS EMail;
|
CREATE VIRTUAL TABLE email USING fts5(sender, title, body) AS EMail;
|
||||||
|
|
|
@ -26,10 +26,12 @@ const _createConfig = 'CREATE TABLE IF NOT EXISTS config ('
|
||||||
'sync_state_implicit INTEGER);';
|
'sync_state_implicit INTEGER);';
|
||||||
|
|
||||||
const _createMyTable = 'CREATE TABLE IF NOT EXISTS mytable ('
|
const _createMyTable = 'CREATE TABLE IF NOT EXISTS mytable ('
|
||||||
'someid INTEGER NOT NULL PRIMARY KEY, '
|
'someid INTEGER NOT NULL, '
|
||||||
'sometext TEXT, '
|
'sometext TEXT, '
|
||||||
'is_inserting INTEGER, '
|
'is_inserting INTEGER, '
|
||||||
'somedate INTEGER);';
|
'somedate INTEGER, '
|
||||||
|
'PRIMARY KEY (someid DESC)'
|
||||||
|
');';
|
||||||
|
|
||||||
const _createEmail = 'CREATE VIRTUAL TABLE IF NOT EXISTS email USING '
|
const _createEmail = 'CREATE VIRTUAL TABLE IF NOT EXISTS email USING '
|
||||||
'fts5(sender, title, body);';
|
'fts5(sender, title, body);';
|
||||||
|
@ -85,6 +87,7 @@ void main() {
|
||||||
expect(db.noIds.primaryKey, [db.noIds.payload]);
|
expect(db.noIds.primaryKey, [db.noIds.payload]);
|
||||||
expect(db.withDefaults.primaryKey, isEmpty);
|
expect(db.withDefaults.primaryKey, isEmpty);
|
||||||
expect(db.config.primaryKey, [db.config.configKey]);
|
expect(db.config.primaryKey, [db.config.configKey]);
|
||||||
|
expect(db.mytable.primaryKey, [db.mytable.someid]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('supports absent values for primary key integers', () async {
|
test('supports absent values for primary key integers', () async {
|
||||||
|
|
|
@ -184,11 +184,13 @@ class CreateTableReader {
|
||||||
|
|
||||||
for (final keyConstraint in table.tableConstraints.whereType<KeyClause>()) {
|
for (final keyConstraint in table.tableConstraints.whereType<KeyClause>()) {
|
||||||
if (keyConstraint.isPrimaryKey) {
|
if (keyConstraint.isPrimaryKey) {
|
||||||
primaryKeyFromTableConstraint = {
|
primaryKeyFromTableConstraint = {};
|
||||||
for (final column in keyConstraint.indexedColumns)
|
for (final column in keyConstraint.columns) {
|
||||||
if (foundColumns.containsKey(column.columnName))
|
final expr = column.expression;
|
||||||
foundColumns[column.columnName]
|
if (expr is Reference && foundColumns.containsKey(expr.columnName)) {
|
||||||
};
|
primaryKeyFromTableConstraint.add(foundColumns[expr.columnName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,9 @@ class EntityHandler extends BaseAnalyzer {
|
||||||
for (final entity in file.declaredEntities) {
|
for (final entity in file.declaredEntities) {
|
||||||
if (entity is MoorTable) {
|
if (entity is MoorTable) {
|
||||||
entity.references.clear();
|
entity.references.clear();
|
||||||
_handleMoorDeclaration<MoorTableDeclaration>(entity, _tables);
|
final node =
|
||||||
|
_handleMoorDeclaration<MoorTableDeclaration>(entity, _tables);
|
||||||
|
_lint(node, entity.sqlName);
|
||||||
} else if (entity is MoorTrigger) {
|
} else if (entity is MoorTrigger) {
|
||||||
entity.clearResolvedReferences();
|
entity.clearResolvedReferences();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ dependencies:
|
||||||
# Moor-specific analysis and apis
|
# Moor-specific analysis and apis
|
||||||
moor: ^4.0.0-nullsafety
|
moor: ^4.0.0-nullsafety
|
||||||
sqlite3: ^0.1.6
|
sqlite3: ^0.1.6
|
||||||
sqlparser: ^0.12.0-nullsafety.0
|
sqlparser: ^0.13.0-nullsafety.0
|
||||||
|
|
||||||
# Dart analysis
|
# Dart analysis
|
||||||
analyzer: ">=0.40.0 <0.42.0"
|
analyzer: ">=0.40.0 <0.42.0"
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
## 0.13.0-nullsafety.0
|
||||||
|
|
||||||
|
- Parse ordering in table key constraints
|
||||||
|
- Deprecate `KeyClause.indexedColumns` in favor of `KeyClause.columns`
|
||||||
|
|
||||||
## 0.12.0-nullsafety.0
|
## 0.12.0-nullsafety.0
|
||||||
|
|
||||||
- Migrate to null-safety
|
- Migrate to null-safety
|
||||||
|
|
|
@ -61,6 +61,8 @@ class TableColumn extends Column implements ColumnWithType {
|
||||||
/// The table this column belongs to.
|
/// The table this column belongs to.
|
||||||
Table? table;
|
Table? table;
|
||||||
|
|
||||||
|
late final bool _isAliasForRowId = _computeIsAliasForRowId();
|
||||||
|
|
||||||
TableColumn(this.name, this._type, {this.definition});
|
TableColumn(this.name, this._type, {this.definition});
|
||||||
|
|
||||||
/// Applies a type hint to this column.
|
/// Applies a type hint to this column.
|
||||||
|
@ -80,6 +82,10 @@ class TableColumn extends Column implements ColumnWithType {
|
||||||
/// - if this column has a [PrimaryKeyColumn], the [OrderingMode] of that
|
/// - if this column has a [PrimaryKeyColumn], the [OrderingMode] of that
|
||||||
/// constraint is not [OrderingMode.descending].
|
/// constraint is not [OrderingMode.descending].
|
||||||
bool isAliasForRowId() {
|
bool isAliasForRowId() {
|
||||||
|
return _isAliasForRowId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _computeIsAliasForRowId() {
|
||||||
if (definition == null ||
|
if (definition == null ||
|
||||||
table == null ||
|
table == null ||
|
||||||
type.type != BasicType.int ||
|
type.type != BasicType.int ||
|
||||||
|
@ -93,8 +99,13 @@ class TableColumn extends Column implements ColumnWithType {
|
||||||
for (final tableConstraint in columnsWithKey) {
|
for (final tableConstraint in columnsWithKey) {
|
||||||
if (!tableConstraint.isPrimaryKey) continue;
|
if (!tableConstraint.isPrimaryKey) continue;
|
||||||
|
|
||||||
final columns = tableConstraint.indexedColumns;
|
final columns = tableConstraint.columns;
|
||||||
if (columns.length == 1 && columns.single.columnName == name) {
|
if (columns.length != 1) continue;
|
||||||
|
|
||||||
|
final singleColumnExpr = columns.single.expression;
|
||||||
|
|
||||||
|
if (singleColumnExpr is Reference &&
|
||||||
|
singleColumnExpr.columnName == name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,13 @@ class ColumnResolver extends RecursiveVisitor<void, void> {
|
||||||
visitChildren(e, arg);
|
visitChildren(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitTableReference(TableReference e, void arg) {
|
||||||
|
if (e.resolved == null) {
|
||||||
|
_resolveTableReference(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _addIfResolved(AstNode node, TableReference ref) {
|
void _addIfResolved(AstNode node, TableReference ref) {
|
||||||
final table = _resolveTableReference(ref);
|
final table = _resolveTableReference(ref);
|
||||||
if (table != null) {
|
if (table != null) {
|
||||||
|
|
|
@ -40,6 +40,25 @@ class LintingVisitor extends RecursiveVisitor<void, void> {
|
||||||
visitChildren(e, arg);
|
visitChildren(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitTableConstraint(TableConstraint e, void arg) {
|
||||||
|
if (e is KeyClause && e.isPrimaryKey) {
|
||||||
|
// Primary key clauses may only include simple columns
|
||||||
|
for (final column in e.columns) {
|
||||||
|
final expr = column.expression;
|
||||||
|
if (expr is! Reference || expr.tableName != null) {
|
||||||
|
context.reportError(AnalysisError(
|
||||||
|
type: AnalysisErrorType.synctactic,
|
||||||
|
message: 'Only column names can be used in a PRIMARY KEY clause',
|
||||||
|
relevantNode: expr,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitChildren(e, arg);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void visitTuple(Tuple e, void arg) {
|
void visitTuple(Tuple e, void arg) {
|
||||||
if (!e.usedAsRowValue) return;
|
if (!e.usedAsRowValue) return;
|
||||||
|
|
|
@ -19,6 +19,19 @@ class AstPreparingVisitor extends RecursiveVisitor<void, void> {
|
||||||
_resolveIndexOfVariables();
|
_resolveIndexOfVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitCreateTableStatement(CreateTableStatement e, void arg) {
|
||||||
|
final scope = e.scope = e.scope.createChild();
|
||||||
|
final registeredTable = scope.resolve(e.tableName) as Table?;
|
||||||
|
|
||||||
|
if (registeredTable != null) {
|
||||||
|
scope.availableColumns = registeredTable.resolvedColumns;
|
||||||
|
for (final column in registeredTable.resolvedColumns) {
|
||||||
|
scope.register(column.name, column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void visitSelectStatement(SelectStatement e, void arg) {
|
void visitSelectStatement(SelectStatement e, void arg) {
|
||||||
// a select statement can appear as a sub query which has its own scope, so
|
// a select statement can appear as a sub query which has its own scope, so
|
||||||
|
|
|
@ -6,6 +6,28 @@ class ReferenceResolver extends RecursiveVisitor<void, void> {
|
||||||
|
|
||||||
ReferenceResolver(this.context);
|
ReferenceResolver(this.context);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitForeignKeyClause(ForeignKeyClause e, void arg) {
|
||||||
|
final table = e.foreignTable.resultSet;
|
||||||
|
if (table == null) {
|
||||||
|
// If the table wasn't found, an earlier step will have reported an error
|
||||||
|
return super.visitForeignKeyClause(e, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final columnName in e.columnNames) {
|
||||||
|
_resolveReferenceInTable(columnName, table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _resolveReferenceInTable(Reference ref, ResultSet resultSet) {
|
||||||
|
final column = resultSet.findColumn(ref.columnName);
|
||||||
|
if (column == null) {
|
||||||
|
_reportUnknownColumnError(ref, columns: resultSet.resolvedColumns);
|
||||||
|
} else {
|
||||||
|
ref.resolved = column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void visitReference(Reference e, void arg) {
|
void visitReference(Reference e, void arg) {
|
||||||
if (e.resolved != null) {
|
if (e.resolved != null) {
|
||||||
|
@ -26,12 +48,7 @@ class ReferenceResolver extends RecursiveVisitor<void, void> {
|
||||||
relevantNode: e,
|
relevantNode: e,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
final column = resultSet.findColumn(e.columnName);
|
_resolveReferenceInTable(e, resultSet);
|
||||||
if (column == null) {
|
|
||||||
_reportUnknownColumnError(e, columns: resultSet.resolvedColumns);
|
|
||||||
} else {
|
|
||||||
e.resolved = column;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (aliasesForRowId.contains(e.columnName.toLowerCase())) {
|
} else if (aliasesForRowId.contains(e.columnName.toLowerCase())) {
|
||||||
// special case for aliases to a rowid
|
// special case for aliases to a rowid
|
||||||
|
|
|
@ -84,15 +84,21 @@ abstract class TableConstraint extends AstNode {
|
||||||
|
|
||||||
class KeyClause extends TableConstraint {
|
class KeyClause extends TableConstraint {
|
||||||
final bool isPrimaryKey;
|
final bool isPrimaryKey;
|
||||||
final List<Reference> indexedColumns;
|
final List<IndexedColumn> columns;
|
||||||
final ConflictClause? onConflict;
|
final ConflictClause? onConflict;
|
||||||
|
|
||||||
bool get isUnique => !isPrimaryKey;
|
bool get isUnique => !isPrimaryKey;
|
||||||
|
|
||||||
|
@Deprecated('Use columns instead')
|
||||||
|
List<Reference> get indexedColumns {
|
||||||
|
return [
|
||||||
|
for (final column in columns)
|
||||||
|
if (column.expression is Reference) column.expression as Reference
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
KeyClause(String? name,
|
KeyClause(String? name,
|
||||||
{required this.isPrimaryKey,
|
{required this.isPrimaryKey, required this.columns, this.onConflict})
|
||||||
required this.indexedColumns,
|
|
||||||
this.onConflict})
|
|
||||||
: super(name);
|
: super(name);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -102,11 +108,11 @@ class KeyClause extends TableConstraint {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||||
transformer.transformChildren(indexedColumns, this, arg);
|
transformer.transformChildren(columns, this, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Iterable<AstNode> get childNodes => indexedColumns;
|
Iterable<AstNode> get childNodes => columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CheckTable extends TableConstraint {
|
class CheckTable extends TableConstraint {
|
||||||
|
|
|
@ -145,7 +145,7 @@ class SqlEngine {
|
||||||
final result = parse(sql);
|
final result = parse(sql);
|
||||||
final analyzed = analyzeParsed(result, stmtOptions: stmtOptions);
|
final analyzed = analyzeParsed(result, stmtOptions: stmtOptions);
|
||||||
|
|
||||||
// Add parsing errors that occured to the beginning since they are the most
|
// Add parsing errors that occurred at the beginning since they are the most
|
||||||
// prominent problems.
|
// prominent problems.
|
||||||
analyzed.errors
|
analyzed.errors
|
||||||
.insertAll(0, result.errors.map((e) => AnalysisError.fromParser(e)));
|
.insertAll(0, result.errors.map((e) => AnalysisError.fromParser(e)));
|
||||||
|
|
|
@ -2249,12 +2249,16 @@ class Parser {
|
||||||
_consume(TokenType.key, 'Expected KEY to start PRIMARY KEY clause');
|
_consume(TokenType.key, 'Expected KEY to start PRIMARY KEY clause');
|
||||||
}
|
}
|
||||||
|
|
||||||
final columns = _listColumnsInParentheses(allowEmpty: false);
|
_consume(TokenType.leftParen,
|
||||||
|
'Expected a left parenthesis to start key columns');
|
||||||
|
final columns = _indexedColumns();
|
||||||
|
_consume(
|
||||||
|
TokenType.rightParen, 'Expected a closing parenthesis after columns');
|
||||||
final conflictClause = _conflictClauseOrNull();
|
final conflictClause = _conflictClauseOrNull();
|
||||||
|
|
||||||
result = KeyClause(name,
|
result = KeyClause(name,
|
||||||
isPrimaryKey: isPrimaryKey,
|
isPrimaryKey: isPrimaryKey,
|
||||||
indexedColumns: columns,
|
columns: columns,
|
||||||
onConflict: conflictClause);
|
onConflict: conflictClause);
|
||||||
} else if (_matchOne(TokenType.check)) {
|
} else if (_matchOne(TokenType.check)) {
|
||||||
final expr = _expressionInParentheses();
|
final expr = _expressionInParentheses();
|
||||||
|
|
|
@ -1037,7 +1037,7 @@ class _NodeSqlBuilder extends AstVisitor<void, void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_symbol('(');
|
_symbol('(');
|
||||||
_join(e.indexedColumns, ',');
|
_join(e.columns, ',');
|
||||||
_symbol(')');
|
_symbol(')');
|
||||||
_conflictClause(e.onConflict);
|
_conflictClause(e.onConflict);
|
||||||
} else if (e is CheckTable) {
|
} else if (e is CheckTable) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: sqlparser
|
name: sqlparser
|
||||||
description: Parses sqlite statements and performs static analysis on them
|
description: Parses sqlite statements and performs static analysis on them
|
||||||
version: 0.12.0-nullsafety.0
|
version: 0.13.0-nullsafety.0
|
||||||
homepage: https://github.com/simolus3/moor/tree/develop/sqlparser
|
homepage: https://github.com/simolus3/moor/tree/develop/sqlparser
|
||||||
#homepage: https://moor.simonbinder.eu/
|
#homepage: https://moor.simonbinder.eu/
|
||||||
issue_tracker: https://github.com/simolus3/moor/issues
|
issue_tracker: https://github.com/simolus3/moor/issues
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// tests for syntax errors revealed during static analysis.
|
// tests for syntax errors revealed during static analysis.
|
||||||
|
|
||||||
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
import 'package:sqlparser/src/analysis/analysis.dart';
|
import 'package:sqlparser/src/analysis/analysis.dart';
|
||||||
import 'package:sqlparser/src/engine/sql_engine.dart';
|
import 'package:sqlparser/src/engine/sql_engine.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
@ -19,4 +20,25 @@ void main() {
|
||||||
contains('Expected a conflict clause'))
|
contains('Expected a conflict clause'))
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('complex expressions in PRIMARY KEY clause', () {
|
||||||
|
final engine = SqlEngine();
|
||||||
|
final parseResult = engine.parse('''
|
||||||
|
CREATE TABLE tbl (
|
||||||
|
foo INTEGER NOT NULL,
|
||||||
|
bar TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (foo DESC, bar || 'test')
|
||||||
|
);
|
||||||
|
''');
|
||||||
|
engine.registerTable(const SchemaFromCreateTable()
|
||||||
|
.read(parseResult.rootNode as CreateTableStatement));
|
||||||
|
final analyzeResult = engine.analyzeParsed(parseResult);
|
||||||
|
|
||||||
|
expect(analyzeResult.errors, [
|
||||||
|
const TypeMatcher<AnalysisError>()
|
||||||
|
.having((e) => e.type, 'type', AnalysisErrorType.synctactic)
|
||||||
|
.having((e) => e.message, 'message',
|
||||||
|
contains('Only column names can be used in a PRIMARY KEY clause'))
|
||||||
|
]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,9 +94,9 @@ void main() {
|
||||||
KeyClause(
|
KeyClause(
|
||||||
null,
|
null,
|
||||||
isPrimaryKey: false,
|
isPrimaryKey: false,
|
||||||
indexedColumns: [
|
columns: [
|
||||||
Reference(columnName: 'score'),
|
IndexedColumn(Reference(columnName: 'score')),
|
||||||
Reference(columnName: 'display_name'),
|
IndexedColumn(Reference(columnName: 'display_name')),
|
||||||
],
|
],
|
||||||
onConflict: ConflictClause.abort,
|
onConflict: ConflictClause.abort,
|
||||||
),
|
),
|
||||||
|
@ -125,6 +125,28 @@ void main() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('parses KEY ORDERING in PRIMARY KEY clause', () {
|
||||||
|
testStatement(
|
||||||
|
'CREATE TABLE a (b TEXT, PRIMARY KEY (b DESC))',
|
||||||
|
CreateTableStatement(
|
||||||
|
tableName: 'a',
|
||||||
|
columns: [ColumnDefinition(columnName: 'b', typeName: 'TEXT')],
|
||||||
|
tableConstraints: [
|
||||||
|
KeyClause(
|
||||||
|
null,
|
||||||
|
isPrimaryKey: true,
|
||||||
|
columns: [
|
||||||
|
IndexedColumn(
|
||||||
|
Reference(columnName: 'b'),
|
||||||
|
OrderingMode.descending,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('parses MAPPED BY constraints when in moor mode', () {
|
test('parses MAPPED BY constraints when in moor mode', () {
|
||||||
testStatement(
|
testStatement(
|
||||||
'CREATE TABLE a (b NOT NULL MAPPED BY `Mapper()` PRIMARY KEY)',
|
'CREATE TABLE a (b NOT NULL MAPPED BY `Mapper()` PRIMARY KEY)',
|
||||||
|
|
|
@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS my_table(
|
||||||
COLLATE c
|
COLLATE c
|
||||||
REFERENCES t2 (c) ON DELETE RESTRICT ON UPDATE NO ACTION,
|
REFERENCES t2 (c) ON DELETE RESTRICT ON UPDATE NO ACTION,
|
||||||
|
|
||||||
PRIMARY KEY (foo, bar) ON CONFLICT ABORT,
|
PRIMARY KEY (foo, bar DESC) ON CONFLICT ABORT,
|
||||||
UNIQUE (baz) ON CONFLICT REPLACE,
|
UNIQUE (baz) ON CONFLICT REPLACE,
|
||||||
CONSTRAINT my_constraint CHECK(baz < 3),
|
CONSTRAINT my_constraint CHECK(baz < 3),
|
||||||
FOREIGN KEY (foo, baz) REFERENCES t2 ON DELETE SET NULL ON UPDATE CASCADE
|
FOREIGN KEY (foo, baz) REFERENCES t2 ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
|
Loading…
Reference in New Issue