clean fts option strings; rowid fallback;

This commit is contained in:
Fabian Freund 2022-08-25 20:38:14 +03:00
parent b87e5cae0c
commit d5fac6da07
2 changed files with 62 additions and 3 deletions

View File

@ -14,6 +14,7 @@ class Fts5Extension implements Extension {
/// FTS5 module for `CREATE VIRTUAL TABLE USING fts5` support
class _Fts5Module extends Module {
static final RegExp _option = RegExp(r'^(.+)\s*=\s*(.+)$');
static final RegExp _cleanTicks = RegExp('[\'"]');
_Fts5Module() : super('fts5');
@ -31,14 +32,21 @@ class _Fts5Module extends Module {
// actual syntax is <name> <options...>
columnNames.add(argument.trim().split(' ').first);
} else {
options[match.group(1)!] = match.group(2)!;
options[match.group(1)!.replaceAll(_cleanTicks, '')] =
match.group(2)!.replaceAll(_cleanTicks, '');
}
}
//No external content when null or empty String
final contentTable =
(options['content']?.isNotEmpty ?? false) ? options['content'] : null;
//Fallback to "rowid" when option is not set
final contentRowId = options['content_rowid'] ?? 'rowid';
return Fts5Table._(
name: stmt.tableName,
contentTable: options['content'],
contentRowId: options['content_rowid'],
contentTable: contentTable,
contentRowId: (contentTable != null) ? contentRowId : null,
columns: [
for (var arg in columnNames)
TableColumn(arg, const ResolvedType(type: BasicType.text)),

View File

@ -18,6 +18,12 @@ void main() {
final columns = table.resultColumns;
expect(columns, hasLength(1));
expect(columns.single.name, 'bar');
expect(
table,
isA<Fts5Table>()
.having((e) => e.contentTable, 'contentTable', null)
.having((e) => e.contentRowId, 'contentRowId', null),
);
});
test('can create fts5 tables with content table', () {
@ -40,6 +46,51 @@ void main() {
);
});
test('does clean option values', () {
final result = engine.analyze('CREATE VIRTUAL TABLE foo USING '
"fts5(bar , tokenize = 'porter ascii', content='tbl', content_rowid='d')");
final table = const SchemaFromCreateTable()
.read(result.root as TableInducingStatement);
expect(
table,
isA<Fts5Table>()
.having((e) => e.contentTable, 'contentTable', 'tbl')
.having((e) => e.contentRowId, 'contentRowId', 'd'),
);
});
test('detects empty content table', () {
final result = engine.analyze('CREATE VIRTUAL TABLE foo USING '
"fts5(bar , tokenize = 'porter ascii',content='', content_rowid='d')");
final table = const SchemaFromCreateTable()
.read(result.root as TableInducingStatement);
expect(
table,
isA<Fts5Table>()
.having((e) => e.contentTable, 'contentTable', null)
.having((e) => e.contentRowId, 'contentRowId', null),
);
});
test('content table undefined rowid falls back', () {
final result = engine.analyze('CREATE VIRTUAL TABLE foo USING '
"fts5(bar , tokenize = 'porter ascii',content='tbl')");
final table = const SchemaFromCreateTable()
.read(result.root as TableInducingStatement);
expect(
table,
isA<Fts5Table>()
.having((e) => e.contentTable, 'contentTable', 'tbl')
.having((e) => e.contentRowId, 'contentRowId', 'rowid'),
);
});
group('creating fts5vocab tables', () {
final engine = SqlEngine(_fts5Options);