diff --git a/docs/content/en/docs/Other engines/vm.md b/docs/content/en/docs/Other engines/vm.md index a386a545..79d95d5c 100644 --- a/docs/content/en/docs/Other engines/vm.md +++ b/docs/content/en/docs/Other engines/vm.md @@ -133,6 +133,7 @@ For more details on sqlite compile options, see [their documentation](https://ww returns null. Otherwise, returns the result of applying the matching function in `dart:math`. - `regexp`: Wraps the Dart `RegExp` apis, so that `foo REGEXP bar` is equivalent to `RegExp(bar).hasMatch(foo)`. Note that we have to create a new `RegExp` instance for each `regexp` sql call, which can impact performance on large queries. +- `current_time_millis`: Returns the current unix timestamp as milliseconds. Equivalent to `DateTime.now().millisecondsSinceEpoch` in Dart. Note that `NaN`, `-infinity` or `+infinity` are represented as `NULL` in sql. diff --git a/moor/lib/src/ffi/moor_ffi_functions.dart b/moor/lib/src/ffi/moor_ffi_functions.dart index 490644c9..9c2c9db8 100644 --- a/moor/lib/src/ffi/moor_ffi_functions.dart +++ b/moor/lib/src/ffi/moor_ffi_functions.dart @@ -91,6 +91,13 @@ extension EnableMoorFunctions on Database { argumentCount: const AllowedArgumentCount(3), function: _containsImpl, ); + createFunction( + functionName: 'current_time_millis', + deterministic: true, + directOnly: false, + argumentCount: const AllowedArgumentCount(0), + function: (List args) => DateTime.now().millisecondsSinceEpoch, + ); } } diff --git a/moor/test/ffi/moor_functions_test.dart b/moor/test/ffi/moor_functions_test.dart index 12869985..10902468 100644 --- a/moor/test/ffi/moor_functions_test.dart +++ b/moor/test/ffi/moor_functions_test.dart @@ -147,6 +147,11 @@ void main() { expect(selectSingle("moor_contains('hi', 'i', 1)"), 1); }); }); + + test('current_time_millis', () { + final now = DateTime.now().millisecondsSinceEpoch; + expect(selectSingle('current_time_millis()'), closeTo(now, 100)); + }); } // utils to verify the sql functions behave exactly like the ones from the VM diff --git a/moor_generator/lib/src/analyzer/moor/moor_ffi_extension.dart b/moor_generator/lib/src/analyzer/moor/moor_ffi_extension.dart index 0b73926c..e6c26fbd 100644 --- a/moor_generator/lib/src/analyzer/moor/moor_ffi_extension.dart +++ b/moor_generator/lib/src/analyzer/moor/moor_ffi_extension.dart @@ -23,7 +23,9 @@ class _MoorFfiFunctions with ArgumentCountLinter implements FunctionHandler { }; @override - Set get functionNames => const {'pow', ..._unaryFunctions}; + Set get functionNames { + return const {'pow', 'current_time_millis', ..._unaryFunctions}; + } @override int argumentCountFor(String function) { @@ -31,6 +33,8 @@ class _MoorFfiFunctions with ArgumentCountLinter implements FunctionHandler { return 1; } else if (function == 'pow') { return 2; + } else if (function == 'current_time_millis') { + return 0; } // ignore: avoid_returning_null return null; @@ -46,6 +50,11 @@ class _MoorFfiFunctions with ArgumentCountLinter implements FunctionHandler { @override ResolveResult inferReturnType(AnalysisContext context, SqlInvocation call, List expandedArgs) { + if (call.name == 'current_time_millis') { + return const ResolveResult( + ResolvedType(type: BasicType.int, nullable: false)); + } + return const ResolveResult( ResolvedType(type: BasicType.real, nullable: true)); } diff --git a/moor_generator/test/analyzer/moor/moor_ffi_extension_test.dart b/moor_generator/test/analyzer/moor/moor_ffi_extension_test.dart index 1b4faa8f..51ab3dfb 100644 --- a/moor_generator/test/analyzer/moor/moor_ffi_extension_test.dart +++ b/moor_generator/test/analyzer/moor/moor_ffi_extension_test.dart @@ -64,6 +64,15 @@ void main() { ]); }); + test('infers return type for current_time_millis', () { + final result = engine.analyze('SELECT current_time_millis();'); + final stmt = result.root as SelectStatement; + + expect(stmt.resolvedColumns.map(result.typeOf), [ + const ResolveResult(ResolvedType(type: BasicType.int, nullable: false)) + ]); + }); + test('infers argument type', () { final result = engine.analyze('SELECT pow(2.5, ?);'); final variable = result.root.allDescendants.whereType().first;