From cf607f0108029a29ff3dc5f98effffbc084bbfe4 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 2 Dec 2019 21:40:41 +0100 Subject: [PATCH] Escape column names during insert --- .../runtime/query_builder/schema/table_info.dart | 1 + .../runtime/query_builder/statements/insert.dart | 4 +++- moor/test/data/tables/todos.dart | 3 ++- moor/test/data/tables/todos.g.dart | 6 +++--- moor/test/insert_test.dart | 9 +++++++++ .../build/generators/moor_generator.dart | 16 ++++++++++++++-- 6 files changed, 32 insertions(+), 7 deletions(-) diff --git a/moor/lib/src/runtime/query_builder/schema/table_info.dart b/moor/lib/src/runtime/query_builder/schema/table_info.dart index f2107783..4faa7a8e 100644 --- a/moor/lib/src/runtime/query_builder/schema/table_info.dart +++ b/moor/lib/src/runtime/query_builder/schema/table_info.dart @@ -54,6 +54,7 @@ mixin TableInfo on Table { /// The keys should represent the column name in sql, the values the /// corresponding values of the field. All fields of the [instance] which are /// present will be written, absent fields will be omitted. + /// Note that column names aren't escaped in the [Map.keys]. Map entityToSql(covariant UpdateCompanion instance); /// Maps the given row returned by the database into the fitting data class. diff --git a/moor/lib/src/runtime/query_builder/statements/insert.dart b/moor/lib/src/runtime/query_builder/statements/insert.dart index 31bd4c6e..73b744f3 100644 --- a/moor/lib/src/runtime/query_builder/statements/insert.dart +++ b/moor/lib/src/runtime/query_builder/statements/insert.dart @@ -106,9 +106,11 @@ class InsertStatement { if (map.isEmpty) { ctx.buffer.write('DEFAULT VALUES'); } else { + final columns = map.keys.map(escapeIfNeeded); + ctx.buffer ..write('(') - ..write(map.keys.join(', ')) + ..write(columns.join(', ')) ..write(') ') ..write('VALUES ('); diff --git a/moor/test/data/tables/todos.dart b/moor/test/data/tables/todos.dart index 7ea681b1..42c12825 100644 --- a/moor/test/data/tables/todos.dart +++ b/moor/test/data/tables/todos.dart @@ -56,7 +56,8 @@ class TableWithoutPK extends Table { } class PureDefaults extends Table with AutoIncrement { - TextColumn get txt => text().nullable()(); + // name after keyword to ensure it's escaped properly + TextColumn get txt => text().named('insert').nullable()(); } // example object used for custom mapping diff --git a/moor/test/data/tables/todos.g.dart b/moor/test/data/tables/todos.g.dart index 77075f17..7321f66c 100644 --- a/moor/test/data/tables/todos.g.dart +++ b/moor/test/data/tables/todos.g.dart @@ -1165,7 +1165,7 @@ class PureDefault extends DataClass implements Insertable { final stringType = db.typeSystem.forDartType(); return PureDefault( id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - txt: stringType.mapFromDatabaseResponse(data['${effectivePrefix}txt']), + txt: stringType.mapFromDatabaseResponse(data['${effectivePrefix}insert']), ); } factory PureDefault.fromJson(Map json, @@ -1257,7 +1257,7 @@ class $PureDefaultsTable extends PureDefaults GeneratedTextColumn get txt => _txt ??= _constructTxt(); GeneratedTextColumn _constructTxt() { return GeneratedTextColumn( - 'txt', + 'insert', $tableName, true, ); @@ -1303,7 +1303,7 @@ class $PureDefaultsTable extends PureDefaults map['id'] = Variable(d.id.value); } if (d.txt.present) { - map['txt'] = Variable(d.txt.value); + map['insert'] = Variable(d.txt.value); } return map; } diff --git a/moor/test/insert_test.dart b/moor/test/insert_test.dart index 9f4aff91..ba66aab4 100644 --- a/moor/test/insert_test.dart +++ b/moor/test/insert_test.dart @@ -157,4 +157,13 @@ void main() { completion(42), ); }); + + test('escaped when column name is keyword', () async { + await db + .into(db.pureDefaults) + .insert(PureDefaultsCompanion.insert(txt: const Value('foo'))); + + verify(executor + .runInsert('INSERT INTO pure_defaults (`insert`) VALUES (?)', ['foo'])); + }); } diff --git a/moor_generator/lib/src/backends/build/generators/moor_generator.dart b/moor_generator/lib/src/backends/build/generators/moor_generator.dart index 6bd790b7..c090e58f 100644 --- a/moor_generator/lib/src/backends/build/generators/moor_generator.dart +++ b/moor_generator/lib/src/backends/build/generators/moor_generator.dart @@ -3,6 +3,18 @@ import 'package:moor_generator/src/backends/build/moor_builder.dart'; import 'package:moor_generator/src/writer/database_writer.dart'; import 'package:source_gen/source_gen.dart'; +const _ignoredLints = [ + 'unnecessary_brace_in_string_interps', + 'unnecessary_this', + // more style rules from the Flutter repo we're violating. Should we fix + // those? + /* + 'always_specify_types', + 'implicit_dynamic_parameter', + 'sort_constructors_first', + 'lines_longer_than_80_chars',*/ +]; + class MoorGenerator extends Generator implements BaseGenerator { @override MoorBuilder builder; @@ -13,8 +25,8 @@ class MoorGenerator extends Generator implements BaseGenerator { final writer = builder.createWriter(); if (parsed.declaredDatabases.isNotEmpty) { - writer.leaf().write( - '// ignore_for_file: unnecessary_brace_in_string_interps, unnecessary_this\n'); + final ignore = '// ignore_for_file: ${_ignoredLints.join(', ')}\n'; + writer.leaf().write(ignore); } for (var db in parsed.declaredDatabases) {