Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/src/crdt_executor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:sqlparser/sqlparser.dart';
import 'package:sqlparser/utils/node_to_text.dart';

import 'database_api.dart';
import 'sql_util.dart';

final _sqlEngine = SqlEngine();

Expand Down Expand Up @@ -36,7 +37,8 @@ class CrdtTableExecutor extends _CrdtTableExecutor implements CrdtApi {

@override
Future<List<Map<String, Object?>>> query(String sql, [List<Object?>? args]) =>
(_db as ReadWriteApi).query(sql, args);
(_db as ReadWriteApi)
.query(SqlUtil.transformAutomaticExplicitSql(sql), args);
}

class _CrdtTableExecutor {
Expand Down Expand Up @@ -122,7 +124,8 @@ class CrdtExecutor extends CrdtWriteExecutor implements CrdtApi {

@override
Future<List<Map<String, Object?>>> query(String sql, [List<Object?>? args]) =>
(_db as ReadWriteApi).query(sql, args);
(_db as ReadWriteApi)
.query(SqlUtil.transformAutomaticExplicitSql(sql), args);
}

class CrdtWriteExecutor extends _CrdtTableExecutor {
Expand All @@ -136,6 +139,7 @@ class CrdtWriteExecutor extends _CrdtTableExecutor {
@override
Future<void> _executeStatement(
Statement statement, List<Object?>? args) async {
SqlUtil.transformAutomaticExplicit(statement);
final table = await switch (statement) {
CreateTableStatement statement => _createTable(statement, args),
InsertStatement statement => _insert(statement, args),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/sql_crdt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract class SqlCrdt extends Crdt implements CrdtApi {

@override
Future<List<Map<String, Object?>>> query(String sql, [List<Object?>? args]) =>
_db.query(sql, args);
_db.query(SqlUtil.transformAutomaticExplicitSql(sql), args);

@override
Future<void> execute(String sql, [List<Object?>? args]) async {
Expand Down
22 changes: 22 additions & 0 deletions lib/src/sql_util.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:crdt/crdt.dart';
import 'package:source_span/source_span.dart';
import 'package:sqlparser/sqlparser.dart';
Expand Down Expand Up @@ -27,6 +28,27 @@ class SqlUtil {
.fold({}, (prev, e) => prev..addAll(_getAffectedTables(e)));
}

/// function takes a SQL [statement]
/// transforms the SQL statement to change parameters from automatic
/// index into parameters with explicit index
static void transformAutomaticExplicit(Statement statement) {
statement.allDescendants
.whereType<NumberedVariable>()
.forEachIndexed((i, ref) {
ref.explicitIndex ??= i + 1;
});
}

static String transformAutomaticExplicitSql(String sql) {
final statement = _sqlEngine.parse(sql).rootNode as Statement;

// if statement is of InvalidStatement type, return the original SQL string
if (statement is InvalidStatement) return sql;

transformAutomaticExplicit(statement);
return statement.toSql();
}

static String addChangesetClauses(
String table,
String sql, {
Expand Down
5 changes: 3 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: sql_crdt
description: Base package for Conflict-free Replicated Data Types (CRDTs) using SQL databases
version: 3.0.2
version: 3.0.3
homepage: https://github.com/cachapa/sql_crdt
repository: https://github.com/cachapa/sql_crdt
issue_tracker: https://github.com/cachapa/sql_crdt/issues
Expand All @@ -12,7 +12,8 @@ dependencies:
crdt: ^5.1.3
# path: ../crdt
source_span: ^1.10.0
sqlparser: ^0.39.2
sqlparser: ^0.41.0
collection: ^1.19.1

dev_dependencies:
lints: any
Expand Down
45 changes: 45 additions & 0 deletions test/sql_util_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,49 @@ void main() {
"SELECT * FROM test WHERE node_id != 'node_id' AND modified > '1970-01-01T00:00:00.000Z-0000-node_id' AND a != ?1 AND b = ?2");
});
});

group('Transform automatic to explicit parameters', () {
test('Simple automatic parameters', () {
final sql = 'SELECT * FROM users WHERE name = ? AND age = ?';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed, 'SELECT * FROM users WHERE name = ?1 AND age = ?2');
});

test('Already explicit parameters', () {
final sql = 'SELECT * FROM users WHERE name = ?1 AND age = ?2';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed, 'SELECT * FROM users WHERE name = ?1 AND age = ?2');
});

test('Mixed automatic and explicit parameters', () {
final sql =
'SELECT * FROM users WHERE name = ? AND age = ?2 AND city = ?';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed,
'SELECT * FROM users WHERE name = ?1 AND age = ?2 AND city = ?3');
});

test('Multiple automatic parameters in complex query', () {
final sql = '''SELECT * FROM users
JOIN orders ON users.id = orders.user_id
WHERE users.name = ? AND orders.status = ? AND orders.total > ?
''';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed,
'SELECT * FROM users JOIN orders ON users.id = orders.user_id WHERE users.name = ?1 AND orders.status = ?2 AND orders.total > ?3');
});

test('Automatic parameters in INSERT statement', () {
final sql = 'INSERT INTO users (name, age, city) VALUES (?, ?, ?)';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed,
'INSERT INTO users (name, age, city) VALUES (?1, ?2, ?3)');
});

test('Automatic parameters in UPDATE statement', () {
final sql = 'UPDATE users SET name = ?, age = ? WHERE id = ?';
final transformed = SqlUtil.transformAutomaticExplicitSql(sql);
expect(transformed, 'UPDATE users SET name = ?1, age = ?2 WHERE id = ?3');
});
});
}
Loading