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 /// FTS5 module for `CREATE VIRTUAL TABLE USING fts5` support
class _Fts5Module extends Module { class _Fts5Module extends Module {
static final RegExp _option = RegExp(r'^(.+)\s*=\s*(.+)$'); static final RegExp _option = RegExp(r'^(.+)\s*=\s*(.+)$');
static final RegExp _cleanTicks = RegExp('[\'"]');
_Fts5Module() : super('fts5'); _Fts5Module() : super('fts5');
@ -31,14 +32,21 @@ class _Fts5Module extends Module {
// actual syntax is <name> <options...> // actual syntax is <name> <options...>
columnNames.add(argument.trim().split(' ').first); columnNames.add(argument.trim().split(' ').first);
} else { } 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._( return Fts5Table._(
name: stmt.tableName, name: stmt.tableName,
contentTable: options['content'], contentTable: contentTable,
contentRowId: options['content_rowid'], contentRowId: (contentTable != null) ? contentRowId : null,
columns: [ columns: [
for (var arg in columnNames) for (var arg in columnNames)
TableColumn(arg, const ResolvedType(type: BasicType.text)), TableColumn(arg, const ResolvedType(type: BasicType.text)),

View File

@ -18,6 +18,12 @@ void main() {
final columns = table.resultColumns; final columns = table.resultColumns;
expect(columns, hasLength(1)); expect(columns, hasLength(1));
expect(columns.single.name, 'bar'); 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', () { 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', () { group('creating fts5vocab tables', () {
final engine = SqlEngine(_fts5Options); final engine = SqlEngine(_fts5Options);