Compare commits
12 Commits
kanji-read
...
mugiten-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
4ee21d98e2
|
|||
|
7247af19cb
|
|||
|
ac7deae608
|
|||
|
7978b74f8d
|
|||
|
50870f64a0
|
|||
|
62d77749e6
|
|||
|
80b3610a72
|
|||
|
54705c3c10
|
|||
|
c7134f0d06
|
|||
|
aac9bf69f6
|
|||
|
189d4a95cf
|
|||
|
c32775ce7a
|
12
flake.lock
generated
12
flake.lock
generated
@@ -3,7 +3,7 @@
|
||||
"jmdict-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-84P7r/fFlBnawy6yChrD9WMHmOWcEGWUmoK70N4rdGQ=",
|
||||
"narHash": "sha256-sLl+OrVBgc4QCOZ2cvWGLZBerHDLuApyQOQyDyLUHtk=",
|
||||
"type": "file",
|
||||
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e.gz"
|
||||
},
|
||||
@@ -15,7 +15,7 @@
|
||||
"jmdict-with-examples-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-PM0sv7VcsCya2Ek02CI7hVwB3Jawn6bICSI+dsJK0yo=",
|
||||
"narHash": "sha256-FQvkYXwgmCJ+ChVkoFzamlG8kyczHAgsJ3zJ6OvRLZc=",
|
||||
"type": "file",
|
||||
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e_examp.gz"
|
||||
},
|
||||
@@ -27,7 +27,7 @@
|
||||
"kanjidic2-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-Lc0wUPpuDKuMDv2t87//w3z20RX8SMJI2iIRtUJ8fn0=",
|
||||
"narHash": "sha256-vyMpRnN9O3vCpvfVDACKdTlapBVx6yXg0X2tgXF2t+U=",
|
||||
"type": "file",
|
||||
"url": "https://www.edrdg.org/kanjidic/kanjidic2.xml.gz"
|
||||
},
|
||||
@@ -38,11 +38,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1746904237,
|
||||
"narHash": "sha256-3e+AVBczosP5dCLQmMoMEogM57gmZ2qrVSrmq9aResQ=",
|
||||
"lastModified": 1751792365,
|
||||
"narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d89fc19e405cb2d55ce7cc114356846a0ee5e956",
|
||||
"rev": "1fd8bada0b6117e6c7eb54aad5813023eed37ccb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
16
flake.nix
16
flake.nix
@@ -104,10 +104,24 @@
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
|
||||
src = lib.cleanSource ./.;
|
||||
src = builtins.filterSource (path: type: let
|
||||
baseName = baseNameOf (toString path);
|
||||
in !(lib.any (b: b) [
|
||||
(!(lib.cleanSourceFilter path type))
|
||||
(baseName == ".github" && type == "directory")
|
||||
(baseName == "nix" && type == "directory")
|
||||
(baseName == ".envrc" && type == "regular")
|
||||
(baseName == "flake.lock" && type == "regular")
|
||||
(baseName == "flake.nix" && type == "regular")
|
||||
])) ./.;
|
||||
|
||||
in forAllSystems (system: pkgs: {
|
||||
default = self.packages.${system}.database;
|
||||
|
||||
filteredSource = pkgs.runCommandLocal "filtered-source" { } ''
|
||||
ln -s ${src} $out
|
||||
'';
|
||||
|
||||
jmdict = pkgs.callPackage ./nix/jmdict.nix {
|
||||
inherit jmdict-src jmdict-with-examples-src edrdgMetadata;
|
||||
};
|
||||
|
||||
@@ -72,20 +72,25 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
||||
print(' [JMdict] Batch 1 - Kanji and readings');
|
||||
Batch b = db.batch();
|
||||
|
||||
int elementId = 0;
|
||||
for (final e in entries) {
|
||||
b.insert(JMdictTableNames.entry, e.sqlValue);
|
||||
|
||||
for (final k in e.kanji) {
|
||||
elementId++;
|
||||
b.insert(
|
||||
JMdictTableNames.kanjiElement,
|
||||
k.sqlValue..addAll({'entryId': e.entryId}),
|
||||
k.sqlValue..addAll({
|
||||
'entryId': e.entryId,
|
||||
'elementId': elementId,
|
||||
}),
|
||||
);
|
||||
|
||||
for (final i in k.info) {
|
||||
b.insert(
|
||||
JMdictTableNames.kanjiInfo,
|
||||
{
|
||||
'entryId': e.entryId,
|
||||
'reading': k.reading,
|
||||
'elementId': elementId,
|
||||
'info': i,
|
||||
},
|
||||
);
|
||||
@@ -93,17 +98,20 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
||||
}
|
||||
|
||||
for (final r in e.readings) {
|
||||
elementId++;
|
||||
b.insert(
|
||||
JMdictTableNames.readingElement,
|
||||
r.sqlValue..addAll({'entryId': e.entryId}),
|
||||
r.sqlValue..addAll({
|
||||
'entryId': e.entryId,
|
||||
'elementId': elementId,
|
||||
}),
|
||||
);
|
||||
|
||||
for (final i in r.info) {
|
||||
b.insert(
|
||||
JMdictTableNames.readingInfo,
|
||||
{
|
||||
'entryId': e.entryId,
|
||||
'reading': r.reading,
|
||||
'elementId': elementId,
|
||||
'info': i,
|
||||
},
|
||||
);
|
||||
@@ -112,8 +120,7 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
||||
b.insert(
|
||||
JMdictTableNames.readingRestriction,
|
||||
{
|
||||
'entryId': e.entryId,
|
||||
'reading': r.reading,
|
||||
'elementId': elementId,
|
||||
'restriction': res,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:jadb/_data_ingestion/kanjidic/objects.dart';
|
||||
import 'package:jadb/util/romaji_transliteration.dart';
|
||||
import 'package:xml/xml.dart';
|
||||
|
||||
List<Character> parseKANJIDICData(XmlElement root) {
|
||||
@@ -134,7 +135,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
||||
.map(
|
||||
(e) => Onyomi(
|
||||
kanji: kanji,
|
||||
yomi: e.innerText,
|
||||
yomi: transliterateKatakanaToHiragana(e.innerText),
|
||||
isJouyou: e.getAttribute('r_status') == 'jy',
|
||||
type: e.getAttribute('on_type')),
|
||||
)
|
||||
|
||||
@@ -35,12 +35,19 @@ class CreateDb extends Command {
|
||||
readWrite: true,
|
||||
);
|
||||
|
||||
bool failed = false;
|
||||
await seedData(db).then((_) {
|
||||
print("Database created successfully");
|
||||
}).catchError((error) {
|
||||
print("Error creating database: $error");
|
||||
failed = true;
|
||||
}).whenComplete(() {
|
||||
db.close();
|
||||
});
|
||||
if (failed) {
|
||||
exit(1);
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,11 @@ import 'package:args/command_runner.dart';
|
||||
class QueryKanji extends Command {
|
||||
final name = "query-kanji";
|
||||
final description = "Query the database for kanji data";
|
||||
final invocation = "jadb query-kanji [options] <kanji>";
|
||||
|
||||
QueryKanji() {
|
||||
addLibsqliteArg(argParser);
|
||||
addJadbArg(argParser);
|
||||
argParser.addOption(
|
||||
'kanji',
|
||||
abbr: 'k',
|
||||
help: 'The kanji to search for.',
|
||||
valueHelp: 'KANJI',
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> run() async {
|
||||
@@ -34,10 +29,17 @@ class QueryKanji extends Command {
|
||||
libsqlitePath: argResults!.option('libsqlite')!,
|
||||
);
|
||||
|
||||
if (argResults!.rest.length != 1) {
|
||||
print('You need to provide exactly one kanji character to search for.');
|
||||
print('');
|
||||
printUsage();
|
||||
exit(64);
|
||||
}
|
||||
|
||||
final String kanji = argResults!.rest.first.trim();
|
||||
|
||||
final time = Stopwatch()..start();
|
||||
final result = await JaDBConnection(db).jadbSearchKanji(
|
||||
argResults!.option('kanji') ?? '漢',
|
||||
);
|
||||
final result = await JaDBConnection(db).jadbSearchKanji(kanji);
|
||||
time.stop();
|
||||
|
||||
if (result == null) {
|
||||
|
||||
@@ -5,26 +5,24 @@ import 'package:jadb/cli/args.dart';
|
||||
import 'package:jadb/search.dart';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:sqflite_common/sqflite.dart';
|
||||
|
||||
class QueryWord extends Command {
|
||||
final name = "query-word";
|
||||
final description = "Query the database for word data";
|
||||
final invocation = "jadb query-word [options] (<word> | <ID>)";
|
||||
|
||||
QueryWord() {
|
||||
addLibsqliteArg(argParser);
|
||||
addJadbArg(argParser);
|
||||
argParser.addOption(
|
||||
'word',
|
||||
abbr: 'w',
|
||||
help: 'The word to search for.',
|
||||
valueHelp: 'WORD',
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> run() async {
|
||||
if (argResults!.option('libsqlite') == null ||
|
||||
argResults!.option('jadb') == null) {
|
||||
print(argParser.usage);
|
||||
print("You need to provide both libsqlite and jadb paths.");
|
||||
print('');
|
||||
printUsage();
|
||||
exit(64);
|
||||
}
|
||||
|
||||
@@ -33,8 +31,38 @@ class QueryWord extends Command {
|
||||
libsqlitePath: argResults!.option('libsqlite')!,
|
||||
);
|
||||
|
||||
final String searchWord = argResults!.option('word') ?? 'かな';
|
||||
if (argResults!.rest.isEmpty) {
|
||||
print('You need to provide a word or ID to search for.');
|
||||
print('');
|
||||
printUsage();
|
||||
exit(64);
|
||||
}
|
||||
|
||||
final String searchWord = argResults!.rest.join(" ");
|
||||
final int? maybeId = int.tryParse(searchWord);
|
||||
|
||||
if (maybeId != null && maybeId >= 1000000) {
|
||||
await _searchId(db, maybeId);
|
||||
} else {
|
||||
await _searchWord(db, searchWord);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _searchId(DatabaseExecutor db, int id) async {
|
||||
final time = Stopwatch()..start();
|
||||
final result = await JaDBConnection(db).jadbGetWordById(id);
|
||||
time.stop();
|
||||
|
||||
if (result == null) {
|
||||
print("Invalid ID");
|
||||
} else {
|
||||
print(result.toString());
|
||||
}
|
||||
|
||||
print("Query took ${time.elapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
Future<void> _searchWord(DatabaseExecutor db, String searchWord) async {
|
||||
final time = Stopwatch()..start();
|
||||
final count = await JaDBConnection(db).jadbSearchWordCount(searchWord);
|
||||
time.stop();
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:jadb/table_names/kanjidic.dart';
|
||||
import 'package:jadb/table_names/radkfile.dart';
|
||||
import 'package:jadb/models/kanji_search/kanji_search_radical.dart';
|
||||
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
|
||||
import 'package:jadb/util/romaji_transliteration.dart';
|
||||
import 'package:sqflite_common/sqflite.dart';
|
||||
|
||||
Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
||||
@@ -201,7 +202,10 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
||||
meanings: meanings.map((item) => item['meaning'] as String).toList(),
|
||||
kunyomi: kunyomis.map((item) => item['yomi'] as String).toList(),
|
||||
parts: parts.map((item) => item['radical'] as String).toList(),
|
||||
onyomi: onyomis.map((item) => item['yomi'] as String).toList(),
|
||||
onyomi: onyomis
|
||||
.map((item) => item['yomi'] as String)
|
||||
.map(transliterateHiraganaToKatakana)
|
||||
.toList(),
|
||||
radical: radical,
|
||||
codepoints: {
|
||||
for (final codepoint in codepoints)
|
||||
|
||||
@@ -230,40 +230,37 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
|
||||
// Reading queries
|
||||
|
||||
final readingIds = readingElements
|
||||
.map((element) => (
|
||||
element['entryId'] as int,
|
||||
escapeStringValue(element['reading'] as String)
|
||||
))
|
||||
.map((element) => element['elementId'] as int)
|
||||
.toList();
|
||||
|
||||
late final List<Map<String, Object?>> readingElementInfos;
|
||||
final Future<List<Map<String, Object?>>> readingElementInfos_query =
|
||||
connection.query(
|
||||
JMdictTableNames.readingInfo,
|
||||
where: '(entryId, reading) IN (${readingIds.join(',')})',
|
||||
where: '(elementId) IN (${List.filled(readingIds.length, '?').join(',')})',
|
||||
whereArgs: readingIds,
|
||||
);
|
||||
|
||||
late final List<Map<String, Object?>> readingElementRestrictions;
|
||||
final Future<List<Map<String, Object?>>> readingElementRestrictions_query =
|
||||
connection.query(
|
||||
JMdictTableNames.readingRestriction,
|
||||
where: '(entryId, reading) IN (${readingIds.join(',')})',
|
||||
where: '(elementId) IN (${List.filled(readingIds.length, '?').join(',')})',
|
||||
whereArgs: readingIds,
|
||||
);
|
||||
|
||||
// Kanji queries
|
||||
|
||||
final kanjiIds = kanjiElements
|
||||
.map((element) => (
|
||||
element['entryId'] as int,
|
||||
escapeStringValue(element['reading'] as String)
|
||||
))
|
||||
.map((element) => element['elementId'] as int)
|
||||
.toList();
|
||||
|
||||
late final List<Map<String, Object?>> kanjiElementInfos;
|
||||
final Future<List<Map<String, Object?>>> kanjiElementInfos_query =
|
||||
connection.query(
|
||||
JMdictTableNames.kanjiInfo,
|
||||
where: '(entryId, reading) IN (${kanjiIds.join(',')})',
|
||||
where: '(elementId) IN (${List.filled(kanjiIds.length, '?').join(',')})',
|
||||
whereArgs: kanjiIds,
|
||||
);
|
||||
|
||||
await Future.wait([
|
||||
|
||||
@@ -51,18 +51,16 @@ String _filterFTSSensitiveCharacters(String word) {
|
||||
WITH
|
||||
fts_results AS (
|
||||
SELECT DISTINCT
|
||||
"${tableName}FTS"."entryId",
|
||||
"${tableName}"."entryId",
|
||||
100
|
||||
+ (("${tableName}FTS"."reading" = ?) * 50)
|
||||
+ (("${tableName}FTS"."reading" = ?) * 10000)
|
||||
+ "JMdict_EntryScore"."score"
|
||||
AS "score"
|
||||
FROM "${tableName}FTS"
|
||||
JOIN "${tableName}" USING ("entryId", "reading")
|
||||
JOIN "JMdict_EntryScore" USING ("entryId", "reading")
|
||||
JOIN "${tableName}" USING ("elementId")
|
||||
JOIN "JMdict_EntryScore" USING ("elementId")
|
||||
WHERE "${tableName}FTS"."reading" MATCH ? || '*'
|
||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'kanji' : 'reading'}'
|
||||
ORDER BY
|
||||
"JMdict_EntryScore"."score" DESC
|
||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
|
||||
${!countOnly ? 'LIMIT ?' : ''}
|
||||
),
|
||||
non_fts_results AS (
|
||||
@@ -72,22 +70,23 @@ String _filterFTSSensitiveCharacters(String word) {
|
||||
+ "JMdict_EntryScore"."score"
|
||||
AS "score"
|
||||
FROM "${tableName}"
|
||||
JOIN "JMdict_EntryScore" USING ("entryId", "reading")
|
||||
JOIN "JMdict_EntryScore" USING ("elementId")
|
||||
WHERE "reading" LIKE '%' || ? || '%'
|
||||
AND "entryId" NOT IN (SELECT "entryId" FROM "fts_results")
|
||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'kanji' : 'reading'}'
|
||||
ORDER BY
|
||||
"JMdict_EntryScore"."score" DESC,
|
||||
"${tableName}"."entryId" ASC
|
||||
AND "${tableName}"."entryId" NOT IN (SELECT "entryId" FROM "fts_results")
|
||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
|
||||
${!countOnly ? 'LIMIT ?' : ''}
|
||||
)
|
||||
|
||||
${countOnly ? 'SELECT COUNT("entryId") AS count' : 'SELECT "entryId", "score"'}
|
||||
${countOnly ? 'SELECT COUNT("entryId") AS count' : 'SELECT "entryId", MAX("score") AS "score"'}
|
||||
FROM (
|
||||
SELECT * FROM fts_results
|
||||
UNION ALL
|
||||
UNION
|
||||
SELECT * FROM non_fts_results
|
||||
)
|
||||
GROUP BY "entryId"
|
||||
ORDER BY
|
||||
"score" DESC,
|
||||
"entryId" ASC
|
||||
'''
|
||||
.trim(),
|
||||
[
|
||||
|
||||
@@ -182,16 +182,35 @@ GroupedWordResult _regroup_words({
|
||||
'No readings found for entryId: $entryId',
|
||||
);
|
||||
|
||||
final Map<int, String> readingElementIdsToReading = {
|
||||
for (final element in readingElements_)
|
||||
element['elementId'] as int: element['reading'] as String,
|
||||
};
|
||||
|
||||
final Map<int, String> kanjiElementIdsToReading = {
|
||||
for (final element in kanjiElements_)
|
||||
element['elementId'] as int: element['reading'] as String,
|
||||
};
|
||||
|
||||
final readingElementInfos_ = readingElementInfos
|
||||
.where((element) => element['entryId'] == entryId)
|
||||
.toList();
|
||||
|
||||
final kanjiElementInfos_ = kanjiElementInfos
|
||||
.where((element) => element['entryId'] == entryId)
|
||||
.toList();
|
||||
|
||||
return GroupedWordResult(
|
||||
rubys: rubys,
|
||||
readingInfos: {
|
||||
for (final rei in readingElementInfos)
|
||||
rei['reading'] as String:
|
||||
for (final rei in readingElementInfos_)
|
||||
readingElementIdsToReading[rei['elementId'] as int]!:
|
||||
JMdictReadingInfo.fromId(rei['info'] as String),
|
||||
},
|
||||
kanjiInfos: {
|
||||
for (final kei in kanjiElementInfos)
|
||||
kei['reading'] as String: JMdictKanjiInfo.fromId(kei['info'] as String),
|
||||
for (final kei in kanjiElementInfos_)
|
||||
kanjiElementIdsToReading[kei['elementId'] as int]!:
|
||||
JMdictKanjiInfo.fromId(kei['info'] as String),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ Future<List<WordSearchResult>?> searchWordWithDbConnection(
|
||||
);
|
||||
|
||||
if (entryIds.isEmpty) {
|
||||
// TODO: try conjugation search
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ CREATE TABLE "JMdict_Entry" (
|
||||
-- KanjiElement
|
||||
|
||||
CREATE TABLE "JMdict_KanjiElement" (
|
||||
"elementId" INTEGER PRIMARY KEY,
|
||||
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||
"orderNum" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
@@ -47,7 +48,7 @@ CREATE TABLE "JMdict_KanjiElement" (
|
||||
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
||||
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
||||
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
||||
PRIMARY KEY ("entryId", "reading"),
|
||||
UNIQUE("entryId", "reading"),
|
||||
UNIQUE("entryId", "orderNum")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
@@ -55,17 +56,15 @@ CREATE INDEX "JMdict_KanjiElement_byEntryId_byOrderNum" ON "JMdict_KanjiElement"
|
||||
CREATE INDEX "JMdict_KanjiElement_byReading" ON "JMdict_KanjiElement"("reading");
|
||||
|
||||
CREATE TABLE "JMdict_KanjiElementInfo" (
|
||||
"entryId" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
"elementId" INTEGER NOT NULL REFERENCES "JMdict_KanjiElement"("elementId"),
|
||||
"info" TEXT NOT NULL REFERENCES "JMdict_InfoKanji"("id"),
|
||||
FOREIGN KEY ("entryId", "reading")
|
||||
REFERENCES "JMdict_KanjiElement"("entryId", "reading"),
|
||||
PRIMARY KEY ("entryId", "reading", "info")
|
||||
PRIMARY KEY ("elementId", "info")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
-- ReadingElement
|
||||
|
||||
CREATE TABLE "JMdict_ReadingElement" (
|
||||
"elementId" INTEGER PRIMARY KEY,
|
||||
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||
"orderNum" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
@@ -75,7 +74,7 @@ CREATE TABLE "JMdict_ReadingElement" (
|
||||
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
||||
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
||||
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
||||
PRIMARY KEY ("entryId", "reading"),
|
||||
UNIQUE("entryId", "reading"),
|
||||
UNIQUE("entryId", "orderNum")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
@@ -83,21 +82,15 @@ CREATE INDEX "JMdict_ReadingElement_byEntryId_byOrderNum" ON "JMdict_ReadingElem
|
||||
CREATE INDEX "JMdict_ReadingElement_byReading" ON "JMdict_ReadingElement"("reading");
|
||||
|
||||
CREATE TABLE "JMdict_ReadingElementRestriction" (
|
||||
"entryId" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
"elementId" INTEGER NOT NULL REFERENCES "JMdict_ReadingElement"("elementId"),
|
||||
"restriction" TEXT NOT NULL,
|
||||
FOREIGN KEY ("entryId", "reading")
|
||||
REFERENCES "JMdict_ReadingElement"("entryId", "reading"),
|
||||
PRIMARY KEY ("entryId", "reading", "restriction")
|
||||
PRIMARY KEY ("elementId", "restriction")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE TABLE "JMdict_ReadingElementInfo" (
|
||||
"entryId" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
"elementId" INTEGER NOT NULL REFERENCES "JMdict_ReadingElement"("elementId"),
|
||||
"info" TEXT NOT NULL REFERENCES "JMdict_InfoReading"("id"),
|
||||
FOREIGN KEY ("entryId", "reading")
|
||||
REFERENCES "JMdict_ReadingElement"("entryId", "reading"),
|
||||
PRIMARY KEY ("entryId", "reading", "info")
|
||||
PRIMARY KEY ("elementId", "info")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
-- Sense
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
CREATE VIRTUAL TABLE "JMdict_KanjiElementFTS" USING FTS5("entryId" UNINDEXED, "reading");
|
||||
CREATE VIRTUAL TABLE "JMdict_KanjiElementFTS" USING FTS5("elementId" UNINDEXED, "reading");
|
||||
|
||||
CREATE TRIGGER "JMdict_KanjiElement_InsertFTS"
|
||||
AFTER INSERT ON "JMdict_KanjiElement"
|
||||
BEGIN
|
||||
INSERT INTO "JMdict_KanjiElementFTS"("entryId", "reading")
|
||||
VALUES (NEW."entryId", NEW."reading");
|
||||
INSERT INTO "JMdict_KanjiElementFTS"("elementId", "reading")
|
||||
VALUES (NEW."elementId", NEW."reading");
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_KanjiElement_UpdateFTS"
|
||||
AFTER UPDATE OF "entryId", "reading"
|
||||
AFTER UPDATE OF "elementId", "reading"
|
||||
ON "JMdict_KanjiElement"
|
||||
BEGIN
|
||||
UPDATE "JMdict_KanjiElementFTS"
|
||||
SET
|
||||
"entryId" = NEW."entryId",
|
||||
"elementId" = NEW."elementId",
|
||||
"reading" = NEW."reading"
|
||||
WHERE "entryId" = OLD."entryId";
|
||||
WHERE "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_KanjiElement_DeleteFTS"
|
||||
AFTER DELETE ON "JMdict_KanjiElement"
|
||||
BEGIN
|
||||
DELETE FROM "JMdict_KanjiElementFTS"
|
||||
WHERE "entryId" = OLD."entryId";
|
||||
WHERE "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
|
||||
|
||||
CREATE VIRTUAL TABLE "JMdict_ReadingElementFTS" USING FTS5("entryId" UNINDEXED, "reading");
|
||||
CREATE VIRTUAL TABLE "JMdict_ReadingElementFTS" USING FTS5("elementId" UNINDEXED, "reading");
|
||||
|
||||
CREATE TRIGGER "JMdict_ReadingElement_InsertFTS"
|
||||
AFTER INSERT ON "JMdict_ReadingElement"
|
||||
BEGIN
|
||||
INSERT INTO "JMdict_ReadingElementFTS"("entryId", "reading")
|
||||
VALUES (NEW."entryId", NEW."reading");
|
||||
INSERT INTO "JMdict_ReadingElementFTS"("elementId", "reading")
|
||||
VALUES (NEW."elementId", NEW."reading");
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_ReadingElement_UpdateFTS"
|
||||
AFTER UPDATE OF "entryId", "reading"
|
||||
AFTER UPDATE OF "elementId", "reading"
|
||||
ON "JMdict_ReadingElement"
|
||||
BEGIN
|
||||
UPDATE "JMdict_ReadingElementFTS"
|
||||
SET
|
||||
"entryId" = NEW."entryId",
|
||||
"elementId" = NEW."elementId",
|
||||
"reading" = NEW."reading"
|
||||
WHERE "entryId" = OLD."entryId";
|
||||
WHERE "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_ReadingElement_DeleteFTS"
|
||||
AFTER DELETE ON "JMdict_ReadingElement"
|
||||
BEGIN
|
||||
DELETE FROM "JMdict_ReadingElementFTS"
|
||||
WHERE "entryId" = OLD."entryId";
|
||||
WHERE "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
CREATE TABLE "JMdict_EntryScore" (
|
||||
"type" TEXT NOT NULL CHECK ("type" IN ('reading', 'kanji')),
|
||||
"entryId" INTEGER NOT NULL,
|
||||
"reading" TEXT NOT NULL,
|
||||
"type" CHAR(1) NOT NULL CHECK ("type" IN ('r', 'k')),
|
||||
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||
"elementId" INTEGER NOT NULL,
|
||||
"score" INTEGER NOT NULL DEFAULT 0,
|
||||
"common" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("type", "entryId", "reading")
|
||||
PRIMARY KEY ("type", "elementId")
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX "JMdict_EntryScore_byEntryId_byReading_byScore" ON "JMdict_EntryScore"("entryId", "reading", "score");
|
||||
CREATE INDEX "JMdict_EntryScore_byElementId_byScore" ON "JMdict_EntryScore"("elementId", "score");
|
||||
CREATE INDEX "JMdict_EntryScore_byScore" ON "JMdict_EntryScore"("score");
|
||||
CREATE INDEX "JMdict_EntryScore_byCommon" ON "JMdict_EntryScore"("common");
|
||||
|
||||
CREATE INDEX "JMdict_EntryScore_byType_byEntryId_byReading_byScore" ON "JMdict_EntryScore"("type", "entryId", "reading", "score");
|
||||
CREATE INDEX "JMdict_EntryScore_byType_byElementId_byScore" ON "JMdict_EntryScore"("type", "elementId", "score");
|
||||
CREATE INDEX "JMdict_EntryScore_byType_byScore" ON "JMdict_EntryScore"("type", "score");
|
||||
CREATE INDEX "JMdict_EntryScore_byType_byCommon" ON "JMdict_EntryScore"("type", "common");
|
||||
|
||||
@@ -20,9 +20,9 @@ CREATE INDEX "JMdict_EntryScore_byType_byCommon" ON "JMdict_EntryScore"("type",
|
||||
|
||||
CREATE VIEW "JMdict_EntryScoreView_Reading" AS
|
||||
SELECT
|
||||
'reading' AS "type",
|
||||
'r' AS "type",
|
||||
"JMdict_ReadingElement"."entryId",
|
||||
"JMdict_ReadingElement"."reading",
|
||||
"JMdict_ReadingElement"."elementId",
|
||||
(
|
||||
"news" IS 1
|
||||
OR "ichi" IS 1
|
||||
@@ -52,9 +52,9 @@ LEFT JOIN "JMdict_JLPTTag" USING ("entryId");
|
||||
|
||||
CREATE VIEW "JMdict_EntryScoreView_Kanji" AS
|
||||
SELECT
|
||||
'kanji' AS "type",
|
||||
'k' AS "type",
|
||||
"JMdict_KanjiElement"."entryId",
|
||||
"JMdict_KanjiElement"."reading",
|
||||
"JMdict_KanjiElement"."elementId",
|
||||
(
|
||||
"news" IS 1
|
||||
OR "ichi" IS 1
|
||||
@@ -98,14 +98,13 @@ BEGIN
|
||||
INSERT INTO "JMdict_EntryScore" (
|
||||
"type",
|
||||
"entryId",
|
||||
"reading",
|
||||
"elementId",
|
||||
"score",
|
||||
"common"
|
||||
)
|
||||
SELECT "type", "entryId", "reading", "score", "common"
|
||||
SELECT "type", "entryId", "elementId", "score", "common"
|
||||
FROM "JMdict_EntryScoreView_Reading"
|
||||
WHERE "entryId" = NEW."entryId"
|
||||
AND "reading" = NEW."reading";
|
||||
WHERE "elementId" = NEW."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_ReadingElement"
|
||||
@@ -117,17 +116,15 @@ BEGIN
|
||||
"score" = "JMdict_EntryScoreView_Reading"."score",
|
||||
"common" = "JMdict_EntryScoreView_Reading"."common"
|
||||
FROM "JMdict_EntryScoreView_Reading"
|
||||
WHERE "entryId" = NEW."entryId"
|
||||
AND "reading" = NEW."reading";
|
||||
WHERE "elementId" = NEW."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_ReadingElement"
|
||||
AFTER DELETE ON "JMdict_ReadingElement"
|
||||
BEGIN
|
||||
DELETE FROM "JMdict_EntryScore"
|
||||
WHERE "type" = 'reading'
|
||||
AND "entryId" = OLD."entryId"
|
||||
AND "reading" = OLD."reading";
|
||||
WHERE "type" = 'r'
|
||||
AND "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
--- JMdict_KanjiElement triggers
|
||||
@@ -138,14 +135,13 @@ BEGIN
|
||||
INSERT INTO "JMdict_EntryScore" (
|
||||
"type",
|
||||
"entryId",
|
||||
"reading",
|
||||
"elementId",
|
||||
"score",
|
||||
"common"
|
||||
)
|
||||
SELECT "type", "entryId", "reading", "score", "common"
|
||||
SELECT "type", "entryId", "elementId", "score", "common"
|
||||
FROM "JMdict_EntryScoreView_Kanji"
|
||||
WHERE "entryId" = NEW."entryId"
|
||||
AND "reading" = NEW."reading";
|
||||
WHERE "elementId" = NEW."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_KanjiElement"
|
||||
@@ -157,17 +153,15 @@ BEGIN
|
||||
"score" = "JMdict_EntryScoreView_Kanji"."score",
|
||||
"common" = "JMdict_EntryScoreView_Kanji"."common"
|
||||
FROM "JMdict_EntryScoreView_Kanji"
|
||||
WHERE "entryId" = NEW."entryId"
|
||||
AND "reading" = NEW."reading";
|
||||
WHERE "elementId" = NEW."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_KanjiElement"
|
||||
AFTER DELETE ON "JMdict_KanjiElement"
|
||||
BEGIN
|
||||
DELETE FROM "JMdict_EntryScore"
|
||||
WHERE "type" = 'kanji'
|
||||
AND "entryId" = OLD."entryId"
|
||||
AND "reading" = OLD."reading";
|
||||
WHERE "type" = 'k'
|
||||
AND "elementId" = OLD."elementId";
|
||||
END;
|
||||
|
||||
--- JMdict_JLPTTag triggers
|
||||
@@ -181,8 +175,8 @@ BEGIN
|
||||
"common" = "JMdict_EntryScoreView"."common"
|
||||
FROM "JMdict_EntryScoreView"
|
||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
||||
AND "JMdict_EntryScore"."entryId" = NEW."entryId"
|
||||
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_JLPTTag"
|
||||
@@ -195,8 +189,8 @@ BEGIN
|
||||
"common" = "JMdict_EntryScoreView"."common"
|
||||
FROM "JMdict_EntryScoreView"
|
||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
||||
AND "JMdict_EntryScore"."entryId" = NEW."entryId"
|
||||
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||
END;
|
||||
|
||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_JLPTTag"
|
||||
@@ -207,7 +201,7 @@ BEGIN
|
||||
"score" = "JMdict_EntryScoreView"."score",
|
||||
"common" = "JMdict_EntryScoreView"."common"
|
||||
FROM "JMdict_EntryScoreView"
|
||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
||||
WHERE "JMdict_EntryScoreView"."entryId" = OLD."entryId"
|
||||
AND "JMdict_EntryScore"."entryId" = OLD."entryId"
|
||||
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||
END;
|
||||
|
||||
@@ -65,7 +65,7 @@ JOIN "JMdict_KanjiElement"
|
||||
ON "JMdict_KanjiElementFTS"."entryId" = "JMdict_KanjiElement"."entryId"
|
||||
AND "JMdict_KanjiElementFTS"."reading" LIKE '%' || "JMdict_KanjiElement"."reading"
|
||||
JOIN "JMdict_EntryScore"
|
||||
ON "JMdict_EntryScore"."type" = 'kanji'
|
||||
ON "JMdict_EntryScore"."type" = 'k'
|
||||
AND "JMdict_KanjiElement"."entryId" = "JMdict_EntryScore"."entryId"
|
||||
AND "JMdict_KanjiElement"."reading" = "JMdict_EntryScore"."reading"
|
||||
WHERE "JMdict_EntryScore"."common" = 1;
|
||||
@@ -77,8 +77,13 @@ SELECT DISTINCT "radical" FROM "RADKFILE";
|
||||
CREATE VIEW "JMdict_CombinedEntryScore"
|
||||
AS
|
||||
SELECT
|
||||
"JMdict_EntryScore"."entryId",
|
||||
CASE
|
||||
WHEN "JMdict_EntryScore"."type" = 'k'
|
||||
THEN (SELECT entryId FROM "JMdict_KanjiElement" WHERE "elementId" = "JMdict_EntryScore"."elementId")
|
||||
WHEN "JMdict_EntryScore"."type" = 'r'
|
||||
THEN (SELECT entryId FROM "JMdict_ReadingElement" WHERE "elementId" = "JMdict_EntryScore"."elementId")
|
||||
END AS "entryId",
|
||||
MAX("JMdict_EntryScore"."score") AS "score",
|
||||
MAX("JMdict_EntryScore"."common") AS "common"
|
||||
FROM "JMdict_EntryScore"
|
||||
GROUP BY "JMdict_EntryScore"."entryId";
|
||||
GROUP BY "entryId";
|
||||
|
||||
@@ -4,12 +4,42 @@ import 'package:test/test.dart';
|
||||
import 'setup_database_connection.dart';
|
||||
|
||||
void main() {
|
||||
test("Search a word", () async {
|
||||
test("Search a word - english - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWord("kana");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Get word search count - english - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWordCount("kana");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Search a word - japanese kana - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWord("かな");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Get word search count - japanese kana - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWordCount("かな");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Search a word - japanese kanji - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWord("仮名");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Get word search count - japanese kanji - auto", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbSearchWordCount("仮名");
|
||||
expect(result, isNotNull);
|
||||
});
|
||||
|
||||
test("Get a word by id", () async {
|
||||
final connection = await setup_database_connection();
|
||||
final result = await connection.jadbGetWordById(1577090);
|
||||
|
||||
Reference in New Issue
Block a user