diff --git a/lib/_data_ingestion/open_local_db.dart b/lib/_data_ingestion/open_local_db.dart index a1f89cb..4d1bbce 100644 --- a/lib/_data_ingestion/open_local_db.dart +++ b/lib/_data_ingestion/open_local_db.dart @@ -1,10 +1,7 @@ import 'dart:ffi'; import 'dart:io'; -import 'package:jadb/_data_ingestion/jmdict/table_names.dart'; -import 'package:jadb/_data_ingestion/kanjidic/table_names.dart'; -import 'package:jadb/_data_ingestion/radkfile/table_names.dart'; -import 'package:jadb/_data_ingestion/tanos-jlpt/table_names.dart'; +import 'package:jadb/search.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqlite3/open.dart'; @@ -12,7 +9,7 @@ Future openLocalDb({ String? libsqlitePath, String? jadbPath, bool readWrite = false, - bool assertTablesExist = true, + bool verifyTablesExist = true, bool walMode = false, }) async { libsqlitePath ??= Platform.environment['LIBSQLITE_PATH']; @@ -52,43 +49,9 @@ Future openLocalDb({ ), ); - if (assertTablesExist) { - await _assertTablesExist(db); + if (verifyTablesExist) { + await db.jadbVerifyTables(); } return db; } - -Future _assertTablesExist(Database db) async { - final Set tables = await db - .query( - 'sqlite_master', - columns: ['name'], - where: 'type = ?', - whereArgs: ['table'], - ) - .then((result) { - return result.map((row) => row['name'] as String).toSet(); - }); - - final Set expectedTables = { - ...JMdictTableNames.allTables, - ...KANJIDICTableNames.allTables, - ...RADKFILETableNames.allTables, - ...TanosJLPTTableNames.allTables, - }; - - final missingTables = expectedTables.difference(tables); - - if (missingTables.isNotEmpty) { - throw Exception([ - 'Missing tables:', - missingTables.map((table) => ' - $table').join('\n'), - '', - 'Found tables:\n', - tables.map((table) => ' - $table').join('\n'), - '', - 'Please ensure the database is correctly set up.', - ].join('\n')); - } -} diff --git a/lib/cli/commands/query_kanji.dart b/lib/cli/commands/query_kanji.dart index f6e3895..3776d3e 100644 --- a/lib/cli/commands/query_kanji.dart +++ b/lib/cli/commands/query_kanji.dart @@ -35,7 +35,7 @@ class QueryKanji extends Command { ); final time = Stopwatch()..start(); - final result = await JaDBConnection(db).searchKanji( + final result = await JaDBConnection(db).jadbSearchKanji( argResults!.option('kanji') ?? '漢', ); time.stop(); diff --git a/lib/cli/commands/query_word.dart b/lib/cli/commands/query_word.dart index f0ee18d..caade0b 100644 --- a/lib/cli/commands/query_word.dart +++ b/lib/cli/commands/query_word.dart @@ -36,11 +36,11 @@ class QueryWord extends Command { final String searchWord = argResults!.option('word') ?? 'かな'; final time = Stopwatch()..start(); - final count = await JaDBConnection(db).searchWordCount(searchWord); + final count = await JaDBConnection(db).jadbSearchWordCount(searchWord); time.stop(); final time2 = Stopwatch()..start(); - final result = await JaDBConnection(db).searchWord(searchWord); + final result = await JaDBConnection(db).jadbSearchWord(searchWord); time2.stop(); if (result == null) { diff --git a/lib/models/verifyTables.dart b/lib/models/verifyTables.dart new file mode 100644 index 0000000..57fc307 --- /dev/null +++ b/lib/models/verifyTables.dart @@ -0,0 +1,39 @@ +import 'package:jadb/_data_ingestion/jmdict/table_names.dart'; +import 'package:jadb/_data_ingestion/kanjidic/table_names.dart'; +import 'package:jadb/_data_ingestion/radkfile/table_names.dart'; +import 'package:jadb/_data_ingestion/tanos-jlpt/table_names.dart'; +import 'package:sqflite_common/sqlite_api.dart'; + +Future verifyTablesWithDbConnection(DatabaseExecutor db) async { + final Set tables = await db + .query( + 'sqlite_master', + columns: ['name'], + where: 'type = ?', + whereArgs: ['table'], + ) + .then((result) { + return result.map((row) => row['name'] as String).toSet(); + }); + + final Set expectedTables = { + ...JMdictTableNames.allTables, + ...KANJIDICTableNames.allTables, + ...RADKFILETableNames.allTables, + ...TanosJLPTTableNames.allTables, + }; + + final missingTables = expectedTables.difference(tables); + + if (missingTables.isNotEmpty) { + throw Exception([ + 'Missing tables:', + missingTables.map((table) => ' - $table').join('\n'), + '', + 'Found tables:\n', + tables.map((table) => ' - $table').join('\n'), + '', + 'Please ensure the database is correctly set up.', + ].join('\n')); + } +} diff --git a/lib/search.dart b/lib/search.dart index c312166..641af61 100644 --- a/lib/search.dart +++ b/lib/search.dart @@ -1,3 +1,4 @@ +import 'package:jadb/models/verifyTables.dart'; import 'package:jadb/models/word_search/word_search_result.dart'; import 'package:jadb/models/kanji_search/kanji_search_result.dart'; import 'package:jadb/search/filter_kanji.dart'; @@ -8,31 +9,32 @@ import 'package:jadb/search/kanji_search.dart'; import 'package:sqflite_common/sqlite_api.dart'; -class JaDBConnection { - final DatabaseExecutor _connection; - - const JaDBConnection(this._connection); +extension JaDBConnection on DatabaseExecutor { + /// Ensure that the database contain all JaDB tables. + /// + /// This will throw an exception if any of the tables are missing. + Future jadbVerifyTables() => verifyTablesWithDbConnection(this); /// Search for a kanji in the database. - Future searchKanji(String kanji) => - searchKanjiWithDbConnection(this._connection, kanji); + Future jadbSearchKanji(String kanji) => + searchKanjiWithDbConnection(this, kanji); /// Filter a list of characters, and return the ones that are listed in the kanji dictionary. Future> filterKanji( List kanji, { bool deduplicate = false, }) => - filterKanjiWithDbConnection(this._connection, kanji, deduplicate); + filterKanjiWithDbConnection(this, kanji, deduplicate); /// Search for a word in the database. - Future?> searchWord( + Future?> jadbSearchWord( String word, { SearchMode searchMode = SearchMode.Auto, int page = 0, int pageSize = 10, }) => searchWordWithDbConnection( - this._connection, + this, word, searchMode, page, @@ -40,21 +42,21 @@ class JaDBConnection { ); /// Search for a word in the database, and return the count of results. - Future searchWordCount( + Future jadbSearchWordCount( String word, { SearchMode searchMode = SearchMode.Auto, }) => - searchWordCountWithDbConnection(this._connection, word, searchMode); + searchWordCountWithDbConnection(this, word, searchMode); /// Given a list of radicals, search which kanji contains all /// of the radicals, find their other radicals, and return those. /// This is used to figure out which remaining combinations of radicals /// the user can search for without getting zero results. - Future> searchRemainingRadicals(List radicals) => - searchRemainingRadicalsWithDbConnection(this._connection, radicals); + Future> jadbSearchRemainingRadicals(List radicals) => + searchRemainingRadicalsWithDbConnection(this, radicals); /// Given a list of radicals, search which kanji contains all /// of the radicals, and return those. - Future> searchKanjiByRadicals(List radicals) => - searchKanjiByRadicalsWithDbConnection(this._connection, radicals); + Future> jadbSearchKanjiByRadicals(List radicals) => + searchKanjiByRadicalsWithDbConnection(this, radicals); } diff --git a/test/search/kanji_search_test.dart b/test/search/kanji_search_test.dart index f05aca4..86284d3 100644 --- a/test/search/kanji_search_test.dart +++ b/test/search/kanji_search_test.dart @@ -1,4 +1,5 @@ import 'package:jadb/const_data/kanji_grades.dart'; +import 'package:jadb/search.dart'; import 'package:test/test.dart'; import 'setup_database_connection.dart'; @@ -7,7 +8,7 @@ void main() { test("Search a kanji", () async { final connection = await setup_database_connection(); - final result = await connection.searchKanji('漢'); + final result = await connection.jadbSearchKanji('漢'); expect(result, isNotNull); }); @@ -17,7 +18,7 @@ void main() { final connection = await setup_database_connection(); for (final character in characters) { - final result = await connection.searchKanji(character); + final result = await connection.jadbSearchKanji(character); expect(result, isNotNull); } }, timeout: Timeout.factor(10)); diff --git a/test/search/setup_database_connection.dart b/test/search/setup_database_connection.dart index 8c77d43..c52477b 100644 --- a/test/search/setup_database_connection.dart +++ b/test/search/setup_database_connection.dart @@ -1,9 +1,9 @@ import 'dart:io'; import 'package:jadb/_data_ingestion/open_local_db.dart'; -import 'package:jadb/search.dart'; +import 'package:sqflite_common/sqlite_api.dart'; -Future setup_database_connection() async { +Future setup_database_connection() async { final lib_sqlite_path = Platform.environment['LIBSQLITE_PATH']; final jadb_path = Platform.environment['JADB_PATH']; @@ -24,5 +24,5 @@ Future setup_database_connection() async { throw Exception("Failed to open database"); } - return JaDBConnection(db_connection); + return db_connection; } diff --git a/test/search/word_search_test.dart b/test/search/word_search_test.dart index 75c204a..e109fd5 100644 --- a/test/search/word_search_test.dart +++ b/test/search/word_search_test.dart @@ -1,3 +1,4 @@ +import 'package:jadb/search.dart'; import 'package:test/test.dart'; import 'setup_database_connection.dart'; @@ -6,7 +7,7 @@ void main() { test("Search a word", () async { final connection = await setup_database_connection(); - final result = await connection.searchWord("kana"); + final result = await connection.jadbSearchWord("kana"); expect(result, isNotNull); }); @@ -17,7 +18,7 @@ void main() { // Test serializing all words for (final letter in "aiueoksthnmyrw".split("")) { - await connection.searchWord(letter); + await connection.jadbSearchWord(letter); } }, timeout: Timeout.factor(100),