diff --git a/lib/search.dart b/lib/search.dart index 9ab1d85..73112e6 100644 --- a/lib/search.dart +++ b/lib/search.dart @@ -1,7 +1,7 @@ import 'package:jadb/models/word_search/word_search_result.dart'; import 'package:jadb/models/kanji_search/kanji_search_result.dart'; import 'package:jadb/models/radkfile/radicals_search_result.dart'; -import 'package:jadb/search/word_search.dart'; +import 'package:jadb/search/word_search/word_search.dart'; import 'package:jadb/search/kanji_search.dart'; diff --git a/lib/search/word_search/data_query.dart b/lib/search/word_search/data_query.dart new file mode 100644 index 0000000..1eb1ef8 --- /dev/null +++ b/lib/search/word_search/data_query.dart @@ -0,0 +1,292 @@ +import 'package:jadb/util/sqlite_utils.dart'; +import 'package:sqflite_common/sqflite.dart'; + +class LinearWordQueryData { + final List> senses; + final List> readingElements; + final List> kanjiElements; + final List> jlptTags; + final List> commonEntries; + final List> senseAntonyms; + final List> senseDialects; + final List> senseFields; + final List> senseGlossaries; + final List> senseInfos; + final List> senseLanguageSources; + final List> senseMiscs; + final List> sensePOSs; + final List> senseRestrictedToKanjis; + final List> senseRestrictedToReadings; + final List> senseSeeAlsos; + final List> exampleSentences; + final List> readingElementInfos; + final List> readingElementRestrictions; + final List> kanjiElementInfos; + + const LinearWordQueryData({ + required this.senses, + required this.readingElements, + required this.kanjiElements, + required this.jlptTags, + required this.commonEntries, + required this.senseAntonyms, + required this.senseDialects, + required this.senseFields, + required this.senseGlossaries, + required this.senseInfos, + required this.senseLanguageSources, + required this.senseMiscs, + required this.sensePOSs, + required this.senseRestrictedToKanjis, + required this.senseRestrictedToReadings, + required this.senseSeeAlsos, + required this.exampleSentences, + required this.readingElementInfos, + required this.readingElementRestrictions, + required this.kanjiElementInfos, + }); +} + +Future fetchLinearWordQueryData( + DatabaseExecutor connection, + List entryIds, +) async { + + late final List> senses; + final Future>> senses_query = connection.query( + 'JMdict_Sense', + where: 'entryId IN (${entryIds.join(',')})', + ); + + late final List> readingElements; + final Future>> readingElements_query = + connection.query( + 'JMdict_ReadingElement', + where: 'entryId IN (${entryIds.join(',')})', + ); + + late final List> kanjiElements; + final Future>> kanjiElements_query = + connection.query( + 'JMdict_KanjiElement', + where: 'entryId IN (${entryIds.join(',')})', + ); + + late final List> jlptTags; + final Future>> jlptTags_query = connection.query( + 'JMdict_JLPTTag', + where: 'entryId IN (${entryIds.join(',')})', + ); + + late final List> commonEntries; + final Future>> commonEntries_query = + connection.query( + 'JMdict_EntryCommon', + where: 'entryId IN (${entryIds.join(',')})', + ); + + await Future.wait([ + senses_query.then((value) => senses = value), + readingElements_query.then((value) => readingElements = value), + kanjiElements_query.then((value) => kanjiElements = value), + jlptTags_query.then((value) => jlptTags = value), + commonEntries_query.then((value) => commonEntries = value), + ]); + + // Sense queries + + final senseIds = senses.map((sense) => sense['senseId'] as int).toList(); + + late final List> senseAntonyms; + final Future>> senseAntonyms_query = + connection.rawQuery(""" + SELECT + JMdict_SenseAntonym.senseId, + JMdict_SenseAntonym.ambiguous, + JMdict_SenseAntonym.xrefEntryId, + JMdict_BaseAndFurigana.base, + JMdict_BaseAndFurigana.furigana + FROM JMdict_SenseAntonym + JOIN "JMdict_BaseAndFurigana" + ON JMdict_SenseAntonym.xrefEntryId = JMdict_BaseAndFurigana.entryId + WHERE + senseId IN (${senseIds.join(',')}) + AND COALESCE("JMdict_BaseAndFurigana"."kanjiOrderNum", 1) + + "JMdict_BaseAndFurigana"."readingOrderNum" + = 2 + ORDER BY + JMdict_SenseAntonym.senseId, + JMdict_SenseAntonym.xrefEntryId + """); + + late final List> senseDialects; + final Future>> senseDialects_query = + connection.query( + 'JMdict_SenseDialect', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseFields; + final Future>> senseFields_query = connection.query( + 'JMdict_SenseField', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseGlossaries; + final Future>> senseGlossaries_query = + connection.query( + 'JMdict_SenseGlossary', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseInfos; + final Future>> senseInfos_query = connection.query( + 'JMdict_SenseInfo', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseLanguageSources; + final Future>> senseLanguageSources_query = + connection.query( + 'JMdict_SenseLanguageSource', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseMiscs; + final Future>> senseMiscs_query = connection.query( + 'JMdict_SenseMisc', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> sensePOSs; + final Future>> sensePOSs_query = connection.query( + 'JMdict_SensePOS', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseRestrictedToKanjis; + final Future>> senseRestrictedToKanjis_query = + connection.query( + 'JMdict_SenseRestrictedToKanji', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseRestrictedToReadings; + final Future>> senseRestrictedToReadings_query = + connection.query( + 'JMdict_SenseRestrictedToReading', + where: 'senseId IN (${senseIds.join(',')})', + ); + + late final List> senseSeeAlsos; + final Future>> senseSeeAlsos_query = + connection.rawQuery(""" + SELECT + JMdict_SenseSeeAlso.senseId, + JMdict_SenseSeeAlso.ambiguous, + JMdict_SenseSeeAlso.xrefEntryId, + JMdict_BaseAndFurigana.base, + JMdict_BaseAndFurigana.furigana + FROM JMdict_SenseSeeAlso + JOIN "JMdict_BaseAndFurigana" + ON JMdict_SenseSeeAlso.xrefEntryId = JMdict_BaseAndFurigana.entryId + WHERE + senseId IN (${senseIds.join(',')}) + AND COALESCE("JMdict_BaseAndFurigana"."kanjiOrderNum", 1) + + "JMdict_BaseAndFurigana"."readingOrderNum" + = 2 + ORDER BY + JMdict_SenseSeeAlso.senseId, + JMdict_SenseSeeAlso.xrefEntryId + """); + + late final List> exampleSentences; + final Future>> exampleSentences_query = + connection.query( + 'JMdict_ExampleSentence', + where: 'senseId IN (${senseIds.join(',')})', + ); + + // Reading queries + + final readingIds = readingElements + .map((element) => ( + element['entryId'] as int, + escapeStringValue(element['reading'] as String) + )) + .toList(); + + late final List> readingElementInfos; + final Future>> readingElementInfos_query = + connection.query( + 'JMdict_ReadingElementInfo', + where: '(entryId, reading) IN (${readingIds.join(',')})', + ); + + late final List> readingElementRestrictions; + final Future>> readingElementRestrictions_query = + connection.query( + 'JMdict_ReadingElementRestriction', + where: '(entryId, reading) IN (${readingIds.join(',')})', + ); + + // Kanji queries + + final kanjiIds = kanjiElements + .map((element) => ( + element['entryId'] as int, + escapeStringValue(element['reading'] as String) + )) + .toList(); + + late final List> kanjiElementInfos; + final Future>> kanjiElementInfos_query = + connection.query( + 'JMdict_KanjiElementInfo', + where: '(entryId, reading) IN (${kanjiIds.join(',')})', + ); + + await Future.wait([ + senseAntonyms_query.then((value) => senseAntonyms = value), + senseDialects_query.then((value) => senseDialects = value), + senseFields_query.then((value) => senseFields = value), + senseGlossaries_query.then((value) => senseGlossaries = value), + senseInfos_query.then((value) => senseInfos = value), + senseLanguageSources_query.then((value) => senseLanguageSources = value), + senseMiscs_query.then((value) => senseMiscs = value), + sensePOSs_query.then((value) => sensePOSs = value), + senseRestrictedToKanjis_query + .then((value) => senseRestrictedToKanjis = value), + senseRestrictedToReadings_query + .then((value) => senseRestrictedToReadings = value), + senseSeeAlsos_query.then((value) => senseSeeAlsos = value), + exampleSentences_query.then((value) => exampleSentences = value), + readingElementInfos_query.then((value) => readingElementInfos = value), + readingElementRestrictions_query + .then((value) => readingElementRestrictions = value), + kanjiElementInfos_query.then((value) => kanjiElementInfos = value), + ]); + + return LinearWordQueryData( + senses: senses, + readingElements: readingElements, + kanjiElements: kanjiElements, + jlptTags: jlptTags, + commonEntries: commonEntries, + senseAntonyms: senseAntonyms, + senseDialects: senseDialects, + senseFields: senseFields, + senseGlossaries: senseGlossaries, + senseInfos: senseInfos, + senseLanguageSources: senseLanguageSources, + senseMiscs: senseMiscs, + sensePOSs: sensePOSs, + senseRestrictedToKanjis: senseRestrictedToKanjis, + senseRestrictedToReadings: senseRestrictedToReadings, + senseSeeAlsos: senseSeeAlsos, + exampleSentences: exampleSentences, + readingElementInfos: readingElementInfos, + readingElementRestrictions: readingElementRestrictions, + kanjiElementInfos: kanjiElementInfos, + ); +} diff --git a/lib/search/word_search/entry_id_query.dart b/lib/search/word_search/entry_id_query.dart new file mode 100644 index 0000000..96523ca --- /dev/null +++ b/lib/search/word_search/entry_id_query.dart @@ -0,0 +1,72 @@ +import 'package:jadb/search/word_search/word_search.dart'; +import 'package:jadb/util/text_filtering.dart'; +import 'package:sqflite_common/sqlite_api.dart'; + +SearchMode _determineSearchMode(String word) { + final bool containsKanji = kanjiRegex.hasMatch(word); + final bool containsAscii = RegExp(r'[A-Za-z]').hasMatch(word); + + if (containsKanji && containsAscii) { + return SearchMode.MixedKanji; + } else if (containsKanji) { + return SearchMode.Kanji; + } else if (containsAscii) { + return SearchMode.English; + } else if (word.contains(hiraganaRegex) || word.contains(katakanaRegex)) { + return SearchMode.Kana; + } else { + return SearchMode.MixedKana; + } +} + +Future> fetchEntryIds( + DatabaseExecutor connection, + String word, + SearchMode searchMode, + int pageSize, + int? offset, +) async { + if (searchMode == SearchMode.Auto) { + searchMode = _determineSearchMode(word); + } + + assert( + word.isNotEmpty, + 'Word should not be empty when fetching entry IDs', + ); + + late final List entryIds; + if (searchMode == SearchMode.Kanji) { + entryIds = (await connection.query( + 'JMdict_EntryByKanji', + where: 'kanji LIKE ?', + whereArgs: ['%$word%'], + limit: pageSize, + offset: offset, + )) + .map((row) => row['entryId'] as int) + .toList(); + } else if (searchMode == SearchMode.Kana) { + entryIds = (await connection.query( + 'JMdict_EntryByKana', + where: 'kana LIKE ?', + whereArgs: ['%$word%'], + limit: pageSize, + offset: offset, + )) + .map((row) => row['entryId'] as int) + .toList(); + } else { + entryIds = (await connection.query( + 'JMdict_EntryByEnglish', + where: 'english LIKE ?', + whereArgs: ['%$word%'], + limit: pageSize, + offset: offset, + )) + .map((row) => row['entryId'] as int) + .toList(); + } + + return entryIds; +} diff --git a/lib/search/word_search.dart b/lib/search/word_search/regrouping.dart similarity index 50% rename from lib/search/word_search.dart rename to lib/search/word_search/regrouping.dart index e415700..4b4b31a 100644 --- a/lib/search/word_search.dart +++ b/lib/search/word_search/regrouping.dart @@ -12,363 +12,8 @@ import 'package:jadb/models/word_search/word_search_sense.dart'; import 'package:jadb/models/word_search/word_search_sense_language_source.dart'; import 'package:jadb/models/word_search/word_search_sources.dart'; import 'package:jadb/models/word_search/word_search_xref_entry.dart'; -import 'package:jadb/util/sqlite_utils.dart'; -import 'package:jadb/util/text_filtering.dart'; -import 'package:sqflite_common/sqlite_api.dart'; -// TODO: Support globs - -// TODO: Support tags - -// TODO: Prefer original kana type when sorting results - -// TODO: Support mixing kana and romaji - -enum SearchMode { - Auto, - English, - Kanji, - MixedKanji, - Kana, - MixedKana, -} - -SearchMode _determineSearchMode(String word) { - final bool containsKanji = kanjiRegex.hasMatch(word); - final bool containsAscii = RegExp(r'[A-Za-z]').hasMatch(word); - - if (containsKanji && containsAscii) { - return SearchMode.MixedKanji; - } else if (containsKanji) { - return SearchMode.Kanji; - } else if (containsAscii) { - return SearchMode.English; - } else if (word.contains(hiraganaRegex) || word.contains(katakanaRegex)) { - return SearchMode.Kana; - } else { - return SearchMode.MixedKana; - } -} - -Future> _fetchEntryIds(DatabaseExecutor connection, String word, - SearchMode searchMode, int pageSize, int? offset) async { - assert( - searchMode != SearchMode.Auto, - 'Search mode should not be auto when fetching entry IDs', - ); - assert( - word.isNotEmpty, - 'Word should not be empty when fetching entry IDs', - ); - - late final List entryIds; - if (searchMode == SearchMode.Kanji) { - entryIds = (await connection.query( - 'JMdict_EntryByKanji', - where: 'kanji LIKE ?', - whereArgs: ['%$word%'], - limit: pageSize, - offset: offset, - )) - .map((row) => row['entryId'] as int) - .toList(); - } else if (searchMode == SearchMode.Kana) { - entryIds = (await connection.query( - 'JMdict_EntryByKana', - where: 'kana LIKE ?', - whereArgs: ['%$word%'], - limit: pageSize, - offset: offset, - )) - .map((row) => row['entryId'] as int) - .toList(); - } else { - entryIds = (await connection.query( - 'JMdict_EntryByEnglish', - where: 'english LIKE ?', - whereArgs: ['%$word%'], - limit: pageSize, - offset: offset, - )) - .map((row) => row['entryId'] as int) - .toList(); - } - - return entryIds; -} - -Future?> searchWordWithDbConnection( - DatabaseExecutor connection, - String word, { - SearchMode searchMode = SearchMode.Auto, - int page = 0, - int pageSize = 10, -}) async { - if (word.isEmpty) { - return null; - } - - if (searchMode == SearchMode.Auto) { - searchMode = _determineSearchMode(word); - } - - final offset = page * pageSize; - - final List entryIds = await _fetchEntryIds( - connection, - word, - searchMode, - pageSize, - offset, - ); - - if (entryIds.isEmpty) { - return []; - } - - late final List> senses; - final Future>> senses_query = connection.query( - 'JMdict_Sense', - where: 'entryId IN (${entryIds.join(',')})', - ); - - late final List> readingElements; - final Future>> readingElements_query = - connection.query( - 'JMdict_ReadingElement', - where: 'entryId IN (${entryIds.join(',')})', - ); - - late final List> kanjiElements; - final Future>> kanjiElements_query = - connection.query( - 'JMdict_KanjiElement', - where: 'entryId IN (${entryIds.join(',')})', - ); - - late final List> jlptTags; - final Future>> jlptTags_query = connection.query( - 'JMdict_JLPTTag', - where: 'entryId IN (${entryIds.join(',')})', - ); - - late final List> commonEntries; - final Future>> commonEntries_query = - connection.query( - 'JMdict_EntryCommon', - where: 'entryId IN (${entryIds.join(',')})', - ); - - await Future.wait([ - senses_query.then((value) => senses = value), - readingElements_query.then((value) => readingElements = value), - kanjiElements_query.then((value) => kanjiElements = value), - jlptTags_query.then((value) => jlptTags = value), - commonEntries_query.then((value) => commonEntries = value), - ]); - - // Sense queries - - final senseIds = senses.map((sense) => sense['senseId'] as int).toList(); - - late final List> senseAntonyms; - final Future>> senseAntonyms_query = - connection.rawQuery(""" - SELECT - JMdict_SenseAntonym.senseId, - JMdict_SenseAntonym.ambiguous, - JMdict_SenseAntonym.xrefEntryId, - JMdict_BaseAndFurigana.base, - JMdict_BaseAndFurigana.furigana - FROM JMdict_SenseAntonym - JOIN "JMdict_BaseAndFurigana" - ON JMdict_SenseAntonym.xrefEntryId = JMdict_BaseAndFurigana.entryId - WHERE - senseId IN (${senseIds.join(',')}) - AND COALESCE("JMdict_BaseAndFurigana"."kanjiOrderNum", 1) - + "JMdict_BaseAndFurigana"."readingOrderNum" - = 2 - ORDER BY - JMdict_SenseAntonym.senseId, - JMdict_SenseAntonym.xrefEntryId - """); - - late final List> senseDialects; - final Future>> senseDialects_query = - connection.query( - 'JMdict_SenseDialect', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseFields; - final Future>> senseFields_query = connection.query( - 'JMdict_SenseField', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseGlossaries; - final Future>> senseGlossaries_query = - connection.query( - 'JMdict_SenseGlossary', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseInfos; - final Future>> senseInfos_query = connection.query( - 'JMdict_SenseInfo', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseLanguageSources; - final Future>> senseLanguageSources_query = - connection.query( - 'JMdict_SenseLanguageSource', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseMiscs; - final Future>> senseMiscs_query = connection.query( - 'JMdict_SenseMisc', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> sensePOSs; - final Future>> sensePOSs_query = connection.query( - 'JMdict_SensePOS', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseRestrictedToKanjis; - final Future>> senseRestrictedToKanjis_query = - connection.query( - 'JMdict_SenseRestrictedToKanji', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseRestrictedToReadings; - final Future>> senseRestrictedToReadings_query = - connection.query( - 'JMdict_SenseRestrictedToReading', - where: 'senseId IN (${senseIds.join(',')})', - ); - - late final List> senseSeeAlsos; - final Future>> senseSeeAlsos_query = - connection.rawQuery(""" - SELECT - JMdict_SenseSeeAlso.senseId, - JMdict_SenseSeeAlso.ambiguous, - JMdict_SenseSeeAlso.xrefEntryId, - JMdict_BaseAndFurigana.base, - JMdict_BaseAndFurigana.furigana - FROM JMdict_SenseSeeAlso - JOIN "JMdict_BaseAndFurigana" - ON JMdict_SenseSeeAlso.xrefEntryId = JMdict_BaseAndFurigana.entryId - WHERE - senseId IN (${senseIds.join(',')}) - AND COALESCE("JMdict_BaseAndFurigana"."kanjiOrderNum", 1) - + "JMdict_BaseAndFurigana"."readingOrderNum" - = 2 - ORDER BY - JMdict_SenseSeeAlso.senseId, - JMdict_SenseSeeAlso.xrefEntryId - """); - - late final List> exampleSentences; - final Future>> exampleSentences_query = - connection.query( - 'JMdict_ExampleSentence', - where: 'senseId IN (${senseIds.join(',')})', - ); - - // Reading queries - - final readingIds = readingElements - .map((element) => ( - element['entryId'] as int, - escapeStringValue(element['reading'] as String) - )) - .toList(); - - late final List> readingElementInfos; - final Future>> readingElementInfos_query = - connection.query( - 'JMdict_ReadingElementInfo', - where: '(entryId, reading) IN (${readingIds.join(',')})', - ); - - late final List> readingElementRestrictions; - final Future>> readingElementRestrictions_query = - connection.query( - 'JMdict_ReadingElementRestriction', - where: '(entryId, reading) IN (${readingIds.join(',')})', - ); - - // Kanji queries - - final kanjiIds = kanjiElements - .map((element) => ( - element['entryId'] as int, - escapeStringValue(element['reading'] as String) - )) - .toList(); - - late final List> kanjiElementInfos; - final Future>> kanjiElementInfos_query = - connection.query( - 'JMdict_KanjiElementInfo', - where: '(entryId, reading) IN (${kanjiIds.join(',')})', - ); - - await Future.wait([ - senseAntonyms_query.then((value) => senseAntonyms = value), - senseDialects_query.then((value) => senseDialects = value), - senseFields_query.then((value) => senseFields = value), - senseGlossaries_query.then((value) => senseGlossaries = value), - senseInfos_query.then((value) => senseInfos = value), - senseLanguageSources_query.then((value) => senseLanguageSources = value), - senseMiscs_query.then((value) => senseMiscs = value), - sensePOSs_query.then((value) => sensePOSs = value), - senseRestrictedToKanjis_query - .then((value) => senseRestrictedToKanjis = value), - senseRestrictedToReadings_query - .then((value) => senseRestrictedToReadings = value), - senseSeeAlsos_query.then((value) => senseSeeAlsos = value), - exampleSentences_query.then((value) => exampleSentences = value), - readingElementInfos_query.then((value) => readingElementInfos = value), - readingElementRestrictions_query - .then((value) => readingElementRestrictions = value), - kanjiElementInfos_query.then((value) => kanjiElementInfos = value), - ]); - - final result = _regroupWordSearchResults( - entryIds: entryIds, - readingElements: readingElements, - kanjiElements: kanjiElements, - jlptTags: jlptTags, - commonEntries: commonEntries, - senses: senses, - senseAntonyms: senseAntonyms, - senseDialects: senseDialects, - senseFields: senseFields, - senseGlossaries: senseGlossaries, - senseInfos: senseInfos, - senseLanguageSources: senseLanguageSources, - senseMiscs: senseMiscs, - sensePOSs: sensePOSs, - senseRestrictedToKanjis: senseRestrictedToKanjis, - senseRestrictedToReadings: senseRestrictedToReadings, - senseSeeAlsos: senseSeeAlsos, - exampleSentences: exampleSentences, - readingElementInfos: readingElementInfos, - readingElementRestrictions: readingElementRestrictions, - kanjiElementInfos: kanjiElementInfos, - ); - - return result; -} - -List _regroupWordSearchResults({ +List regroupWordSearchResults({ required List entryIds, required List> readingElements, required List> kanjiElements, diff --git a/lib/search/word_search/word_search.dart b/lib/search/word_search/word_search.dart new file mode 100644 index 0000000..2bbb16c --- /dev/null +++ b/lib/search/word_search/word_search.dart @@ -0,0 +1,78 @@ +// TODO: Support globs + +// TODO: Support tags + +// TODO: Prefer original kana type when sorting results + +// TODO: Support mixing kana and romaji +// +import 'package:jadb/models/word_search/word_search_result.dart'; +import 'package:jadb/search/word_search/data_query.dart'; +import 'package:jadb/search/word_search/entry_id_query.dart'; +import 'package:jadb/search/word_search/regrouping.dart'; +import 'package:sqflite_common/sqlite_api.dart'; + +enum SearchMode { + Auto, + English, + Kanji, + MixedKanji, + Kana, + MixedKana, +} + +Future?> searchWordWithDbConnection( + DatabaseExecutor connection, + String word, { + SearchMode searchMode = SearchMode.Auto, + int page = 0, + int pageSize = 10, +}) async { + if (word.isEmpty) { + return null; + } + + final offset = page * pageSize; + final List entryIds = await fetchEntryIds( + connection, + word, + searchMode, + pageSize, + offset, + ); + + if (entryIds.isEmpty) { + return []; + } + + final LinearWordQueryData linearWordQueryData = await fetchLinearWordQueryData( + connection, + entryIds, + ); + + final result = regroupWordSearchResults( + entryIds: entryIds, + readingElements: linearWordQueryData.readingElements, + kanjiElements: linearWordQueryData.kanjiElements, + jlptTags: linearWordQueryData.jlptTags, + commonEntries: linearWordQueryData.commonEntries, + senses: linearWordQueryData.senses, + senseAntonyms: linearWordQueryData.senseAntonyms, + senseDialects: linearWordQueryData.senseDialects, + senseFields: linearWordQueryData.senseFields, + senseGlossaries: linearWordQueryData.senseGlossaries, + senseInfos: linearWordQueryData.senseInfos, + senseLanguageSources: linearWordQueryData.senseLanguageSources, + senseMiscs: linearWordQueryData.senseMiscs, + sensePOSs: linearWordQueryData.sensePOSs, + senseRestrictedToKanjis: linearWordQueryData.senseRestrictedToKanjis, + senseRestrictedToReadings: linearWordQueryData.senseRestrictedToReadings, + senseSeeAlsos: linearWordQueryData.senseSeeAlsos, + exampleSentences: linearWordQueryData.exampleSentences, + readingElementInfos: linearWordQueryData.readingElementInfos, + readingElementRestrictions: linearWordQueryData.readingElementRestrictions, + kanjiElementInfos: linearWordQueryData.kanjiElementInfos, + ); + + return result; +}