Support table-valued json1 functions

This commit is contained in:
Simon Binder 2020-01-26 14:42:52 +01:00
parent 5268d88344
commit 71ef9b8cd7
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 72 additions and 7 deletions

View File

@ -13,8 +13,6 @@ abstract class Column
/// Some columns, notably the rowid aliases, are exempt from this.
bool get includedInResults => true;
Column();
@override
String humanReadableDescription() {
return name;

View File

@ -24,6 +24,14 @@ abstract class ResultSet implements ResolvesToResultSet {
}
}
/// A custom result set that has columns but isn't a table.
class CustomResultSet with ResultSet {
@override
final List<Column> resolvedColumns;
CustomResultSet(this.resolvedColumns);
}
/// A database table. The information stored here will be used to resolve
/// references and for type inference.
class Table

View File

@ -5,7 +5,10 @@ class Json1Extension implements Extension {
@override
void register(SqlEngine engine) {
engine.registerFunctionHandler(const _Json1Functions());
engine
..registerFunctionHandler(const _Json1Functions())
..registerTableValuedFunctionHandler(const _JsonEachFunction())
..registerTableValuedFunctionHandler(const _JsonTreeFunction());
}
}
@ -68,3 +71,42 @@ class _Json1Functions implements FunctionHandler {
@override
void reportErrors(SqlInvocation call, AnalysisContext context) {}
}
final _jsonFunctionResultSet = CustomResultSet([
// https://www.sqlite.org/json1.html#the_json_each_and_json_tree_table_valued_functions
// we use string for any
TableColumn('key', const ResolvedType(type: BasicType.text)),
TableColumn(
'value', const ResolvedType(type: BasicType.text, nullable: true)),
TableColumn('type', const ResolvedType(type: BasicType.text)),
TableColumn('atom', const ResolvedType(type: BasicType.text)),
TableColumn('type', const ResolvedType(type: BasicType.text)),
TableColumn('id', const ResolvedType(type: BasicType.int)),
TableColumn(
'parent', const ResolvedType(type: BasicType.int, nullable: true)),
TableColumn('fullkey', const ResolvedType(type: BasicType.text)),
]);
abstract class _JsonTableValuedFunction implements TableValuedFunctionHandler {
const _JsonTableValuedFunction();
@override
ResultSet resolveTableValued(
AnalysisContext context, TableValuedFunction call) {
return _jsonFunctionResultSet;
}
}
class _JsonEachFunction extends _JsonTableValuedFunction {
const _JsonEachFunction();
@override
String get functionName => 'json_each';
}
class _JsonTreeFunction extends _JsonTableValuedFunction {
const _JsonTreeFunction();
@override
String get functionName => 'json_tree';
}

View File

@ -12,11 +12,18 @@ void main() {
}
void _runTests(bool types2) {
final engine = SqlEngine.withOptions(EngineOptions(
enableExperimentalTypeInference: types2,
enabledExtensions: const [Json1Extension()],
));
// add user (name, phone) table
final table = engine.schemaReader.read(
engine.parse('CREATE TABLE user (name TEXT, phone TEXT)').rootNode
as TableInducingStatement,
);
engine.registerTable(table);
ResolveResult findResult(String expression) {
final engine = SqlEngine.withOptions(EngineOptions(
enableExperimentalTypeInference: types2,
enabledExtensions: const [Json1Extension()],
));
final result = engine.analyze('SELECT $expression;');
final select = result.root as SelectStatement;
@ -63,4 +70,14 @@ void _runTests(bool types2) {
const ResolveResult(ResolvedType(type: BasicType.int)),
);
});
test('can use table-valued functions', () {
final result = engine.analyze('''
SELECT DISTINCT user.name
FROM user, json_each(user.phone)
WHERE json_each.value LIKE '704-%';
''');
expect(result.errors, isEmpty);
});
}