mirror of https://github.com/AMT-Cheif/drift.git
Static analysis support for spellfix1 (#2013)
This commit is contained in:
parent
87c58d0685
commit
cd89379627
|
@ -137,6 +137,9 @@ We currently support the following extensions:
|
|||
of trigonometric functions. Details on those functions are available [here]({{ "../Other engines/vm.md#moor-only-functions" | pageUrl }}).
|
||||
- `math`: Assumes that sqlite3 was compiled with [math functions](https://www.sqlite.org/lang_mathfunc.html).
|
||||
This module is largely incompatible with the `moor_ffi` module.
|
||||
- `spellfix1`: Assumes that the [spellfix1](https://www.sqlite.org/spellfix1.html)
|
||||
module is available. Note that this is not the case for most sqlite3 builds,
|
||||
including the ones shipping with `sqlite3_flutter_libs`.
|
||||
|
||||
## Recommended options
|
||||
|
||||
|
|
|
@ -279,4 +279,6 @@ enum SqlModule {
|
|||
/// Enables support for the rtree module and its functions when parsing sql
|
||||
/// queries.
|
||||
rtree,
|
||||
|
||||
spellfix1,
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ const _$SqlModuleEnumMap = {
|
|||
SqlModule.moor_ffi: 'moor_ffi',
|
||||
SqlModule.math: 'math',
|
||||
SqlModule.rtree: 'rtree',
|
||||
SqlModule.spellfix1: 'spellfix1',
|
||||
};
|
||||
|
||||
DialectOptions _$DialectOptionsFromJson(Map json) => $checkedCreate(
|
||||
|
|
|
@ -46,6 +46,7 @@ class MoorSession {
|
|||
if (options.hasModule(SqlModule.moor_ffi)) const MoorFfiExtension(),
|
||||
if (options.hasModule(SqlModule.math)) const BuiltInMathExtension(),
|
||||
if (options.hasModule(SqlModule.rtree)) const RTreeExtension(),
|
||||
if (options.hasModule(SqlModule.spellfix1)) const Spellfix1Extension(),
|
||||
],
|
||||
version: options.sqliteVersion,
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ export 'src/engine/module/fts5.dart' show Fts5Extension, Fts5Table;
|
|||
export 'src/engine/module/json1.dart' show Json1Extension;
|
||||
export 'src/engine/module/math.dart' show BuiltInMathExtension;
|
||||
export 'src/engine/module/rtree.dart' show RTreeExtension;
|
||||
export 'src/engine/module/spellfix1.dart' show Spellfix1Extension;
|
||||
export 'src/engine/module/module.dart';
|
||||
export 'src/engine/options.dart';
|
||||
export 'src/engine/sql_engine.dart';
|
||||
|
|
|
@ -41,6 +41,10 @@ class TableColumn extends Column implements ColumnWithType {
|
|||
/// Generated columns can't be inserted or updated.
|
||||
final bool isGenerated;
|
||||
|
||||
/// Whether this column is `HIDDEN`, as specified in
|
||||
/// https://www.sqlite.org/vtab.html#hidden_columns_in_virtual_tables
|
||||
final bool isHidden;
|
||||
|
||||
@override
|
||||
ResultSet? get containingSet => table;
|
||||
|
||||
|
@ -69,8 +73,16 @@ class TableColumn extends Column implements ColumnWithType {
|
|||
|
||||
late final bool _isAliasForRowId = _computeIsAliasForRowId();
|
||||
|
||||
TableColumn(this.name, this._type,
|
||||
{this.definition, this.isGenerated = false});
|
||||
TableColumn(
|
||||
this.name,
|
||||
this._type, {
|
||||
this.definition,
|
||||
this.isGenerated = false,
|
||||
this.isHidden = false,
|
||||
});
|
||||
|
||||
@override
|
||||
bool get includedInResults => !isHidden;
|
||||
|
||||
/// Applies a type hint to this column.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import 'package:sqlparser/sqlparser.dart';
|
||||
|
||||
class Spellfix1Extension implements Extension {
|
||||
const Spellfix1Extension();
|
||||
|
||||
@override
|
||||
void register(SqlEngine engine) {
|
||||
engine.registerModule(_Spellfix1Module());
|
||||
}
|
||||
}
|
||||
|
||||
class _Spellfix1Module extends Module {
|
||||
_Spellfix1Module() : super('spellfix1');
|
||||
|
||||
@override
|
||||
Table parseTable(CreateVirtualTableStatement stmt) {
|
||||
return Table(
|
||||
name: stmt.tableName,
|
||||
resolvedColumns: [
|
||||
TableColumn('word', const ResolvedType(type: BasicType.text)),
|
||||
TableColumn(
|
||||
'rank', const ResolvedType(type: BasicType.int, nullable: true)),
|
||||
TableColumn('distance',
|
||||
const ResolvedType(type: BasicType.int, nullable: true)),
|
||||
TableColumn('langid',
|
||||
const ResolvedType(type: BasicType.int, nullable: true)),
|
||||
TableColumn(
|
||||
'score', const ResolvedType(type: BasicType.int, nullable: true)),
|
||||
TableColumn('matchlen',
|
||||
const ResolvedType(type: BasicType.int, nullable: true)),
|
||||
TableColumn(
|
||||
'top',
|
||||
const ResolvedType(type: BasicType.int),
|
||||
isHidden: true,
|
||||
),
|
||||
TableColumn(
|
||||
'scope',
|
||||
const ResolvedType(type: BasicType.int),
|
||||
isHidden: true,
|
||||
),
|
||||
TableColumn(
|
||||
'srchcnt',
|
||||
const ResolvedType(type: BasicType.int),
|
||||
isHidden: true,
|
||||
),
|
||||
TableColumn(
|
||||
'soundslike',
|
||||
const ResolvedType(type: BasicType.text),
|
||||
isHidden: true,
|
||||
),
|
||||
TableColumn(
|
||||
'command',
|
||||
const ResolvedType(type: BasicType.int),
|
||||
isHidden: true,
|
||||
),
|
||||
],
|
||||
definition: stmt,
|
||||
isVirtual: true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import 'package:sqlparser/sqlparser.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final _spellfixOptions =
|
||||
EngineOptions(enabledExtensions: const [Spellfix1Extension()]);
|
||||
|
||||
void main() {
|
||||
final engine = SqlEngine(_spellfixOptions);
|
||||
test('creating spellfix1 table', () {
|
||||
final result = engine.analyze('CREATE VIRTUAL TABLE demo USING spellfix1;');
|
||||
|
||||
final table = const SchemaFromCreateTable()
|
||||
.read(result.root as TableInducingStatement);
|
||||
|
||||
expect(table.name, 'demo');
|
||||
final columns = table.resultColumns;
|
||||
expect(columns, hasLength(6));
|
||||
});
|
||||
|
||||
group('engine analyze spellfix1', () {
|
||||
late SqlEngine engine;
|
||||
setUp(() {
|
||||
engine = SqlEngine(_spellfixOptions);
|
||||
final fts5Result =
|
||||
engine.analyze('CREATE VIRTUAL TABLE demo USING spellfix1;');
|
||||
engine.registerTable(const SchemaFromCreateTable()
|
||||
.read(fts5Result.root as TableInducingStatement));
|
||||
});
|
||||
|
||||
test('ignore hidden columns in result', () {
|
||||
final result =
|
||||
engine.analyze('SELECT * FROM demo WHERE word MATCH \'none\'');
|
||||
expect(result.errors, isEmpty);
|
||||
|
||||
final select = result.root as SelectStatement;
|
||||
expect(select.resolvedColumns, hasLength(6));
|
||||
});
|
||||
|
||||
test('accepts hidden columns in query', () {
|
||||
final result = engine
|
||||
.analyze('SELECT * FROM demo WHERE word MATCH \'none\' AND top=3');
|
||||
expect(result.errors, isEmpty);
|
||||
});
|
||||
|
||||
test('consideres hidden columns', () {
|
||||
final result = engine.analyze(
|
||||
'SELECT * FROM demo WHERE word MATCH \'none\' AND noneexistent=3');
|
||||
expect(result.errors, hasLength(1));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue