lib/search/word_search: split
This commit is contained in:
@@ -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';
|
||||
|
||||
|
||||
292
lib/search/word_search/data_query.dart
Normal file
292
lib/search/word_search/data_query.dart
Normal file
@@ -0,0 +1,292 @@
|
||||
import 'package:jadb/util/sqlite_utils.dart';
|
||||
import 'package:sqflite_common/sqflite.dart';
|
||||
|
||||
class LinearWordQueryData {
|
||||
final List<Map<String, Object?>> senses;
|
||||
final List<Map<String, Object?>> readingElements;
|
||||
final List<Map<String, Object?>> kanjiElements;
|
||||
final List<Map<String, Object?>> jlptTags;
|
||||
final List<Map<String, Object?>> commonEntries;
|
||||
final List<Map<String, Object?>> senseAntonyms;
|
||||
final List<Map<String, Object?>> senseDialects;
|
||||
final List<Map<String, Object?>> senseFields;
|
||||
final List<Map<String, Object?>> senseGlossaries;
|
||||
final List<Map<String, Object?>> senseInfos;
|
||||
final List<Map<String, Object?>> senseLanguageSources;
|
||||
final List<Map<String, Object?>> senseMiscs;
|
||||
final List<Map<String, Object?>> sensePOSs;
|
||||
final List<Map<String, Object?>> senseRestrictedToKanjis;
|
||||
final List<Map<String, Object?>> senseRestrictedToReadings;
|
||||
final List<Map<String, Object?>> senseSeeAlsos;
|
||||
final List<Map<String, Object?>> exampleSentences;
|
||||
final List<Map<String, Object?>> readingElementInfos;
|
||||
final List<Map<String, Object?>> readingElementRestrictions;
|
||||
final List<Map<String, Object?>> 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<LinearWordQueryData> fetchLinearWordQueryData(
|
||||
DatabaseExecutor connection,
|
||||
List<int> entryIds,
|
||||
) async {
|
||||
|
||||
late final List<Map<String, Object?>> senses;
|
||||
final Future<List<Map<String, Object?>>> senses_query = connection.query(
|
||||
'JMdict_Sense',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> readingElements;
|
||||
final Future<List<Map<String, Object?>>> readingElements_query =
|
||||
connection.query(
|
||||
'JMdict_ReadingElement',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> kanjiElements;
|
||||
final Future<List<Map<String, Object?>>> kanjiElements_query =
|
||||
connection.query(
|
||||
'JMdict_KanjiElement',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> jlptTags;
|
||||
final Future<List<Map<String, Object?>>> jlptTags_query = connection.query(
|
||||
'JMdict_JLPTTag',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> commonEntries;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> senseAntonyms;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> senseDialects;
|
||||
final Future<List<Map<String, Object?>>> senseDialects_query =
|
||||
connection.query(
|
||||
'JMdict_SenseDialect',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseFields;
|
||||
final Future<List<Map<String, Object?>>> senseFields_query = connection.query(
|
||||
'JMdict_SenseField',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseGlossaries;
|
||||
final Future<List<Map<String, Object?>>> senseGlossaries_query =
|
||||
connection.query(
|
||||
'JMdict_SenseGlossary',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseInfos;
|
||||
final Future<List<Map<String, Object?>>> senseInfos_query = connection.query(
|
||||
'JMdict_SenseInfo',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseLanguageSources;
|
||||
final Future<List<Map<String, Object?>>> senseLanguageSources_query =
|
||||
connection.query(
|
||||
'JMdict_SenseLanguageSource',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseMiscs;
|
||||
final Future<List<Map<String, Object?>>> senseMiscs_query = connection.query(
|
||||
'JMdict_SenseMisc',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> sensePOSs;
|
||||
final Future<List<Map<String, Object?>>> sensePOSs_query = connection.query(
|
||||
'JMdict_SensePOS',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseRestrictedToKanjis;
|
||||
final Future<List<Map<String, Object?>>> senseRestrictedToKanjis_query =
|
||||
connection.query(
|
||||
'JMdict_SenseRestrictedToKanji',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseRestrictedToReadings;
|
||||
final Future<List<Map<String, Object?>>> senseRestrictedToReadings_query =
|
||||
connection.query(
|
||||
'JMdict_SenseRestrictedToReading',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseSeeAlsos;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> exampleSentences;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> readingElementInfos;
|
||||
final Future<List<Map<String, Object?>>> readingElementInfos_query =
|
||||
connection.query(
|
||||
'JMdict_ReadingElementInfo',
|
||||
where: '(entryId, reading) IN (${readingIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> readingElementRestrictions;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> kanjiElementInfos;
|
||||
final Future<List<Map<String, Object?>>> 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,
|
||||
);
|
||||
}
|
||||
72
lib/search/word_search/entry_id_query.dart
Normal file
72
lib/search/word_search/entry_id_query.dart
Normal file
@@ -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<List<int>> 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<int> 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;
|
||||
}
|
||||
@@ -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<List<int>> _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<int> 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<List<WordSearchResult>?> 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<int> entryIds = await _fetchEntryIds(
|
||||
connection,
|
||||
word,
|
||||
searchMode,
|
||||
pageSize,
|
||||
offset,
|
||||
);
|
||||
|
||||
if (entryIds.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
late final List<Map<String, Object?>> senses;
|
||||
final Future<List<Map<String, Object?>>> senses_query = connection.query(
|
||||
'JMdict_Sense',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> readingElements;
|
||||
final Future<List<Map<String, Object?>>> readingElements_query =
|
||||
connection.query(
|
||||
'JMdict_ReadingElement',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> kanjiElements;
|
||||
final Future<List<Map<String, Object?>>> kanjiElements_query =
|
||||
connection.query(
|
||||
'JMdict_KanjiElement',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> jlptTags;
|
||||
final Future<List<Map<String, Object?>>> jlptTags_query = connection.query(
|
||||
'JMdict_JLPTTag',
|
||||
where: 'entryId IN (${entryIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> commonEntries;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> senseAntonyms;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> senseDialects;
|
||||
final Future<List<Map<String, Object?>>> senseDialects_query =
|
||||
connection.query(
|
||||
'JMdict_SenseDialect',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseFields;
|
||||
final Future<List<Map<String, Object?>>> senseFields_query = connection.query(
|
||||
'JMdict_SenseField',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseGlossaries;
|
||||
final Future<List<Map<String, Object?>>> senseGlossaries_query =
|
||||
connection.query(
|
||||
'JMdict_SenseGlossary',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseInfos;
|
||||
final Future<List<Map<String, Object?>>> senseInfos_query = connection.query(
|
||||
'JMdict_SenseInfo',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseLanguageSources;
|
||||
final Future<List<Map<String, Object?>>> senseLanguageSources_query =
|
||||
connection.query(
|
||||
'JMdict_SenseLanguageSource',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseMiscs;
|
||||
final Future<List<Map<String, Object?>>> senseMiscs_query = connection.query(
|
||||
'JMdict_SenseMisc',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> sensePOSs;
|
||||
final Future<List<Map<String, Object?>>> sensePOSs_query = connection.query(
|
||||
'JMdict_SensePOS',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseRestrictedToKanjis;
|
||||
final Future<List<Map<String, Object?>>> senseRestrictedToKanjis_query =
|
||||
connection.query(
|
||||
'JMdict_SenseRestrictedToKanji',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseRestrictedToReadings;
|
||||
final Future<List<Map<String, Object?>>> senseRestrictedToReadings_query =
|
||||
connection.query(
|
||||
'JMdict_SenseRestrictedToReading',
|
||||
where: 'senseId IN (${senseIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> senseSeeAlsos;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> exampleSentences;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> readingElementInfos;
|
||||
final Future<List<Map<String, Object?>>> readingElementInfos_query =
|
||||
connection.query(
|
||||
'JMdict_ReadingElementInfo',
|
||||
where: '(entryId, reading) IN (${readingIds.join(',')})',
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> readingElementRestrictions;
|
||||
final Future<List<Map<String, Object?>>> 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<Map<String, Object?>> kanjiElementInfos;
|
||||
final Future<List<Map<String, Object?>>> 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<WordSearchResult> _regroupWordSearchResults({
|
||||
List<WordSearchResult> regroupWordSearchResults({
|
||||
required List<int> entryIds,
|
||||
required List<Map<String, Object?>> readingElements,
|
||||
required List<Map<String, Object?>> kanjiElements,
|
||||
78
lib/search/word_search/word_search.dart
Normal file
78
lib/search/word_search/word_search.dart
Normal file
@@ -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<List<WordSearchResult>?> 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<int> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user