mirror of https://github.com/AMT-Cheif/drift.git
Dart apis for the json1 extension (#235)
This commit is contained in:
parent
d2c863c5fc
commit
59f408229b
|
@ -9,7 +9,8 @@
|
|||
return ...
|
||||
}).get();
|
||||
```
|
||||
|
||||
- Provide Dart apis for the json1 extension in the `package:moor/extensions/json1.dart` library. Note that
|
||||
json1 is not supported on most platforms.
|
||||
- Batches are now always sent in a transaction, this used to be implementation specific before
|
||||
|
||||
## 2.1.0
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/// Experimental bindings to the [json1](https://www.sqlite.org/json1.html)
|
||||
/// sqlite extension.
|
||||
///
|
||||
/// Note that the json1 extension might not be available on all runtimes. In
|
||||
/// particular, it can only work reliably on Android when using the
|
||||
/// [moor_ffi](https://moor.simonbinder.eu/docs/other-engines/vm/) and it might
|
||||
/// not work on older iOS versions.
|
||||
@experimental
|
||||
library json1;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import '../moor.dart';
|
||||
|
||||
/// Defines extensions on string expressions to support the json1 api from Dart.
|
||||
extension JsonExtensions on Expression<String, StringType> {
|
||||
/// Assuming that this string is a json array, returns the length of this json
|
||||
/// array.
|
||||
///
|
||||
/// The [path] parameter is optional. If it's set, it must refer to a valid
|
||||
/// path in this json that will be used instead of `this`. See the
|
||||
/// [sqlite documentation](https://www.sqlite.org/json1.html#path_arguments)
|
||||
/// for details. If [path] is an invalid path, this expression can cause an
|
||||
/// error when run by sqlite.
|
||||
///
|
||||
/// For this method to be valid, `this` must be a string representing a valid
|
||||
/// json array. Otherwise, sqlite will report an error when attempting to
|
||||
/// evaluate this expression.
|
||||
///
|
||||
/// See also:
|
||||
/// - the [sqlite documentation for this function](https://www.sqlite.org/json1.html#the_json_array_length_function)
|
||||
Expression<int, IntType> jsonArrayLength([String path]) {
|
||||
return FunctionCallExpression('json_array_length', [
|
||||
this,
|
||||
if (path != null) Variable.withString(path),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Assuming that this string is a json object or array, extracts a part of
|
||||
/// this structure identified by [path].
|
||||
///
|
||||
/// For more details on how to format the [path] argument, see the
|
||||
/// [sqlite documentation](https://www.sqlite.org/json1.html#path_arguments).
|
||||
///
|
||||
/// Evaluating this expression will cause an error if [path] has an invalid
|
||||
/// format or `this` isn't well-formatted json.
|
||||
///
|
||||
/// Note that, since the return type of this function is dynamic, it can't be
|
||||
/// used in [JoinedSelectStatement.addColumns]. It's also recommended to use
|
||||
/// [Expression.equalsExp] with an explicit [Variable] instead of
|
||||
/// [Expression.equals].
|
||||
Expression jsonExtract(String path) {
|
||||
return FunctionCallExpression('json_extract', [
|
||||
this,
|
||||
Variable.withString(path),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -47,10 +47,7 @@ class UseMoor {
|
|||
/// Defines the `.moor` files to include when building the table structure for
|
||||
/// this database. For details on how to integrate `.moor` files into your
|
||||
/// Dart code, see [the documentation](https://moor.simonbinder.eu/docs/using-sql/custom_tables/).
|
||||
///
|
||||
/// Please note that this feature is experimental at the moment.
|
||||
/// {@endtemplate}
|
||||
@experimental
|
||||
final Set<String> include;
|
||||
|
||||
/// Use this class as an annotation to inform moor_generator that a database
|
||||
|
@ -59,7 +56,7 @@ class UseMoor {
|
|||
@required this.tables,
|
||||
this.daos = const [],
|
||||
this.queries = const {},
|
||||
@experimental this.include = const {},
|
||||
this.include = const {},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -92,7 +89,6 @@ class UseDao {
|
|||
final Map<String, String> queries;
|
||||
|
||||
/// {@macro moor_include_param}
|
||||
@experimental
|
||||
final Set<String> include;
|
||||
|
||||
/// Annotation for a class to declare it as an dao. See [UseDao] and the
|
||||
|
@ -100,5 +96,5 @@ class UseDao {
|
|||
const UseDao(
|
||||
{@required this.tables,
|
||||
this.queries = const {},
|
||||
@experimental this.include = const {}});
|
||||
this.include = const {}});
|
||||
}
|
||||
|
|
|
@ -313,15 +313,24 @@ class _CastExpression<D1, D2, S1 extends SqlType<D1>, S2 extends SqlType<D2>>
|
|||
}
|
||||
}
|
||||
|
||||
class _FunctionCallExpression<R, S extends SqlType<R>>
|
||||
extends Expression<R, S> {
|
||||
/// A sql expression that calls a function.
|
||||
///
|
||||
/// This class is mainly used by moor internally. If you find yourself using
|
||||
/// this class, consider [creating an issue](https://github.com/simolus3/moor/issues/new)
|
||||
/// to request native support in moor.
|
||||
class FunctionCallExpression<R, S extends SqlType<R>> extends Expression<R, S> {
|
||||
/// The name of the function to call
|
||||
final String functionName;
|
||||
|
||||
/// The arguments passed to the function, as expressions.
|
||||
final List<Expression> arguments;
|
||||
|
||||
@override
|
||||
final Precedence precedence = Precedence.primary;
|
||||
|
||||
_FunctionCallExpression(this.functionName, this.arguments);
|
||||
/// Constructs a function call expression in sql from the [functionName] and
|
||||
/// the target [arguments].
|
||||
FunctionCallExpression(this.functionName, this.arguments);
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
|
@ -345,7 +354,7 @@ class _FunctionCallExpression<R, S extends SqlType<R>>
|
|||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
return other is _FunctionCallExpression &&
|
||||
return other is FunctionCallExpression &&
|
||||
other.functionName == functionName &&
|
||||
_equality.equals(other.arguments, arguments);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ extension StringExpressionOperators on Expression<String, StringType> {
|
|||
/// See also:
|
||||
/// - https://www.w3resource.com/sqlite/core-functions-upper.php
|
||||
Expression<String, StringType> upper() {
|
||||
return _FunctionCallExpression('UPPER', [this]);
|
||||
return FunctionCallExpression('UPPER', [this]);
|
||||
}
|
||||
|
||||
/// Calls the sqlite function `LOWER` on `this` string. Please note that, in
|
||||
|
@ -37,7 +37,7 @@ extension StringExpressionOperators on Expression<String, StringType> {
|
|||
/// See also:
|
||||
/// - https://www.w3resource.com/sqlite/core-functions-lower.php
|
||||
Expression<String, StringType> lower() {
|
||||
return _FunctionCallExpression('LOWER', [this]);
|
||||
return FunctionCallExpression('LOWER', [this]);
|
||||
}
|
||||
|
||||
/// Calls the sqlite function `LENGTH` on `this` string, which counts the
|
||||
|
@ -47,7 +47,7 @@ extension StringExpressionOperators on Expression<String, StringType> {
|
|||
/// See also:
|
||||
/// - https://www.w3resource.com/sqlite/core-functions-length.php
|
||||
Expression<int, IntType> get length {
|
||||
return _FunctionCallExpression('LENGTH', [this]);
|
||||
return FunctionCallExpression('LENGTH', [this]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,14 @@ import 'package:moor/moor.dart';
|
|||
import 'package:test/test.dart';
|
||||
|
||||
extension ComponentExpectations on Component {
|
||||
void expectGenerates(String sql) {
|
||||
void expectGenerates(String sql, [List<dynamic> variables]) {
|
||||
final ctx = GenerationContext(SqlTypeSystem.defaultInstance, null);
|
||||
writeInto(ctx);
|
||||
|
||||
expect(ctx.sql, sql);
|
||||
|
||||
if (variables != null) {
|
||||
expect(ctx.boundVariables, variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:moor/moor.dart';
|
||||
import 'package:moor/extensions/json1.dart';
|
||||
import 'package:moor_ffi/moor_ffi.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../data/tables/todos.dart';
|
||||
import '../data/utils/expect_generated.dart';
|
||||
|
||||
void main() {
|
||||
test('json1 functions generate valid sql', () {
|
||||
final column = GeneratedTextColumn('col', 'tbl', false);
|
||||
|
||||
column.jsonArrayLength().expectGenerates('json_array_length(col)');
|
||||
column
|
||||
.jsonArrayLength(r'$.c')
|
||||
.expectGenerates('json_array_length(col, ?)', [r'$.c']);
|
||||
|
||||
column
|
||||
.jsonExtract(r'$.c')
|
||||
.expectGenerates('json_extract(col, ?)', [r'$.c']);
|
||||
});
|
||||
|
||||
test('json1 integration test', () async {
|
||||
final db = TodoDb(VmDatabase.memory());
|
||||
const jsonObject = {
|
||||
'foo': 'bar',
|
||||
'array': [
|
||||
'one',
|
||||
'two',
|
||||
'three',
|
||||
],
|
||||
};
|
||||
await db
|
||||
.into(db.pureDefaults)
|
||||
.insert(PureDefaultsCompanion(txt: Value(json.encode(jsonObject))));
|
||||
|
||||
final arrayLengthExpr = db.pureDefaults.txt.jsonArrayLength(r'$.array');
|
||||
final query = db.select(db.pureDefaults).addColumns([arrayLengthExpr]);
|
||||
query.where(db.pureDefaults.txt
|
||||
.jsonExtract(r'$.foo')
|
||||
.equalsExp(Variable.withString('bar')));
|
||||
|
||||
final resultRow = await query.getSingle();
|
||||
expect(resultRow.read(arrayLengthExpr), 3);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue