From 6d0870b35a4e959dcdb9244b1b7d8375e66a1e84 Mon Sep 17 00:00:00 2001 From: Daniel Cachapa Date: Fri, 16 Feb 2024 22:52:39 +0100 Subject: [PATCH] Add support for inserts from select queries --- CHANGELOG.md | 4 +++ lib/src/timestamped_crdt.dart | 50 +++++++++++++++++++++++++++++------ pubspec.yaml | 2 +- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3a8d5a..e52ecea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.7 + +- Add support for inserts from select queries + ## 2.1.6 - Upgrade sqlparser diff --git a/lib/src/timestamped_crdt.dart b/lib/src/timestamped_crdt.dart index d069bd6..f637c87 100644 --- a/lib/src/timestamped_crdt.dart +++ b/lib/src/timestamped_crdt.dart @@ -10,7 +10,48 @@ abstract class TimestampedCrdt extends BaseCrdt { @override Future _insert(InsertStatement statement, List? args, [Hlc? hlc]) async { + // Force explicit column description in insert statements + assert(statement.targetColumns.isNotEmpty, + 'Unsupported statement: target columns must be explicitly stated.\n${statement.toSql()}'); + // Disallow star select statements + assert( + statement.source is! SelectInsertSource || + ((statement.source as SelectInsertSource).stmt as SelectStatement) + .columns + .whereType() + .isEmpty, + 'Unsupported statement: select columns must be explicitly stated.\n${statement.toSql()}'); + final argCount = args?.length ?? 0; + final source = switch (statement.source) { + ValuesSource s => ValuesSource([ + Tuple(expressions: [ + ...s.values.first.expressions, + NumberedVariable(argCount + 1), + NumberedVariable(argCount + 2), + NumberedVariable(argCount + 3), + ]) + ]), + SelectInsertSource s => SelectInsertSource(SelectStatement( + withClause: (s.stmt as SelectStatement).withClause, + distinct: (s.stmt as SelectStatement).distinct, + columns: [ + ...(s.stmt as SelectStatement).columns, + ExpressionResultColumn(expression: NumberedVariable(argCount + 1)), + ExpressionResultColumn(expression: NumberedVariable(argCount + 2)), + ExpressionResultColumn(expression: NumberedVariable(argCount + 3)), + ], + from: (s.stmt as SelectStatement).from, + where: (s.stmt as SelectStatement).where, + groupBy: (s.stmt as SelectStatement).groupBy, + windowDeclarations: (s.stmt as SelectStatement).windowDeclarations, + orderBy: (s.stmt as SelectStatement).orderBy, + limit: (s.stmt as SelectStatement).limit, + )), + _ => throw UnimplementedError( + 'Unsupported data source: ${statement.source.runtimeType}, please file an issue in the sql_crdt project.') + }; + final newStatement = InsertStatement( mode: statement.mode, upsert: statement.upsert, @@ -23,14 +64,7 @@ abstract class TimestampedCrdt extends BaseCrdt { Reference(columnName: 'node_id'), Reference(columnName: 'modified'), ], - source: ValuesSource([ - Tuple(expressions: [ - ...(statement.source as ValuesSource).values.first.expressions, - NumberedVariable(argCount + 1), - NumberedVariable(argCount + 2), - NumberedVariable(argCount + 3), - ]) - ]), + source: source, ); // Touch diff --git a/pubspec.yaml b/pubspec.yaml index 6ab2247..71b3f2a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: sql_crdt description: Base package for Conflict-free Replicated Data Types (CRDTs) using SQL databases -version: 2.1.6 +version: 2.1.7 homepage: https://github.com/cachapa/sql_crdt repository: https://github.com/cachapa/sql_crdt issue_tracker: https://github.com/cachapa/sql_crdt/issues