diff --git a/README.md b/README.md index 8444e50..b150a82 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ Useful utilities to augment [sqflite](https://pub.dev/packages/sqflite). Designed to be unobtrusive helpers, so you still access sqflite directly (not a wrapper). -## Features +## Usage -- Functions for working with `bool` values ([sqflite does not support bool](https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md#supported-sqlite-types)) +### Bool utilities -## Usage +Sqflite does not support the `bool` type ([reference](https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md#supported-sqlite-types)). ```dart import 'package:sqflite_ext/sqflite_ext.dart'; @@ -25,5 +25,17 @@ intToBool(1); intToBoolOrNull(null); // => null +``` + +### Named arguments + +```dart +import 'package:sqflite_ext/sqflite_ext.dart'; +final result = parseNamedArgs( + 'SELECT * FROM demo WHERE id = :id', + {'id': 83}, +); +// result.query => 'SELECT * FROM demo WHERE id = ?' +// result.arguments => [83] ``` diff --git a/example/example.dart b/example/example.dart index 9a623c7..c6e8217 100644 --- a/example/example.dart +++ b/example/example.dart @@ -27,6 +27,13 @@ void main() async { // use with json_annotation (see class DemoItem below) const item = DemoItem(isAwesome: true); await db.insert('demo', item.toJson()); + + // query with named args + final p = parseNamedArgs( + 'SELECT * FROM demo WHERE isAwesome = :status', + {'status': true}, + ); + await db.query(p.query, whereArgs: p.arguments); } @immutable diff --git a/lib/sqflite_ext.dart b/lib/sqflite_ext.dart index 973ca4b..837d9f5 100644 --- a/lib/sqflite_ext.dart +++ b/lib/sqflite_ext.dart @@ -1,3 +1,4 @@ library sqflite_ext; export 'src/boolean_utils.dart'; +export 'src/parse_named_args.dart'; diff --git a/lib/src/parse_named_args.dart b/lib/src/parse_named_args.dart new file mode 100644 index 0000000..8dc602e --- /dev/null +++ b/lib/src/parse_named_args.dart @@ -0,0 +1,25 @@ +/// A parsed raw query + argument values. +class QueryWithArgs { + QueryWithArgs(this.query, this.arguments); + + /// Query with named arguments replace with placeholders (?). + String query; + + /// List of query argument values. + List arguments; +} + +/// Parse a query with named arguments into a raw query + argument values. +QueryWithArgs parseNamedArgs(String query, Map params) { + final exp = RegExp(r":([\w]+)"); + List arguments = []; + RegExpMatch? match; + + while ((match = exp.firstMatch(query)) != null) { + final name = query.substring(match!.start + 1, match.end); + query = query.replaceRange(match.start, match.end, '?'); + arguments.add(params[name]); + } + + return QueryWithArgs(query, arguments); +} diff --git a/test/src/parse_named_args_test.dart b/test/src/parse_named_args_test.dart new file mode 100644 index 0000000..ab3254e --- /dev/null +++ b/test/src/parse_named_args_test.dart @@ -0,0 +1,62 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:sqflite_ext/src/parse_named_args.dart'; + +void main() { + group('parseNamedArgs', () { + test('with no params', () { + final result = parseNamedArgs( + 'SELECT * FROM demo', + {}, + ); + + expect(result.query, 'SELECT * FROM demo'); + expect(result.arguments, []); + }); + + test('with missing param', () { + final result = parseNamedArgs( + 'SELECT * FROM demo WHERE id = :fail', + {}, + ); + + expect(result.query, 'SELECT * FROM demo WHERE id = ?'); + expect(result.arguments, [null]); + }); + + test('with a single param', () { + final result = parseNamedArgs( + 'SELECT * FROM demo WHERE id = :id', + {'id': 83}, + ); + + expect(result.query, 'SELECT * FROM demo WHERE id = ?'); + expect(result.arguments, [83]); + }); + + test('with multiple different params', () { + final result = parseNamedArgs( + 'SELECT * FROM demo WHERE a = :a AND b = :b AND c = :c', + {'a': 83, 'b': 'active', 'c': true}, + ); + + expect( + result.query, + 'SELECT * FROM demo WHERE a = ? AND b = ? AND c = ?', + ); + expect(result.arguments, [83, 'active', true]); + }); + + test('with the same param multiple times', () { + final result = parseNamedArgs( + 'SELECT * FROM demo WHERE a = :a AND b = :b AND c = :b', + {'a': 83, 'b': 'active'}, + ); + + expect( + result.query, + 'SELECT * FROM demo WHERE a = ? AND b = ? AND c = ?', + ); + expect(result.arguments, [83, 'active', 'active']); + }); + }); +}