Compare commits
34 Commits
kanji-read
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
ac0cb14bbe
|
|||
|
49a86f60ea
|
|||
|
9472156feb
|
|||
|
4fbdba604e
|
|||
|
0cdfa2015e
|
|||
|
a9ca9b08a5
|
|||
|
45e8181041
|
|||
|
0d3ebc97f5
|
|||
|
bb68319527
|
|||
|
2803db9c12
|
|||
|
93b76ed660
|
|||
|
29a3a6aafb
|
|||
|
3a2adf0367
|
|||
|
eae6e881a7
|
|||
|
0a3387e77a
|
|||
|
f30465a33c
|
|||
|
d9006a0767
|
|||
|
1e1761ab4d
|
|||
|
37d29fc6ad
|
|||
|
60898fe9a2
|
|||
|
5049157b02
|
|||
|
1868c6fb41
|
|||
|
4ee21d98e2
|
|||
|
7247af19cb
|
|||
|
ac7deae608
|
|||
|
7978b74f8d
|
|||
|
50870f64a0
|
|||
|
62d77749e6
|
|||
|
80b3610a72
|
|||
|
54705c3c10
|
|||
|
c7134f0d06
|
|||
|
aac9bf69f6
|
|||
|
189d4a95cf
|
|||
|
c32775ce7a
|
38
.gitea/workflows/build.yml
Normal file
38
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: "Build database"
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
jobs:
|
||||||
|
evals:
|
||||||
|
runs-on: debian-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Install sudo
|
||||||
|
run: apt-get update && apt-get -y install sudo
|
||||||
|
|
||||||
|
- name: Install nix
|
||||||
|
uses: https://github.com/cachix/install-nix-action@v31
|
||||||
|
|
||||||
|
- name: Configure nix
|
||||||
|
run: echo -e "show-trace = true\nmax-jobs = auto\ntrusted-users = root\nexperimental-features = nix-command flakes\nbuild-users-group =" > /etc/nix/nix.conf
|
||||||
|
|
||||||
|
- name: Update database inputs
|
||||||
|
run: |
|
||||||
|
nix flake update jmdict-src
|
||||||
|
nix flake update jmdict-with-examples-src
|
||||||
|
nix flake update radkfile-src
|
||||||
|
nix flake update kanjidic2-src
|
||||||
|
|
||||||
|
- name: Build database
|
||||||
|
run: nix build .#database -L
|
||||||
|
|
||||||
|
- name: Upload database as artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: jadb-${{ gitea.sha }}.zip
|
||||||
|
path: result/jadb.sqlite
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 15
|
||||||
|
# Already compressed
|
||||||
|
compression: 0
|
||||||
41
analysis_options.yaml
Normal file
41
analysis_options.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include:
|
||||||
|
- package:lints/recommended.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
always_declare_return_types: true
|
||||||
|
annotate_redeclares: true
|
||||||
|
avoid_print: false
|
||||||
|
avoid_setters_without_getters: true
|
||||||
|
avoid_slow_async_io: true
|
||||||
|
directives_ordering: true
|
||||||
|
eol_at_end_of_file: true
|
||||||
|
prefer_const_declarations: true
|
||||||
|
prefer_contains: true
|
||||||
|
prefer_final_fields: true
|
||||||
|
prefer_final_locals: true
|
||||||
|
prefer_single_quotes: true
|
||||||
|
use_key_in_widget_constructors: true
|
||||||
|
use_null_aware_elements: true
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
||||||
@@ -9,7 +9,7 @@ import 'package:jadb/cli/commands/query_word.dart';
|
|||||||
Future<void> main(List<String> args) async {
|
Future<void> main(List<String> args) async {
|
||||||
final runner = CommandRunner(
|
final runner = CommandRunner(
|
||||||
'jadb',
|
'jadb',
|
||||||
"CLI tool to help creating and testing the jadb database",
|
'CLI tool to help creating and testing the jadb database',
|
||||||
);
|
);
|
||||||
|
|
||||||
runner.addCommand(CreateDb());
|
runner.addCommand(CreateDb());
|
||||||
|
|||||||
18
flake.lock
generated
18
flake.lock
generated
@@ -3,7 +3,7 @@
|
|||||||
"jmdict-src": {
|
"jmdict-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"narHash": "sha256-84P7r/fFlBnawy6yChrD9WMHmOWcEGWUmoK70N4rdGQ=",
|
"narHash": "sha256-coRi0AIx02GIrVms4C1GMCjgtdIVRpS7WEpN2UdUX1E=",
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e.gz"
|
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e.gz"
|
||||||
},
|
},
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"jmdict-with-examples-src": {
|
"jmdict-with-examples-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"narHash": "sha256-PM0sv7VcsCya2Ek02CI7hVwB3Jawn6bICSI+dsJK0yo=",
|
"narHash": "sha256-UD9QVy9dtPeExN/yvvR8Mi4r+3PvxlbGJA+oRNIGUGk=",
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e_examp.gz"
|
"url": "http://ftp.edrdg.org/pub/Nihongo/JMdict_e_examp.gz"
|
||||||
},
|
},
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"kanjidic2-src": {
|
"kanjidic2-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"narHash": "sha256-Lc0wUPpuDKuMDv2t87//w3z20RX8SMJI2iIRtUJ8fn0=",
|
"narHash": "sha256-NwQ9SmlwxyXXxSS8cVh1PL17m/LKXdIhyyitTIbB2DI=",
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "https://www.edrdg.org/kanjidic/kanjidic2.xml.gz"
|
"url": "https://www.edrdg.org/kanjidic/kanjidic2.xml.gz"
|
||||||
},
|
},
|
||||||
@@ -38,11 +38,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746904237,
|
"lastModified": 1765779637,
|
||||||
"narHash": "sha256-3e+AVBczosP5dCLQmMoMEogM57gmZ2qrVSrmq9aResQ=",
|
"narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d89fc19e405cb2d55ce7cc114356846a0ee5e956",
|
"rev": "1306659b587dc277866c7b69eb97e5f07864d8c4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -54,13 +54,13 @@
|
|||||||
"radkfile-src": {
|
"radkfile-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"narHash": "sha256-rO2z5GPt3g6osZOlpyWysmIbRV2Gw4AR4XvngVTHNpk=",
|
"narHash": "sha256-DHpMUE2Umje8PbzXUCS6pHZeXQ5+WTxbjSkGU3erDHQ=",
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "http://ftp.usf.edu/pub/ftp.monash.edu.au/pub/nihongo/radkfile.gz"
|
"url": "http://ftp.edrdg.org/pub/Nihongo/radkfile.gz"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"url": "http://ftp.usf.edu/pub/ftp.monash.edu.au/pub/nihongo/radkfile.gz"
|
"url": "http://ftp.edrdg.org/pub/Nihongo/radkfile.gz"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
|
|||||||
18
flake.nix
18
flake.nix
@@ -16,7 +16,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
radkfile-src = {
|
radkfile-src = {
|
||||||
url = "http://ftp.usf.edu/pub/ftp.monash.edu.au/pub/nihongo/radkfile.gz";
|
url = "http://ftp.edrdg.org/pub/Nihongo/radkfile.gz";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,10 +104,24 @@
|
|||||||
platforms = lib.platforms.all;
|
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: {
|
in forAllSystems (system: pkgs: {
|
||||||
default = self.packages.${system}.database;
|
default = self.packages.${system}.database;
|
||||||
|
|
||||||
|
filteredSource = pkgs.runCommandLocal "filtered-source" { } ''
|
||||||
|
ln -s ${src} $out
|
||||||
|
'';
|
||||||
|
|
||||||
jmdict = pkgs.callPackage ./nix/jmdict.nix {
|
jmdict = pkgs.callPackage ./nix/jmdict.nix {
|
||||||
inherit jmdict-src jmdict-with-examples-src edrdgMetadata;
|
inherit jmdict-src jmdict-with-examples-src edrdgMetadata;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ abstract class Element extends SQLWritable {
|
|||||||
this.nf,
|
this.nf,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'reading': reading,
|
'reading': reading,
|
||||||
'news': news,
|
'news': news,
|
||||||
'ichi': ichi,
|
'ichi': ichi,
|
||||||
'spec': spec,
|
'spec': spec,
|
||||||
'gai': gai,
|
'gai': gai,
|
||||||
'nf': nf,
|
'nf': nf,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class KanjiElement extends Element {
|
class KanjiElement extends Element {
|
||||||
@@ -33,26 +34,19 @@ class KanjiElement extends Element {
|
|||||||
KanjiElement({
|
KanjiElement({
|
||||||
this.info = const [],
|
this.info = const [],
|
||||||
required this.orderNum,
|
required this.orderNum,
|
||||||
required String reading,
|
required super.reading,
|
||||||
int? news,
|
super.news,
|
||||||
int? ichi,
|
super.ichi,
|
||||||
int? spec,
|
super.spec,
|
||||||
int? gai,
|
super.gai,
|
||||||
int? nf,
|
super.nf,
|
||||||
}) : super(
|
});
|
||||||
reading: reading,
|
|
||||||
news: news,
|
|
||||||
ichi: ichi,
|
|
||||||
spec: spec,
|
|
||||||
gai: gai,
|
|
||||||
nf: nf,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
...super.sqlValue,
|
...super.sqlValue,
|
||||||
'orderNum': orderNum,
|
'orderNum': orderNum,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReadingElement extends Element {
|
class ReadingElement extends Element {
|
||||||
@@ -66,27 +60,20 @@ class ReadingElement extends Element {
|
|||||||
required this.readingDoesNotMatchKanji,
|
required this.readingDoesNotMatchKanji,
|
||||||
this.info = const [],
|
this.info = const [],
|
||||||
this.restrictions = const [],
|
this.restrictions = const [],
|
||||||
required String reading,
|
required super.reading,
|
||||||
int? news,
|
super.news,
|
||||||
int? ichi,
|
super.ichi,
|
||||||
int? spec,
|
super.spec,
|
||||||
int? gai,
|
super.gai,
|
||||||
int? nf,
|
super.nf,
|
||||||
}) : super(
|
});
|
||||||
reading: reading,
|
|
||||||
news: news,
|
|
||||||
ichi: ichi,
|
|
||||||
spec: spec,
|
|
||||||
gai: gai,
|
|
||||||
nf: nf,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
...super.sqlValue,
|
...super.sqlValue,
|
||||||
'orderNum': orderNum,
|
'orderNum': orderNum,
|
||||||
'readingDoesNotMatchKanji': readingDoesNotMatchKanji,
|
'readingDoesNotMatchKanji': readingDoesNotMatchKanji,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class LanguageSource extends SQLWritable {
|
class LanguageSource extends SQLWritable {
|
||||||
@@ -104,11 +91,11 @@ class LanguageSource extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'language': language,
|
'language': language,
|
||||||
'phrase': phrase,
|
'phrase': phrase,
|
||||||
'fullyDescribesSense': fullyDescribesSense,
|
'fullyDescribesSense': fullyDescribesSense,
|
||||||
'constructedFromSmallerWords': constructedFromSmallerWords,
|
'constructedFromSmallerWords': constructedFromSmallerWords,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Glossary extends SQLWritable {
|
class Glossary extends SQLWritable {
|
||||||
@@ -116,48 +103,41 @@ class Glossary extends SQLWritable {
|
|||||||
final String phrase;
|
final String phrase;
|
||||||
final String? type;
|
final String? type;
|
||||||
|
|
||||||
const Glossary({
|
const Glossary({required this.language, required this.phrase, this.type});
|
||||||
required this.language,
|
|
||||||
required this.phrase,
|
|
||||||
this.type,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'language': language,
|
'language': language,
|
||||||
'phrase': phrase,
|
'phrase': phrase,
|
||||||
'type': type,
|
'type': type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
final kanaRegex =
|
final kanaRegex = RegExp(
|
||||||
RegExp(r'^[\p{Script=Katakana}\p{Script=Hiragana}ー]+$', unicode: true);
|
r'^[\p{Script=Katakana}\p{Script=Hiragana}ー]+$',
|
||||||
|
unicode: true,
|
||||||
|
);
|
||||||
|
|
||||||
class XRefParts {
|
class XRefParts {
|
||||||
final String? kanjiRef;
|
final String? kanjiRef;
|
||||||
final String? readingRef;
|
final String? readingRef;
|
||||||
final int? senseOrderNum;
|
final int? senseOrderNum;
|
||||||
|
|
||||||
const XRefParts({
|
const XRefParts({this.kanjiRef, this.readingRef, this.senseOrderNum})
|
||||||
this.kanjiRef,
|
: assert(kanjiRef != null || readingRef != null);
|
||||||
this.readingRef,
|
|
||||||
this.senseOrderNum,
|
|
||||||
}) : assert(kanjiRef != null || readingRef != null);
|
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {
|
||||||
'kanjiRef': kanjiRef,
|
'kanjiRef': kanjiRef,
|
||||||
'readingRef': readingRef,
|
'readingRef': readingRef,
|
||||||
'senseOrderNum': senseOrderNum,
|
'senseOrderNum': senseOrderNum,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class XRef {
|
class XRef {
|
||||||
final String entryId;
|
final String entryId;
|
||||||
final String reading;
|
final String reading;
|
||||||
|
|
||||||
const XRef({
|
const XRef({required this.entryId, required this.reading});
|
||||||
required this.entryId,
|
|
||||||
required this.reading,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Sense extends SQLWritable {
|
class Sense extends SQLWritable {
|
||||||
@@ -193,9 +173,9 @@ class Sense extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'senseId': senseId,
|
'senseId': senseId,
|
||||||
'orderNum': orderNum,
|
'orderNum': orderNum,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool get isEmpty =>
|
bool get isEmpty =>
|
||||||
antonyms.isEmpty &&
|
antonyms.isEmpty &&
|
||||||
@@ -224,5 +204,6 @@ class Entry extends SQLWritable {
|
|||||||
required this.senses,
|
required this.senses,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
Map<String, Object?> get sqlValue => {'entryId': entryId};
|
Map<String, Object?> get sqlValue => {'entryId': entryId};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,18 +18,20 @@ ResolvedXref resolveXref(
|
|||||||
XRefParts xref,
|
XRefParts xref,
|
||||||
) {
|
) {
|
||||||
List<Entry> candidateEntries = switch ((xref.kanjiRef, xref.readingRef)) {
|
List<Entry> candidateEntries = switch ((xref.kanjiRef, xref.readingRef)) {
|
||||||
(null, null) =>
|
(null, null) => throw Exception(
|
||||||
throw Exception('Xref $xref has no kanji or reading reference'),
|
'Xref $xref has no kanji or reading reference',
|
||||||
(String k, null) => entriesByKanji[k]!.toList(),
|
),
|
||||||
(null, String r) => entriesByReading[r]!.toList(),
|
(final String k, null) => entriesByKanji[k]!.toList(),
|
||||||
(String k, String r) =>
|
(null, final String r) => entriesByReading[r]!.toList(),
|
||||||
|
(final String k, final String r) =>
|
||||||
entriesByKanji[k]!.intersection(entriesByReading[r]!).toList(),
|
entriesByKanji[k]!.intersection(entriesByReading[r]!).toList(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Filter out entries that don't have the number of senses specified in the xref
|
// Filter out entries that don't have the number of senses specified in the xref
|
||||||
if (xref.senseOrderNum != null) {
|
if (xref.senseOrderNum != null) {
|
||||||
candidateEntries
|
candidateEntries.retainWhere(
|
||||||
.retainWhere((entry) => entry.senses.length >= xref.senseOrderNum!);
|
(entry) => entry.senses.length >= xref.senseOrderNum!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the xref has a reading ref but no kanji ref, and there are multiple
|
// If the xref has a reading ref but no kanji ref, and there are multiple
|
||||||
@@ -38,8 +40,9 @@ ResolvedXref resolveXref(
|
|||||||
if (xref.kanjiRef == null &&
|
if (xref.kanjiRef == null &&
|
||||||
xref.readingRef != null &&
|
xref.readingRef != null &&
|
||||||
candidateEntries.length > 1) {
|
candidateEntries.length > 1) {
|
||||||
final candidatesWithEmptyKanji =
|
final candidatesWithEmptyKanji = candidateEntries
|
||||||
candidateEntries.where((entry) => entry.kanji.length == 0).toList();
|
.where((entry) => entry.kanji.isEmpty)
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (candidatesWithEmptyKanji.isNotEmpty) {
|
if (candidatesWithEmptyKanji.isNotEmpty) {
|
||||||
candidateEntries = candidatesWithEmptyKanji;
|
candidateEntries = candidatesWithEmptyKanji;
|
||||||
@@ -50,7 +53,7 @@ ResolvedXref resolveXref(
|
|||||||
// entry in case there are multiple candidates left.
|
// entry in case there are multiple candidates left.
|
||||||
candidateEntries.sortBy<num>((entry) => entry.senses.length);
|
candidateEntries.sortBy<num>((entry) => entry.senses.length);
|
||||||
|
|
||||||
if (candidateEntries.length == 0) {
|
if (candidateEntries.isEmpty) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'SKIPPING: Xref $xref has ${candidateEntries.length} entries, '
|
'SKIPPING: Xref $xref has ${candidateEntries.length} entries, '
|
||||||
'kanjiRef: ${xref.kanjiRef}, readingRef: ${xref.readingRef}, '
|
'kanjiRef: ${xref.kanjiRef}, readingRef: ${xref.readingRef}, '
|
||||||
@@ -72,51 +75,43 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
print(' [JMdict] Batch 1 - Kanji and readings');
|
print(' [JMdict] Batch 1 - Kanji and readings');
|
||||||
Batch b = db.batch();
|
Batch b = db.batch();
|
||||||
|
|
||||||
|
int elementId = 0;
|
||||||
for (final e in entries) {
|
for (final e in entries) {
|
||||||
b.insert(JMdictTableNames.entry, e.sqlValue);
|
b.insert(JMdictTableNames.entry, e.sqlValue);
|
||||||
|
|
||||||
for (final k in e.kanji) {
|
for (final k in e.kanji) {
|
||||||
|
elementId++;
|
||||||
b.insert(
|
b.insert(
|
||||||
JMdictTableNames.kanjiElement,
|
JMdictTableNames.kanjiElement,
|
||||||
k.sqlValue..addAll({'entryId': e.entryId}),
|
k.sqlValue..addAll({'entryId': e.entryId, 'elementId': elementId}),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final i in k.info) {
|
for (final i in k.info) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.kanjiInfo, {
|
||||||
JMdictTableNames.kanjiInfo,
|
'elementId': elementId,
|
||||||
{
|
'info': i,
|
||||||
'entryId': e.entryId,
|
});
|
||||||
'reading': k.reading,
|
|
||||||
'info': i,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final r in e.readings) {
|
for (final r in e.readings) {
|
||||||
|
elementId++;
|
||||||
b.insert(
|
b.insert(
|
||||||
JMdictTableNames.readingElement,
|
JMdictTableNames.readingElement,
|
||||||
r.sqlValue..addAll({'entryId': e.entryId}),
|
r.sqlValue..addAll({'entryId': e.entryId, 'elementId': elementId}),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final i in r.info) {
|
for (final i in r.info) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.readingInfo, {
|
||||||
JMdictTableNames.readingInfo,
|
'elementId': elementId,
|
||||||
{
|
'info': i,
|
||||||
'entryId': e.entryId,
|
});
|
||||||
'reading': r.reading,
|
|
||||||
'info': i,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (final res in r.restrictions) {
|
for (final res in r.restrictions) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.readingRestriction, {
|
||||||
JMdictTableNames.readingRestriction,
|
'elementId': elementId,
|
||||||
{
|
'restriction': res,
|
||||||
'entryId': e.entryId,
|
});
|
||||||
'reading': r.reading,
|
|
||||||
'restriction': res,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,16 +124,20 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
for (final e in entries) {
|
for (final e in entries) {
|
||||||
for (final s in e.senses) {
|
for (final s in e.senses) {
|
||||||
b.insert(
|
b.insert(
|
||||||
JMdictTableNames.sense, s.sqlValue..addAll({'entryId': e.entryId}));
|
JMdictTableNames.sense,
|
||||||
|
s.sqlValue..addAll({'entryId': e.entryId}),
|
||||||
|
);
|
||||||
for (final d in s.dialects) {
|
for (final d in s.dialects) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.senseDialect, {
|
||||||
JMdictTableNames.senseDialect,
|
'senseId': s.senseId,
|
||||||
{'senseId': s.senseId, 'dialect': d},
|
'dialect': d,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
for (final f in s.fields) {
|
for (final f in s.fields) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.senseField, {
|
||||||
JMdictTableNames.senseField, {'senseId': s.senseId, 'field': f});
|
'senseId': s.senseId,
|
||||||
|
'field': f,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (final i in s.info) {
|
for (final i in s.info) {
|
||||||
b.insert(JMdictTableNames.senseInfo, {'senseId': s.senseId, 'info': i});
|
b.insert(JMdictTableNames.senseInfo, {'senseId': s.senseId, 'info': i});
|
||||||
@@ -150,16 +149,18 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
b.insert(JMdictTableNames.sensePOS, {'senseId': s.senseId, 'pos': p});
|
b.insert(JMdictTableNames.sensePOS, {'senseId': s.senseId, 'pos': p});
|
||||||
}
|
}
|
||||||
for (final rk in s.restrictedToKanji) {
|
for (final rk in s.restrictedToKanji) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.senseRestrictedToKanji, {
|
||||||
JMdictTableNames.senseRestrictedToKanji,
|
'entryId': e.entryId,
|
||||||
{'entryId': e.entryId, 'senseId': s.senseId, 'kanji': rk},
|
'senseId': s.senseId,
|
||||||
);
|
'kanji': rk,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (final rr in s.restrictedToReading) {
|
for (final rr in s.restrictedToReading) {
|
||||||
b.insert(
|
b.insert(JMdictTableNames.senseRestrictedToReading, {
|
||||||
JMdictTableNames.senseRestrictedToReading,
|
'entryId': e.entryId,
|
||||||
{'entryId': e.entryId, 'senseId': s.senseId, 'reading': rr},
|
'senseId': s.senseId,
|
||||||
);
|
'reading': rr,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (final ls in s.languageSource) {
|
for (final ls in s.languageSource) {
|
||||||
b.insert(
|
b.insert(
|
||||||
@@ -179,7 +180,7 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
await b.commit(noResult: true);
|
await b.commit(noResult: true);
|
||||||
|
|
||||||
print(' [JMdict] Building xref trees');
|
print(' [JMdict] Building xref trees');
|
||||||
SplayTreeMap<String, Set<Entry>> entriesByKanji = SplayTreeMap();
|
final SplayTreeMap<String, Set<Entry>> entriesByKanji = SplayTreeMap();
|
||||||
|
|
||||||
for (final entry in entries) {
|
for (final entry in entries) {
|
||||||
for (final kanji in entry.kanji) {
|
for (final kanji in entry.kanji) {
|
||||||
@@ -190,7 +191,7 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SplayTreeMap<String, Set<Entry>> entriesByReading = SplayTreeMap();
|
final SplayTreeMap<String, Set<Entry>> entriesByReading = SplayTreeMap();
|
||||||
for (final entry in entries) {
|
for (final entry in entries) {
|
||||||
for (final reading in entry.readings) {
|
for (final reading in entry.readings) {
|
||||||
if (entriesByReading.containsKey(reading.reading)) {
|
if (entriesByReading.containsKey(reading.reading)) {
|
||||||
@@ -213,17 +214,14 @@ Future<void> seedJMDictData(List<Entry> entries, Database db) async {
|
|||||||
xref,
|
xref,
|
||||||
);
|
);
|
||||||
|
|
||||||
b.insert(
|
b.insert(JMdictTableNames.senseSeeAlso, {
|
||||||
JMdictTableNames.senseSeeAlso,
|
'senseId': s.senseId,
|
||||||
{
|
'xrefEntryId': resolvedEntry.entry.entryId,
|
||||||
'senseId': s.senseId,
|
'seeAlsoKanji': xref.kanjiRef,
|
||||||
'xrefEntryId': resolvedEntry.entry.entryId,
|
'seeAlsoReading': xref.readingRef,
|
||||||
'seeAlsoKanji': xref.kanjiRef,
|
'seeAlsoSense': xref.senseOrderNum,
|
||||||
'seeAlsoReading': xref.readingRef,
|
'ambiguous': resolvedEntry.ambiguous,
|
||||||
'seeAlsoSense': xref.senseOrderNum,
|
});
|
||||||
'ambiguous': resolvedEntry.ambiguous,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final ant in s.antonyms) {
|
for (final ant in s.antonyms) {
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ List<int?> getPriorityValues(XmlElement e, String prefix) {
|
|||||||
int? news, ichi, spec, gai, nf;
|
int? news, ichi, spec, gai, nf;
|
||||||
for (final pri in e.findElements('${prefix}_pri')) {
|
for (final pri in e.findElements('${prefix}_pri')) {
|
||||||
final txt = pri.innerText;
|
final txt = pri.innerText;
|
||||||
if (txt.startsWith('news'))
|
if (txt.startsWith('news')) {
|
||||||
news = int.parse(txt.substring(4));
|
news = int.parse(txt.substring(4));
|
||||||
else if (txt.startsWith('ichi'))
|
} else if (txt.startsWith('ichi'))
|
||||||
ichi = int.parse(txt.substring(4));
|
ichi = int.parse(txt.substring(4));
|
||||||
else if (txt.startsWith('spec'))
|
else if (txt.startsWith('spec'))
|
||||||
spec = int.parse(txt.substring(4));
|
spec = int.parse(txt.substring(4));
|
||||||
else if (txt.startsWith('gai'))
|
else if (txt.startsWith('gai'))
|
||||||
gai = int.parse(txt.substring(3));
|
gai = int.parse(txt.substring(3));
|
||||||
else if (txt.startsWith('nf')) nf = int.parse(txt.substring(2));
|
else if (txt.startsWith('nf'))
|
||||||
|
nf = int.parse(txt.substring(2));
|
||||||
}
|
}
|
||||||
return [news, ichi, spec, gai, nf];
|
return [news, ichi, spec, gai, nf];
|
||||||
}
|
}
|
||||||
@@ -46,10 +47,7 @@ XRefParts parseXrefParts(String s) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = XRefParts(
|
result = XRefParts(kanjiRef: parts[0], readingRef: parts[1]);
|
||||||
kanjiRef: parts[0],
|
|
||||||
readingRef: parts[1],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ List<Entry> parseJMDictData(XmlElement root) {
|
|||||||
final List<Sense> senses = [];
|
final List<Sense> senses = [];
|
||||||
|
|
||||||
for (final (kanjiNum, k_ele) in entry.findElements('k_ele').indexed) {
|
for (final (kanjiNum, k_ele) in entry.findElements('k_ele').indexed) {
|
||||||
final ke_pri = getPriorityValues(k_ele, 'ke');
|
final kePri = getPriorityValues(k_ele, 'ke');
|
||||||
kanjiEls.add(
|
kanjiEls.add(
|
||||||
KanjiElement(
|
KanjiElement(
|
||||||
orderNum: kanjiNum + 1,
|
orderNum: kanjiNum + 1,
|
||||||
@@ -91,19 +89,20 @@ List<Entry> parseJMDictData(XmlElement root) {
|
|||||||
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
||||||
.toList(),
|
.toList(),
|
||||||
reading: k_ele.findElements('keb').first.innerText,
|
reading: k_ele.findElements('keb').first.innerText,
|
||||||
news: ke_pri[0],
|
news: kePri[0],
|
||||||
ichi: ke_pri[1],
|
ichi: kePri[1],
|
||||||
spec: ke_pri[2],
|
spec: kePri[2],
|
||||||
gai: ke_pri[3],
|
gai: kePri[3],
|
||||||
nf: ke_pri[4],
|
nf: kePri[4],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final (orderNum, r_ele) in entry.findElements('r_ele').indexed) {
|
for (final (orderNum, r_ele) in entry.findElements('r_ele').indexed) {
|
||||||
final re_pri = getPriorityValues(r_ele, 're');
|
final rePri = getPriorityValues(r_ele, 're');
|
||||||
final readingDoesNotMatchKanji =
|
final readingDoesNotMatchKanji = r_ele
|
||||||
r_ele.findElements('re_nokanji').isNotEmpty;
|
.findElements('re_nokanji')
|
||||||
|
.isNotEmpty;
|
||||||
readingEls.add(
|
readingEls.add(
|
||||||
ReadingElement(
|
ReadingElement(
|
||||||
orderNum: orderNum + 1,
|
orderNum: orderNum + 1,
|
||||||
@@ -112,14 +111,16 @@ List<Entry> parseJMDictData(XmlElement root) {
|
|||||||
.findElements('re_inf')
|
.findElements('re_inf')
|
||||||
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
||||||
.toList(),
|
.toList(),
|
||||||
restrictions:
|
restrictions: r_ele
|
||||||
r_ele.findElements('re_restr').map((e) => e.innerText).toList(),
|
.findElements('re_restr')
|
||||||
|
.map((e) => e.innerText)
|
||||||
|
.toList(),
|
||||||
reading: r_ele.findElements('reb').first.innerText,
|
reading: r_ele.findElements('reb').first.innerText,
|
||||||
news: re_pri[0],
|
news: rePri[0],
|
||||||
ichi: re_pri[1],
|
ichi: rePri[1],
|
||||||
spec: re_pri[2],
|
spec: rePri[2],
|
||||||
gai: re_pri[3],
|
gai: rePri[3],
|
||||||
nf: re_pri[4],
|
nf: rePri[4],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,10 +130,14 @@ List<Entry> parseJMDictData(XmlElement root) {
|
|||||||
final result = Sense(
|
final result = Sense(
|
||||||
senseId: senseId,
|
senseId: senseId,
|
||||||
orderNum: orderNum + 1,
|
orderNum: orderNum + 1,
|
||||||
restrictedToKanji:
|
restrictedToKanji: sense
|
||||||
sense.findElements('stagk').map((e) => e.innerText).toList(),
|
.findElements('stagk')
|
||||||
restrictedToReading:
|
.map((e) => e.innerText)
|
||||||
sense.findElements('stagr').map((e) => e.innerText).toList(),
|
.toList(),
|
||||||
|
restrictedToReading: sense
|
||||||
|
.findElements('stagr')
|
||||||
|
.map((e) => e.innerText)
|
||||||
|
.toList(),
|
||||||
pos: sense
|
pos: sense
|
||||||
.findElements('pos')
|
.findElements('pos')
|
||||||
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
.map((e) => e.innerText.substring(1, e.innerText.length - 1))
|
||||||
|
|||||||
@@ -13,42 +13,33 @@ class CodePoint extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'type': type,
|
'type': type,
|
||||||
'codepoint': codepoint,
|
'codepoint': codepoint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Radical extends SQLWritable {
|
class Radical extends SQLWritable {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
final int radicalId;
|
final int radicalId;
|
||||||
|
|
||||||
const Radical({
|
const Radical({required this.kanji, required this.radicalId});
|
||||||
required this.kanji,
|
|
||||||
required this.radicalId,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {'kanji': kanji, 'radicalId': radicalId};
|
||||||
'kanji': kanji,
|
|
||||||
'radicalId': radicalId,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StrokeMiscount extends SQLWritable {
|
class StrokeMiscount extends SQLWritable {
|
||||||
final String kanji;
|
final String kanji;
|
||||||
final int strokeCount;
|
final int strokeCount;
|
||||||
|
|
||||||
const StrokeMiscount({
|
const StrokeMiscount({required this.kanji, required this.strokeCount});
|
||||||
required this.kanji,
|
|
||||||
required this.strokeCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'strokeCount': strokeCount,
|
'strokeCount': strokeCount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Variant extends SQLWritable {
|
class Variant extends SQLWritable {
|
||||||
@@ -64,10 +55,10 @@ class Variant extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'type': type,
|
'type': type,
|
||||||
'variant': variant,
|
'variant': variant,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class DictionaryReference extends SQLWritable {
|
class DictionaryReference extends SQLWritable {
|
||||||
@@ -83,10 +74,10 @@ class DictionaryReference extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'type': type,
|
'type': type,
|
||||||
'ref': ref,
|
'ref': ref,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class DictionaryReferenceMoro extends SQLWritable {
|
class DictionaryReferenceMoro extends SQLWritable {
|
||||||
@@ -104,11 +95,11 @@ class DictionaryReferenceMoro extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'ref': ref,
|
'ref': ref,
|
||||||
'volume': volume,
|
'volume': volume,
|
||||||
'page': page,
|
'page': page,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class QueryCode extends SQLWritable {
|
class QueryCode extends SQLWritable {
|
||||||
@@ -126,11 +117,11 @@ class QueryCode extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'code': code,
|
'code': code,
|
||||||
'type': type,
|
'type': type,
|
||||||
'skipMisclassification': skipMisclassification,
|
'skipMisclassification': skipMisclassification,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Reading extends SQLWritable {
|
class Reading extends SQLWritable {
|
||||||
@@ -146,10 +137,10 @@ class Reading extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'type': type,
|
'type': type,
|
||||||
'reading': reading,
|
'reading': reading,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Kunyomi extends SQLWritable {
|
class Kunyomi extends SQLWritable {
|
||||||
@@ -165,10 +156,10 @@ class Kunyomi extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'yomi': yomi,
|
'yomi': yomi,
|
||||||
'isJouyou': isJouyou,
|
'isJouyou': isJouyou,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Onyomi extends SQLWritable {
|
class Onyomi extends SQLWritable {
|
||||||
@@ -186,11 +177,11 @@ class Onyomi extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'yomi': yomi,
|
'yomi': yomi,
|
||||||
'isJouyou': isJouyou,
|
'isJouyou': isJouyou,
|
||||||
'type': type,
|
'type': type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meaning extends SQLWritable {
|
class Meaning extends SQLWritable {
|
||||||
@@ -206,10 +197,10 @@ class Meaning extends SQLWritable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'language': language,
|
'language': language,
|
||||||
'meaning': meaning,
|
'meaning': meaning,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Character extends SQLWritable {
|
class Character extends SQLWritable {
|
||||||
@@ -254,11 +245,12 @@ class Character extends SQLWritable {
|
|||||||
this.nanori = const [],
|
this.nanori = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {
|
||||||
'literal': literal,
|
'literal': literal,
|
||||||
'grade': grade,
|
'grade': grade,
|
||||||
'strokeCount': strokeCount,
|
'strokeCount': strokeCount,
|
||||||
'frequency': frequency,
|
'frequency': frequency,
|
||||||
'jlpt': jlpt,
|
'jlpt': jlpt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ Future<void> seedKANJIDICData(List<Character> characters, Database db) async {
|
|||||||
assert(c.radical != null, 'Radical name without radical');
|
assert(c.radical != null, 'Radical name without radical');
|
||||||
b.insert(
|
b.insert(
|
||||||
KANJIDICTableNames.radicalName,
|
KANJIDICTableNames.radicalName,
|
||||||
{
|
{'radicalId': c.radical!.radicalId, 'name': n},
|
||||||
'radicalId': c.radical!.radicalId,
|
|
||||||
'name': n,
|
|
||||||
},
|
|
||||||
conflictAlgorithm: ConflictAlgorithm.ignore,
|
conflictAlgorithm: ConflictAlgorithm.ignore,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -34,13 +31,10 @@ Future<void> seedKANJIDICData(List<Character> characters, Database db) async {
|
|||||||
b.insert(KANJIDICTableNames.radical, c.radical!.sqlValue);
|
b.insert(KANJIDICTableNames.radical, c.radical!.sqlValue);
|
||||||
}
|
}
|
||||||
for (final sm in c.strokeMiscounts) {
|
for (final sm in c.strokeMiscounts) {
|
||||||
b.insert(
|
b.insert(KANJIDICTableNames.strokeMiscount, {
|
||||||
KANJIDICTableNames.strokeMiscount,
|
'kanji': c.literal,
|
||||||
{
|
'strokeCount': sm,
|
||||||
'kanji': c.literal,
|
});
|
||||||
'strokeCount': sm,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (final v in c.variants) {
|
for (final v in c.variants) {
|
||||||
b.insert(KANJIDICTableNames.variant, v.sqlValue);
|
b.insert(KANJIDICTableNames.variant, v.sqlValue);
|
||||||
@@ -64,24 +58,24 @@ Future<void> seedKANJIDICData(List<Character> characters, Database db) async {
|
|||||||
}
|
}
|
||||||
for (final (i, y) in c.kunyomi.indexed) {
|
for (final (i, y) in c.kunyomi.indexed) {
|
||||||
b.insert(
|
b.insert(
|
||||||
KANJIDICTableNames.kunyomi, y.sqlValue..addAll({'orderNum': i + 1}));
|
KANJIDICTableNames.kunyomi,
|
||||||
|
y.sqlValue..addAll({'orderNum': i + 1}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (final (i, y) in c.onyomi.indexed) {
|
for (final (i, y) in c.onyomi.indexed) {
|
||||||
b.insert(
|
b.insert(
|
||||||
KANJIDICTableNames.onyomi, y.sqlValue..addAll({'orderNum': i + 1}));
|
KANJIDICTableNames.onyomi,
|
||||||
|
y.sqlValue..addAll({'orderNum': i + 1}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (final (i, m) in c.meanings.indexed) {
|
for (final (i, m) in c.meanings.indexed) {
|
||||||
b.insert(
|
b.insert(
|
||||||
KANJIDICTableNames.meaning, m.sqlValue..addAll({'orderNum': i + 1}));
|
KANJIDICTableNames.meaning,
|
||||||
|
m.sqlValue..addAll({'orderNum': i + 1}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (final n in c.nanori) {
|
for (final n in c.nanori) {
|
||||||
b.insert(
|
b.insert(KANJIDICTableNames.nanori, {'kanji': c.literal, 'nanori': n});
|
||||||
KANJIDICTableNames.nanori,
|
|
||||||
{
|
|
||||||
'kanji': c.literal,
|
|
||||||
'nanori': n,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await b.commit(noResult: true);
|
await b.commit(noResult: true);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:jadb/_data_ingestion/kanjidic/objects.dart';
|
import 'package:jadb/_data_ingestion/kanjidic/objects.dart';
|
||||||
|
import 'package:jadb/util/romaji_transliteration.dart';
|
||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
|
|
||||||
List<Character> parseKANJIDICData(XmlElement root) {
|
List<Character> parseKANJIDICData(XmlElement root) {
|
||||||
@@ -9,27 +10,33 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
final codepoint = c.findElements('codepoint').firstOrNull;
|
final codepoint = c.findElements('codepoint').firstOrNull;
|
||||||
final radical = c.findElements('radical').firstOrNull;
|
final radical = c.findElements('radical').firstOrNull;
|
||||||
final misc = c.findElements('misc').first;
|
final misc = c.findElements('misc').first;
|
||||||
final dic_number = c.findElements('dic_number').firstOrNull;
|
final dicNumber = c.findElements('dic_number').firstOrNull;
|
||||||
final query_code = c.findElements('query_code').first;
|
final queryCode = c.findElements('query_code').first;
|
||||||
final reading_meaning = c.findElements('reading_meaning').firstOrNull;
|
final readingMeaning = c.findElements('reading_meaning').firstOrNull;
|
||||||
|
|
||||||
// TODO: Group readings and meanings by their rmgroup parent node.
|
// TODO: Group readings and meanings by their rmgroup parent node.
|
||||||
|
|
||||||
result.add(
|
result.add(
|
||||||
Character(
|
Character(
|
||||||
literal: kanji,
|
literal: kanji,
|
||||||
strokeCount:
|
strokeCount: int.parse(
|
||||||
int.parse(misc.findElements('stroke_count').first.innerText),
|
misc.findElements('stroke_count').first.innerText,
|
||||||
|
),
|
||||||
grade: int.tryParse(
|
grade: int.tryParse(
|
||||||
misc.findElements('grade').firstOrNull?.innerText ?? ''),
|
misc.findElements('grade').firstOrNull?.innerText ?? '',
|
||||||
|
),
|
||||||
frequency: int.tryParse(
|
frequency: int.tryParse(
|
||||||
misc.findElements('freq').firstOrNull?.innerText ?? ''),
|
misc.findElements('freq').firstOrNull?.innerText ?? '',
|
||||||
|
),
|
||||||
jlpt: int.tryParse(
|
jlpt: int.tryParse(
|
||||||
misc.findElements('jlpt').firstOrNull?.innerText ?? '',
|
misc.findElements('jlpt').firstOrNull?.innerText ?? '',
|
||||||
),
|
),
|
||||||
radicalName:
|
radicalName: misc
|
||||||
misc.findElements('rad_name').map((e) => e.innerText).toList(),
|
.findElements('rad_name')
|
||||||
codepoints: codepoint
|
.map((e) => e.innerText)
|
||||||
|
.toList(),
|
||||||
|
codepoints:
|
||||||
|
codepoint
|
||||||
?.findElements('cp_value')
|
?.findElements('cp_value')
|
||||||
.map(
|
.map(
|
||||||
(e) => CodePoint(
|
(e) => CodePoint(
|
||||||
@@ -44,10 +51,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
?.findElements('rad_value')
|
?.findElements('rad_value')
|
||||||
.where((e) => e.getAttribute('rad_type') == 'classical')
|
.where((e) => e.getAttribute('rad_type') == 'classical')
|
||||||
.map(
|
.map(
|
||||||
(e) => Radical(
|
(e) => Radical(kanji: kanji, radicalId: int.parse(e.innerText)),
|
||||||
kanji: kanji,
|
|
||||||
radicalId: int.parse(e.innerText),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.firstOrNull,
|
.firstOrNull,
|
||||||
strokeMiscounts: misc
|
strokeMiscounts: misc
|
||||||
@@ -65,7 +69,8 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
dictionaryReferences: dic_number
|
dictionaryReferences:
|
||||||
|
dicNumber
|
||||||
?.findElements('dic_ref')
|
?.findElements('dic_ref')
|
||||||
.where((e) => e.getAttribute('dr_type') != 'moro')
|
.where((e) => e.getAttribute('dr_type') != 'moro')
|
||||||
.map(
|
.map(
|
||||||
@@ -77,7 +82,8 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
dictionaryReferencesMoro: dic_number
|
dictionaryReferencesMoro:
|
||||||
|
dicNumber
|
||||||
?.findElements('dic_ref')
|
?.findElements('dic_ref')
|
||||||
.where((e) => e.getAttribute('dr_type') == 'moro')
|
.where((e) => e.getAttribute('dr_type') == 'moro')
|
||||||
.map(
|
.map(
|
||||||
@@ -90,7 +96,7 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
querycodes: query_code
|
querycodes: queryCode
|
||||||
.findElements('q_code')
|
.findElements('q_code')
|
||||||
.map(
|
.map(
|
||||||
(e) => QueryCode(
|
(e) => QueryCode(
|
||||||
@@ -101,7 +107,8 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
readings: reading_meaning
|
readings:
|
||||||
|
readingMeaning
|
||||||
?.findAllElements('reading')
|
?.findAllElements('reading')
|
||||||
.where(
|
.where(
|
||||||
(e) =>
|
(e) =>
|
||||||
@@ -116,7 +123,8 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
kunyomi: reading_meaning
|
kunyomi:
|
||||||
|
readingMeaning
|
||||||
?.findAllElements('reading')
|
?.findAllElements('reading')
|
||||||
.where((e) => e.getAttribute('r_type') == 'ja_kun')
|
.where((e) => e.getAttribute('r_type') == 'ja_kun')
|
||||||
.map(
|
.map(
|
||||||
@@ -128,19 +136,22 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
onyomi: reading_meaning
|
onyomi:
|
||||||
|
readingMeaning
|
||||||
?.findAllElements('reading')
|
?.findAllElements('reading')
|
||||||
.where((e) => e.getAttribute('r_type') == 'ja_on')
|
.where((e) => e.getAttribute('r_type') == 'ja_on')
|
||||||
.map(
|
.map(
|
||||||
(e) => Onyomi(
|
(e) => Onyomi(
|
||||||
kanji: kanji,
|
kanji: kanji,
|
||||||
yomi: e.innerText,
|
yomi: transliterateKatakanaToHiragana(e.innerText),
|
||||||
isJouyou: e.getAttribute('r_status') == 'jy',
|
isJouyou: e.getAttribute('r_status') == 'jy',
|
||||||
type: e.getAttribute('on_type')),
|
type: e.getAttribute('on_type'),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
meanings: reading_meaning
|
meanings:
|
||||||
|
readingMeaning
|
||||||
?.findAllElements('meaning')
|
?.findAllElements('meaning')
|
||||||
.map(
|
.map(
|
||||||
(e) => Meaning(
|
(e) => Meaning(
|
||||||
@@ -151,7 +162,8 @@ List<Character> parseKANJIDICData(XmlElement root) {
|
|||||||
)
|
)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
nanori: reading_meaning
|
nanori:
|
||||||
|
readingMeaning
|
||||||
?.findElements('nanori')
|
?.findElements('nanori')
|
||||||
.map((e) => e.innerText)
|
.map((e) => e.innerText)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
|
|||||||
@@ -22,32 +22,33 @@ Future<Database> openLocalDb({
|
|||||||
jadbPath = File(jadbPath).resolveSymbolicLinksSync();
|
jadbPath = File(jadbPath).resolveSymbolicLinksSync();
|
||||||
|
|
||||||
if (libsqlitePath == null) {
|
if (libsqlitePath == null) {
|
||||||
throw Exception("LIBSQLITE_PATH is not set");
|
throw Exception('LIBSQLITE_PATH is not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File(libsqlitePath).existsSync()) {
|
if (!File(libsqlitePath).existsSync()) {
|
||||||
throw Exception("LIBSQLITE_PATH does not exist: $libsqlitePath");
|
throw Exception('LIBSQLITE_PATH does not exist: $libsqlitePath');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File(jadbPath).existsSync()) {
|
if (!File(jadbPath).existsSync()) {
|
||||||
throw Exception("JADB_PATH does not exist: $jadbPath");
|
throw Exception('JADB_PATH does not exist: $jadbPath');
|
||||||
}
|
}
|
||||||
|
|
||||||
final db = await createDatabaseFactoryFfi(
|
final db =
|
||||||
ffiInit: () =>
|
await createDatabaseFactoryFfi(
|
||||||
open.overrideForAll(() => DynamicLibrary.open(libsqlitePath!)),
|
ffiInit: () =>
|
||||||
).openDatabase(
|
open.overrideForAll(() => DynamicLibrary.open(libsqlitePath!)),
|
||||||
jadbPath,
|
).openDatabase(
|
||||||
options: OpenDatabaseOptions(
|
jadbPath,
|
||||||
onConfigure: (db) async {
|
options: OpenDatabaseOptions(
|
||||||
if (walMode) {
|
onConfigure: (db) async {
|
||||||
await db.execute("PRAGMA journal_mode = WAL");
|
if (walMode) {
|
||||||
}
|
await db.execute('PRAGMA journal_mode = WAL');
|
||||||
await db.execute("PRAGMA foreign_keys = ON");
|
}
|
||||||
},
|
await db.execute('PRAGMA foreign_keys = ON');
|
||||||
readOnly: !readWrite,
|
},
|
||||||
),
|
readOnly: !readWrite,
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (verifyTablesExist) {
|
if (verifyTablesExist) {
|
||||||
await db.jadbVerifyTables();
|
await db.jadbVerifyTables();
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import 'dart:io';
|
|||||||
Iterable<String> parseRADKFILEBlocks(File radkfile) {
|
Iterable<String> parseRADKFILEBlocks(File radkfile) {
|
||||||
final String content = File('data/tmp/radkfile_utf8').readAsStringSync();
|
final String content = File('data/tmp/radkfile_utf8').readAsStringSync();
|
||||||
|
|
||||||
final Iterable<String> blocks =
|
final Iterable<String> blocks = content
|
||||||
content.replaceAll(RegExp(r'^#.*$'), '').split(r'$').skip(2);
|
.replaceAll(RegExp(r'^#.*$'), '')
|
||||||
|
.split(r'$')
|
||||||
|
.skip(2);
|
||||||
|
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,20 @@
|
|||||||
import 'package:jadb/table_names/radkfile.dart';
|
import 'package:jadb/table_names/radkfile.dart';
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
Future<void> seedRADKFILEData(
|
Future<void> seedRADKFILEData(Iterable<String> blocks, Database db) async {
|
||||||
Iterable<String> blocks,
|
|
||||||
Database db,
|
|
||||||
) async {
|
|
||||||
final b = db.batch();
|
final b = db.batch();
|
||||||
|
|
||||||
for (final block in blocks) {
|
for (final block in blocks) {
|
||||||
final String radical = block[1];
|
final String radical = block[1];
|
||||||
final List<String> kanjiList = block
|
final List<String> kanjiList =
|
||||||
.replaceFirst(RegExp(r'.*\n'), '')
|
block.replaceFirst(RegExp(r'.*\n'), '').split('')
|
||||||
.split('')
|
..removeWhere((e) => e == '' || e == '\n');
|
||||||
..removeWhere((e) => e == '' || e == '\n');
|
|
||||||
|
|
||||||
for (final kanji in kanjiList.toSet()) {
|
for (final kanji in kanjiList.toSet()) {
|
||||||
b.insert(
|
b.insert(RADKFILETableNames.radkfile, {
|
||||||
RADKFILETableNames.radkfile,
|
'radical': radical,
|
||||||
{
|
'kanji': kanji,
|
||||||
'radical': radical,
|
});
|
||||||
'kanji': kanji,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ Future<void> seedData(Database db) async {
|
|||||||
|
|
||||||
Future<void> parseAndSeedDataFromJMdict(Database db) async {
|
Future<void> parseAndSeedDataFromJMdict(Database db) async {
|
||||||
print('[JMdict] Reading file content...');
|
print('[JMdict] Reading file content...');
|
||||||
String rawXML = File('data/tmp/JMdict.xml').readAsStringSync();
|
final String rawXML = File('data/tmp/JMdict.xml').readAsStringSync();
|
||||||
|
|
||||||
print('[JMdict] Parsing XML tags...');
|
print('[JMdict] Parsing XML tags...');
|
||||||
XmlElement root = XmlDocument.parse(rawXML).getElement('JMdict')!;
|
final XmlElement root = XmlDocument.parse(rawXML).getElement('JMdict')!;
|
||||||
|
|
||||||
print('[JMdict] Parsing XML content...');
|
print('[JMdict] Parsing XML content...');
|
||||||
final entries = parseJMDictData(root);
|
final entries = parseJMDictData(root);
|
||||||
@@ -38,10 +38,10 @@ Future<void> parseAndSeedDataFromJMdict(Database db) async {
|
|||||||
|
|
||||||
Future<void> parseAndSeedDataFromKANJIDIC(Database db) async {
|
Future<void> parseAndSeedDataFromKANJIDIC(Database db) async {
|
||||||
print('[KANJIDIC2] Reading file...');
|
print('[KANJIDIC2] Reading file...');
|
||||||
String rawXML = File('data/tmp/kanjidic2.xml').readAsStringSync();
|
final String rawXML = File('data/tmp/kanjidic2.xml').readAsStringSync();
|
||||||
|
|
||||||
print('[KANJIDIC2] Parsing XML...');
|
print('[KANJIDIC2] Parsing XML...');
|
||||||
XmlElement root = XmlDocument.parse(rawXML).getElement('kanjidic2')!;
|
final XmlElement root = XmlDocument.parse(rawXML).getElement('kanjidic2')!;
|
||||||
|
|
||||||
print('[KANJIDIC2] Parsing XML content...');
|
print('[KANJIDIC2] Parsing XML content...');
|
||||||
final entries = parseKANJIDICData(root);
|
final entries = parseKANJIDICData(root);
|
||||||
@@ -52,7 +52,7 @@ Future<void> parseAndSeedDataFromKANJIDIC(Database db) async {
|
|||||||
|
|
||||||
Future<void> parseAndSeedDataFromRADKFILE(Database db) async {
|
Future<void> parseAndSeedDataFromRADKFILE(Database db) async {
|
||||||
print('[RADKFILE] Reading file...');
|
print('[RADKFILE] Reading file...');
|
||||||
File raw = File('data/tmp/RADKFILE');
|
final File raw = File('data/tmp/RADKFILE');
|
||||||
|
|
||||||
print('[RADKFILE] Parsing content...');
|
print('[RADKFILE] Parsing content...');
|
||||||
final blocks = parseRADKFILEBlocks(raw);
|
final blocks = parseRADKFILEBlocks(raw);
|
||||||
@@ -63,7 +63,7 @@ Future<void> parseAndSeedDataFromRADKFILE(Database db) async {
|
|||||||
|
|
||||||
Future<void> parseAndSeedDataFromTanosJLPT(Database db) async {
|
Future<void> parseAndSeedDataFromTanosJLPT(Database db) async {
|
||||||
print('[TANOS-JLPT] Reading files...');
|
print('[TANOS-JLPT] Reading files...');
|
||||||
Map<String, File> files = {
|
final Map<String, File> files = {
|
||||||
'N1': File('data/tanos-jlpt/n1.csv'),
|
'N1': File('data/tanos-jlpt/n1.csv'),
|
||||||
'N2': File('data/tanos-jlpt/n2.csv'),
|
'N2': File('data/tanos-jlpt/n2.csv'),
|
||||||
'N3': File('data/tanos-jlpt/n3.csv'),
|
'N3': File('data/tanos-jlpt/n3.csv'),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Future<List<JLPTRankedWord>> parseJLPTRankedWords(
|
|||||||
final file = entry.value;
|
final file = entry.value;
|
||||||
|
|
||||||
if (!file.existsSync()) {
|
if (!file.existsSync()) {
|
||||||
throw Exception("File $jlptLevel does not exist");
|
throw Exception('File $jlptLevel does not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
final rows = await file
|
final rows = await file
|
||||||
@@ -25,29 +25,33 @@ Future<List<JLPTRankedWord>> parseJLPTRankedWords(
|
|||||||
|
|
||||||
for (final row in rows) {
|
for (final row in rows) {
|
||||||
if (row.length != 3) {
|
if (row.length != 3) {
|
||||||
throw Exception("Invalid line in $jlptLevel: $row");
|
throw Exception('Invalid line in $jlptLevel: $row');
|
||||||
}
|
}
|
||||||
|
|
||||||
final kanji = (row[0] as String).isEmpty
|
final kanji = (row[0] as String).isEmpty
|
||||||
? null
|
? null
|
||||||
: (row[0] as String)
|
: (row[0] as String)
|
||||||
.replaceFirst(RegExp('^お・'), '')
|
.replaceFirst(RegExp('^お・'), '')
|
||||||
.replaceAll(RegExp(r'(.*)'), '');
|
.replaceAll(RegExp(r'(.*)'), '');
|
||||||
|
|
||||||
final readings = (row[1] as String)
|
final readings = (row[1] as String)
|
||||||
.split(RegExp('[・/、(:?\s+)]'))
|
.split(RegExp('[・/、(:?s+)]'))
|
||||||
.map((e) => e.trim())
|
.map((e) => e.trim())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final meanings =
|
final meanings = (row[2] as String)
|
||||||
(row[2] as String).split(',').expand(cleanMeaning).toList();
|
.split(',')
|
||||||
|
.expand(cleanMeaning)
|
||||||
|
.toList();
|
||||||
|
|
||||||
result.add(JLPTRankedWord(
|
result.add(
|
||||||
readings: readings,
|
JLPTRankedWord(
|
||||||
kanji: kanji,
|
readings: readings,
|
||||||
jlptLevel: jlptLevel,
|
kanji: kanji,
|
||||||
meanings: meanings,
|
jlptLevel: jlptLevel,
|
||||||
));
|
meanings: meanings,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ class JLPTRankedWord {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'(${jlptLevel},${kanji},"${readings.join(",")}","${meanings.join(",")})';
|
'($jlptLevel,$kanji,"${readings.join(",")}","${meanings.join(",")})';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,39 @@
|
|||||||
import 'package:jadb/table_names/jmdict.dart';
|
|
||||||
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
|
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
|
||||||
import 'package:jadb/_data_ingestion/tanos-jlpt/overrides.dart';
|
import 'package:jadb/_data_ingestion/tanos-jlpt/overrides.dart';
|
||||||
|
import 'package:jadb/table_names/jmdict.dart';
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
Future<List<int>> _findReadingCandidates(
|
Future<List<int>> _findReadingCandidates(JLPTRankedWord word, Database db) => db
|
||||||
JLPTRankedWord word,
|
.query(
|
||||||
Database db,
|
JMdictTableNames.readingElement,
|
||||||
) =>
|
columns: ['entryId'],
|
||||||
db
|
where:
|
||||||
.query(
|
'"reading" IN (${List.filled(word.readings.length, '?').join(',')})',
|
||||||
JMdictTableNames.readingElement,
|
whereArgs: [...word.readings],
|
||||||
columns: ['entryId'],
|
)
|
||||||
where:
|
.then((rows) => rows.map((row) => row['entryId'] as int).toList());
|
||||||
'"reading" IN (${List.filled(word.readings.length, '?').join(',')})',
|
|
||||||
whereArgs: [...word.readings],
|
|
||||||
)
|
|
||||||
.then((rows) => rows.map((row) => row['entryId'] as int).toList());
|
|
||||||
|
|
||||||
Future<List<int>> _findKanjiCandidates(
|
Future<List<int>> _findKanjiCandidates(JLPTRankedWord word, Database db) => db
|
||||||
JLPTRankedWord word,
|
.query(
|
||||||
Database db,
|
JMdictTableNames.kanjiElement,
|
||||||
) =>
|
columns: ['entryId'],
|
||||||
db
|
where: 'reading = ?',
|
||||||
.query(
|
whereArgs: [word.kanji],
|
||||||
JMdictTableNames.kanjiElement,
|
)
|
||||||
columns: ['entryId'],
|
.then((rows) => rows.map((row) => row['entryId'] as int).toList());
|
||||||
where: 'reading = ?',
|
|
||||||
whereArgs: [word.kanji],
|
|
||||||
)
|
|
||||||
.then((rows) => rows.map((row) => row['entryId'] as int).toList());
|
|
||||||
|
|
||||||
Future<List<(int, String)>> _findSenseCandidates(
|
Future<List<(int, String)>> _findSenseCandidates(
|
||||||
JLPTRankedWord word,
|
JLPTRankedWord word,
|
||||||
Database db,
|
Database db,
|
||||||
) =>
|
) => db
|
||||||
db.rawQuery(
|
.rawQuery(
|
||||||
'SELECT entryId, phrase '
|
'SELECT entryId, phrase '
|
||||||
'FROM "${JMdictTableNames.senseGlossary}" '
|
'FROM "${JMdictTableNames.senseGlossary}" '
|
||||||
'JOIN "${JMdictTableNames.sense}" USING (senseId)'
|
'JOIN "${JMdictTableNames.sense}" USING (senseId)'
|
||||||
'WHERE phrase IN (${List.filled(
|
'WHERE phrase IN (${List.filled(word.meanings.length, '?').join(',')})',
|
||||||
word.meanings.length,
|
|
||||||
'?',
|
|
||||||
).join(',')})',
|
|
||||||
[...word.meanings],
|
[...word.meanings],
|
||||||
).then(
|
)
|
||||||
|
.then(
|
||||||
(rows) => rows
|
(rows) => rows
|
||||||
.map((row) => (row['entryId'] as int, row['phrase'] as String))
|
.map((row) => (row['entryId'] as int, row['phrase'] as String))
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -55,8 +45,10 @@ Future<int?> findEntry(
|
|||||||
bool useOverrides = true,
|
bool useOverrides = true,
|
||||||
}) async {
|
}) async {
|
||||||
final List<int> readingCandidates = await _findReadingCandidates(word, db);
|
final List<int> readingCandidates = await _findReadingCandidates(word, db);
|
||||||
final List<(int, String)> senseCandidates =
|
final List<(int, String)> senseCandidates = await _findSenseCandidates(
|
||||||
await _findSenseCandidates(word, db);
|
word,
|
||||||
|
db,
|
||||||
|
);
|
||||||
|
|
||||||
List<int> entryIds;
|
List<int> entryIds;
|
||||||
|
|
||||||
@@ -71,8 +63,10 @@ Future<int?> findEntry(
|
|||||||
print('No entry found, trying to combine with senses');
|
print('No entry found, trying to combine with senses');
|
||||||
|
|
||||||
entryIds = readingCandidates
|
entryIds = readingCandidates
|
||||||
.where((readingId) =>
|
.where(
|
||||||
senseCandidates.any((sense) => sense.$1 == readingId))
|
(readingId) =>
|
||||||
|
senseCandidates.any((sense) => sense.$1 == readingId),
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -88,12 +82,15 @@ Future<int?> findEntry(
|
|||||||
|
|
||||||
if (overrideEntries.length > 1) {
|
if (overrideEntries.length > 1) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Multiple override entries found for ${word.toString()}: $entryIds');
|
'Multiple override entries found for ${word.toString()}: $entryIds',
|
||||||
} else if (overrideEntries.length == 0 &&
|
);
|
||||||
!word.readings.any((reading) =>
|
} else if (overrideEntries.isEmpty &&
|
||||||
TANOS_JLPT_OVERRIDES.containsKey((word.kanji, reading)))) {
|
!word.readings.any(
|
||||||
|
(reading) => TANOS_JLPT_OVERRIDES.containsKey((word.kanji, reading)),
|
||||||
|
)) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'No override entry found for ${word.toString()}: $entryIds');
|
'No override entry found for ${word.toString()}: $entryIds',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Found override: ${overrideEntries.firstOrNull}');
|
print('Found override: ${overrideEntries.firstOrNull}');
|
||||||
@@ -103,7 +100,8 @@ Future<int?> findEntry(
|
|||||||
|
|
||||||
if (entryIds.length > 1) {
|
if (entryIds.length > 1) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Multiple override entries found for ${word.toString()}: $entryIds');
|
'Multiple override entries found for ${word.toString()}: $entryIds',
|
||||||
|
);
|
||||||
} else if (entryIds.isEmpty) {
|
} else if (entryIds.isEmpty) {
|
||||||
throw Exception('No entry found for ${word.toString()}');
|
throw Exception('No entry found for ${word.toString()}');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,17 @@ Future<void> seedTanosJLPTData(
|
|||||||
Map<String, Set<int>> resolvedEntries,
|
Map<String, Set<int>> resolvedEntries,
|
||||||
Database db,
|
Database db,
|
||||||
) async {
|
) async {
|
||||||
Batch b = db.batch();
|
final Batch b = db.batch();
|
||||||
|
|
||||||
for (final jlptLevel in resolvedEntries.entries) {
|
for (final jlptLevel in resolvedEntries.entries) {
|
||||||
final level = jlptLevel.key;
|
final level = jlptLevel.key;
|
||||||
final entryIds = jlptLevel.value;
|
final entryIds = jlptLevel.value;
|
||||||
|
|
||||||
for (final entryId in entryIds) {
|
for (final entryId in entryIds) {
|
||||||
b.insert(
|
b.insert(TanosJLPTTableNames.jlptTag, {
|
||||||
TanosJLPTTableNames.jlptTag,
|
'entryId': entryId,
|
||||||
{
|
'jlptLevel': level,
|
||||||
'entryId': entryId,
|
});
|
||||||
'jlptLevel': level,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
||||||
import 'package:jadb/_data_ingestion/seed_database.dart';
|
import 'package:jadb/_data_ingestion/seed_database.dart';
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
|
||||||
import 'package:jadb/cli/args.dart';
|
import 'package:jadb/cli/args.dart';
|
||||||
|
|
||||||
class CreateDb extends Command {
|
class CreateDb extends Command {
|
||||||
final name = "create-db";
|
@override
|
||||||
final description = "Create the database";
|
final name = 'create-db';
|
||||||
|
@override
|
||||||
|
final description = 'Create the database';
|
||||||
|
|
||||||
CreateDb() {
|
CreateDb() {
|
||||||
addLibsqliteArg(argParser);
|
addLibsqliteArg(argParser);
|
||||||
@@ -23,6 +24,7 @@ class CreateDb extends Command {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
if (argResults!.option('libsqlite') == null) {
|
if (argResults!.option('libsqlite') == null) {
|
||||||
print(argParser.usage);
|
print(argParser.usage);
|
||||||
@@ -35,12 +37,22 @@ class CreateDb extends Command {
|
|||||||
readWrite: true,
|
readWrite: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
await seedData(db).then((_) {
|
bool failed = false;
|
||||||
print("Database created successfully");
|
await seedData(db)
|
||||||
}).catchError((error) {
|
.then((_) {
|
||||||
print("Error creating database: $error");
|
print('Database created successfully');
|
||||||
}).whenComplete(() {
|
})
|
||||||
db.close();
|
.catchError((error) {
|
||||||
});
|
print('Error creating database: $error');
|
||||||
|
failed = true;
|
||||||
|
})
|
||||||
|
.whenComplete(() {
|
||||||
|
db.close();
|
||||||
|
});
|
||||||
|
if (failed) {
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
||||||
import 'package:jadb/_data_ingestion/tanos-jlpt/csv_parser.dart';
|
import 'package:jadb/_data_ingestion/tanos-jlpt/csv_parser.dart';
|
||||||
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
|
import 'package:jadb/_data_ingestion/tanos-jlpt/objects.dart';
|
||||||
import 'package:jadb/_data_ingestion/tanos-jlpt/resolve.dart';
|
import 'package:jadb/_data_ingestion/tanos-jlpt/resolve.dart';
|
||||||
@@ -10,9 +9,11 @@ import 'package:jadb/cli/args.dart';
|
|||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
class CreateTanosJlptMappings extends Command {
|
class CreateTanosJlptMappings extends Command {
|
||||||
final name = "create-tanos-jlpt-mappings";
|
@override
|
||||||
|
final name = 'create-tanos-jlpt-mappings';
|
||||||
|
@override
|
||||||
final description =
|
final description =
|
||||||
"Resolve Tanos JLPT data against JMDict. This tool is useful to create overrides for ambiguous references";
|
'Resolve Tanos JLPT data against JMDict. This tool is useful to create overrides for ambiguous references';
|
||||||
|
|
||||||
CreateTanosJlptMappings() {
|
CreateTanosJlptMappings() {
|
||||||
addLibsqliteArg(argParser);
|
addLibsqliteArg(argParser);
|
||||||
@@ -26,6 +27,7 @@ class CreateTanosJlptMappings extends Command {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
if (argResults!.option('libsqlite') == null ||
|
if (argResults!.option('libsqlite') == null ||
|
||||||
argResults!.option('jadb') == null) {
|
argResults!.option('jadb') == null) {
|
||||||
@@ -40,7 +42,7 @@ class CreateTanosJlptMappings extends Command {
|
|||||||
|
|
||||||
final useOverrides = argResults!.flag('overrides');
|
final useOverrides = argResults!.flag('overrides');
|
||||||
|
|
||||||
Map<String, File> files = {
|
final Map<String, File> files = {
|
||||||
'N1': File('data/tanos-jlpt/n1.csv'),
|
'N1': File('data/tanos-jlpt/n1.csv'),
|
||||||
'N2': File('data/tanos-jlpt/n2.csv'),
|
'N2': File('data/tanos-jlpt/n2.csv'),
|
||||||
'N3': File('data/tanos-jlpt/n3.csv'),
|
'N3': File('data/tanos-jlpt/n3.csv'),
|
||||||
@@ -59,11 +61,12 @@ Future<void> resolveExisting(
|
|||||||
Database db,
|
Database db,
|
||||||
bool useOverrides,
|
bool useOverrides,
|
||||||
) async {
|
) async {
|
||||||
List<JLPTRankedWord> missingWords = [];
|
final List<JLPTRankedWord> missingWords = [];
|
||||||
for (final (i, word) in rankedWords.indexed) {
|
for (final (i, word) in rankedWords.indexed) {
|
||||||
try {
|
try {
|
||||||
print(
|
print(
|
||||||
'[${(i + 1).toString().padLeft(4, '0')}/${rankedWords.length}] ${word.toString()}');
|
'[${(i + 1).toString().padLeft(4, '0')}/${rankedWords.length}] ${word.toString()}',
|
||||||
|
);
|
||||||
await findEntry(word, db, useOverrides: useOverrides);
|
await findEntry(word, db, useOverrides: useOverrides);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
@@ -78,16 +81,19 @@ Future<void> resolveExisting(
|
|||||||
|
|
||||||
print('Statistics:');
|
print('Statistics:');
|
||||||
for (final jlptLevel in ['N5', 'N4', 'N3', 'N2', 'N1']) {
|
for (final jlptLevel in ['N5', 'N4', 'N3', 'N2', 'N1']) {
|
||||||
final missingWordCount =
|
final missingWordCount = missingWords
|
||||||
missingWords.where((e) => e.jlptLevel == jlptLevel).length;
|
.where((e) => e.jlptLevel == jlptLevel)
|
||||||
final totalWordCount =
|
.length;
|
||||||
rankedWords.where((e) => e.jlptLevel == jlptLevel).length;
|
final totalWordCount = rankedWords
|
||||||
|
.where((e) => e.jlptLevel == jlptLevel)
|
||||||
|
.length;
|
||||||
|
|
||||||
final failureRate =
|
final failureRate = ((missingWordCount / totalWordCount) * 100)
|
||||||
((missingWordCount / totalWordCount) * 100).toStringAsFixed(2);
|
.toStringAsFixed(2);
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'${jlptLevel} failures: [${missingWordCount}/${totalWordCount}] (${failureRate}%)');
|
'$jlptLevel failures: [$missingWordCount/$totalWordCount] ($failureRate%)',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Not able to determine the entry for ${missingWords.length} words');
|
print('Not able to determine the entry for ${missingWords.length} words');
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
// import 'dart:io';
|
// import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
// import 'package:jadb/_data_ingestion/open_local_db.dart';
|
// import 'package:jadb/_data_ingestion/open_local_db.dart';
|
||||||
import 'package:jadb/cli/args.dart';
|
import 'package:jadb/cli/args.dart';
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
|
||||||
import 'package:jadb/util/lemmatizer/lemmatizer.dart';
|
import 'package:jadb/util/lemmatizer/lemmatizer.dart';
|
||||||
|
|
||||||
class Lemmatize extends Command {
|
class Lemmatize extends Command {
|
||||||
final name = "lemmatize";
|
@override
|
||||||
final description = "Lemmatize a word using the Jadb lemmatizer";
|
final name = 'lemmatize';
|
||||||
|
@override
|
||||||
|
final description = 'Lemmatize a word using the Jadb lemmatizer';
|
||||||
|
|
||||||
Lemmatize() {
|
Lemmatize() {
|
||||||
addLibsqliteArg(argParser);
|
addLibsqliteArg(argParser);
|
||||||
@@ -21,6 +22,7 @@ class Lemmatize extends Command {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
// if (argResults!.option('libsqlite') == null ||
|
// if (argResults!.option('libsqlite') == null ||
|
||||||
// argResults!.option('jadb') == null) {
|
// argResults!.option('jadb') == null) {
|
||||||
@@ -41,6 +43,6 @@ class Lemmatize extends Command {
|
|||||||
|
|
||||||
print(result.toString());
|
print(result.toString());
|
||||||
|
|
||||||
print("Lemmatization took ${time.elapsedMilliseconds}ms");
|
print('Lemmatization took ${time.elapsedMilliseconds}ms');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
||||||
import 'package:jadb/cli/args.dart';
|
import 'package:jadb/cli/args.dart';
|
||||||
import 'package:jadb/search.dart';
|
import 'package:jadb/search.dart';
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
|
||||||
|
|
||||||
class QueryKanji extends Command {
|
class QueryKanji extends Command {
|
||||||
final name = "query-kanji";
|
@override
|
||||||
final description = "Query the database for kanji data";
|
final name = 'query-kanji';
|
||||||
|
@override
|
||||||
|
final description = 'Query the database for kanji data';
|
||||||
|
@override
|
||||||
|
final invocation = 'jadb query-kanji [options] <kanji>';
|
||||||
|
|
||||||
QueryKanji() {
|
QueryKanji() {
|
||||||
addLibsqliteArg(argParser);
|
addLibsqliteArg(argParser);
|
||||||
addJadbArg(argParser);
|
addJadbArg(argParser);
|
||||||
argParser.addOption(
|
|
||||||
'kanji',
|
|
||||||
abbr: 'k',
|
|
||||||
help: 'The kanji to search for.',
|
|
||||||
valueHelp: 'KANJI',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
if (argResults!.option('libsqlite') == null ||
|
if (argResults!.option('libsqlite') == null ||
|
||||||
argResults!.option('jadb') == null) {
|
argResults!.option('jadb') == null) {
|
||||||
@@ -34,18 +32,25 @@ class QueryKanji extends Command {
|
|||||||
libsqlitePath: argResults!.option('libsqlite')!,
|
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 time = Stopwatch()..start();
|
||||||
final result = await JaDBConnection(db).jadbSearchKanji(
|
final result = await JaDBConnection(db).jadbSearchKanji(kanji);
|
||||||
argResults!.option('kanji') ?? '漢',
|
|
||||||
);
|
|
||||||
time.stop();
|
time.stop();
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
print("No such kanji");
|
print('No such kanji');
|
||||||
} else {
|
} else {
|
||||||
print(JsonEncoder.withIndent(' ').convert(result.toJson()));
|
print(JsonEncoder.withIndent(' ').convert(result.toJson()));
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Query took ${time.elapsedMilliseconds}ms");
|
print('Query took ${time.elapsedMilliseconds}ms');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,38 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
import 'package:jadb/_data_ingestion/open_local_db.dart';
|
||||||
import 'package:jadb/cli/args.dart';
|
import 'package:jadb/cli/args.dart';
|
||||||
import 'package:jadb/search.dart';
|
import 'package:jadb/search.dart';
|
||||||
|
import 'package:sqflite_common/sqflite.dart';
|
||||||
import 'package:args/command_runner.dart';
|
|
||||||
|
|
||||||
class QueryWord extends Command {
|
class QueryWord extends Command {
|
||||||
final name = "query-word";
|
@override
|
||||||
final description = "Query the database for word data";
|
final name = 'query-word';
|
||||||
|
@override
|
||||||
|
final description = 'Query the database for word data';
|
||||||
|
@override
|
||||||
|
final invocation = 'jadb query-word [options] (<word> | <ID>)';
|
||||||
|
|
||||||
QueryWord() {
|
QueryWord() {
|
||||||
addLibsqliteArg(argParser);
|
addLibsqliteArg(argParser);
|
||||||
addJadbArg(argParser);
|
addJadbArg(argParser);
|
||||||
argParser.addOption(
|
|
||||||
'word',
|
argParser.addFlag('json', abbr: 'j', help: 'Output results in JSON format');
|
||||||
abbr: 'w',
|
|
||||||
help: 'The word to search for.',
|
argParser.addOption('page', abbr: 'p', valueHelp: 'NUM', defaultsTo: '0');
|
||||||
valueHelp: 'WORD',
|
|
||||||
);
|
argParser.addOption('pageSize', valueHelp: 'NUM', defaultsTo: '30');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
if (argResults!.option('libsqlite') == null ||
|
if (argResults!.option('libsqlite') == null ||
|
||||||
argResults!.option('jadb') == null) {
|
argResults!.option('jadb') == null) {
|
||||||
print(argParser.usage);
|
print('You need to provide both libsqlite and jadb paths.');
|
||||||
|
print('');
|
||||||
|
printUsage();
|
||||||
exit(64);
|
exit(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,29 +41,81 @@ class QueryWord extends Command {
|
|||||||
libsqlitePath: argResults!.option('libsqlite')!,
|
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, argResults!.flag('json'));
|
||||||
|
} else {
|
||||||
|
await _searchWord(
|
||||||
|
db,
|
||||||
|
searchWord,
|
||||||
|
argResults!.flag('json'),
|
||||||
|
int.parse(argResults!.option('page')!),
|
||||||
|
int.parse(argResults!.option('pageSize')!),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _searchId(DatabaseExecutor db, int id, bool jsonOutput) async {
|
||||||
|
final time = Stopwatch()..start();
|
||||||
|
final result = await JaDBConnection(db).jadbGetWordById(id);
|
||||||
|
time.stop();
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
print('Invalid ID');
|
||||||
|
} else {
|
||||||
|
if (jsonOutput) {
|
||||||
|
print(JsonEncoder.withIndent(' ').convert(result));
|
||||||
|
} else {
|
||||||
|
print(result.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Query took ${time.elapsedMilliseconds}ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _searchWord(
|
||||||
|
DatabaseExecutor db,
|
||||||
|
String searchWord,
|
||||||
|
bool jsonOutput,
|
||||||
|
int page,
|
||||||
|
int pageSize,
|
||||||
|
) async {
|
||||||
final time = Stopwatch()..start();
|
final time = Stopwatch()..start();
|
||||||
final count = await JaDBConnection(db).jadbSearchWordCount(searchWord);
|
final count = await JaDBConnection(db).jadbSearchWordCount(searchWord);
|
||||||
time.stop();
|
time.stop();
|
||||||
|
|
||||||
final time2 = Stopwatch()..start();
|
final time2 = Stopwatch()..start();
|
||||||
final result = await JaDBConnection(db).jadbSearchWord(searchWord);
|
final result = await JaDBConnection(
|
||||||
|
db,
|
||||||
|
).jadbSearchWord(searchWord, page: page, pageSize: pageSize);
|
||||||
time2.stop();
|
time2.stop();
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
print("Invalid search");
|
print('Invalid search');
|
||||||
} else if (result.isEmpty) {
|
} else if (result.isEmpty) {
|
||||||
print("No matches");
|
print('No matches');
|
||||||
} else {
|
} else {
|
||||||
for (final e in result) {
|
if (jsonOutput) {
|
||||||
print(e.toString());
|
print(JsonEncoder.withIndent(' ').convert(result));
|
||||||
print("");
|
} else {
|
||||||
|
for (final e in result) {
|
||||||
|
print(e.toString());
|
||||||
|
print('');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Total count: ${count}");
|
print('Total count: $count');
|
||||||
print("Count query took ${time.elapsedMilliseconds}ms");
|
print('Count query took ${time.elapsedMilliseconds}ms');
|
||||||
print("Query took ${time2.elapsedMilliseconds}ms");
|
print('Query took ${time2.elapsedMilliseconds}ms');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// Jouyou kanji sorted primarily by grades and secondarily by strokes.
|
/// Jouyou kanji sorted primarily by grades and secondarily by strokes.
|
||||||
const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
const Map<int, Map<int, List<String>>>
|
||||||
{
|
JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT = {
|
||||||
1: {
|
1: {
|
||||||
1: ['一'],
|
1: ['一'],
|
||||||
2: ['力', '八', '入', '二', '人', '十', '七', '九'],
|
2: ['力', '八', '入', '二', '人', '十', '七', '九'],
|
||||||
@@ -12,7 +12,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
8: ['林', '青', '空', '金', '学', '雨'],
|
8: ['林', '青', '空', '金', '学', '雨'],
|
||||||
9: ['草', '音'],
|
9: ['草', '音'],
|
||||||
10: ['校'],
|
10: ['校'],
|
||||||
12: ['森']
|
12: ['森'],
|
||||||
},
|
},
|
||||||
2: {
|
2: {
|
||||||
2: ['刀'],
|
2: ['刀'],
|
||||||
@@ -35,7 +35,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'戸',
|
'戸',
|
||||||
'元',
|
'元',
|
||||||
'牛',
|
'牛',
|
||||||
'引'
|
'引',
|
||||||
],
|
],
|
||||||
5: ['用', '北', '母', '半', '冬', '台', '矢', '市', '広', '古', '兄', '外'],
|
5: ['用', '北', '母', '半', '冬', '台', '矢', '市', '広', '古', '兄', '外'],
|
||||||
6: [
|
6: [
|
||||||
@@ -58,7 +58,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'交',
|
'交',
|
||||||
'会',
|
'会',
|
||||||
'回',
|
'回',
|
||||||
'羽'
|
'羽',
|
||||||
],
|
],
|
||||||
7: [
|
7: [
|
||||||
'里',
|
'里',
|
||||||
@@ -78,7 +78,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'近',
|
'近',
|
||||||
'汽',
|
'汽',
|
||||||
'角',
|
'角',
|
||||||
'何'
|
'何',
|
||||||
],
|
],
|
||||||
8: [
|
8: [
|
||||||
'夜',
|
'夜',
|
||||||
@@ -95,7 +95,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'国',
|
'国',
|
||||||
'京',
|
'京',
|
||||||
'岩',
|
'岩',
|
||||||
'画'
|
'画',
|
||||||
],
|
],
|
||||||
9: [
|
9: [
|
||||||
'風',
|
'風',
|
||||||
@@ -115,7 +115,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'計',
|
'計',
|
||||||
'活',
|
'活',
|
||||||
'海',
|
'海',
|
||||||
'科'
|
'科',
|
||||||
],
|
],
|
||||||
10: ['馬', '通', '書', '弱', '時', '紙', '高', '原', '帰', '記', '家', '夏'],
|
10: ['馬', '通', '書', '弱', '時', '紙', '高', '原', '帰', '記', '家', '夏'],
|
||||||
11: ['理', '野', '鳥', '組', '船', '雪', '週', '細', '黒', '黄', '教', '強', '魚'],
|
11: ['理', '野', '鳥', '組', '船', '雪', '週', '細', '黒', '黄', '教', '強', '魚'],
|
||||||
@@ -124,7 +124,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
14: ['鳴', '聞', '読', '算', '語', '歌'],
|
14: ['鳴', '聞', '読', '算', '語', '歌'],
|
||||||
15: ['線'],
|
15: ['線'],
|
||||||
16: ['頭', '親'],
|
16: ['頭', '親'],
|
||||||
18: ['曜', '顔']
|
18: ['曜', '顔'],
|
||||||
},
|
},
|
||||||
3: {
|
3: {
|
||||||
2: ['丁'],
|
2: ['丁'],
|
||||||
@@ -146,7 +146,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'皿',
|
'皿',
|
||||||
'号',
|
'号',
|
||||||
'去',
|
'去',
|
||||||
'央'
|
'央',
|
||||||
],
|
],
|
||||||
6: ['列', '両', '羊', '有', '全', '州', '守', '式', '次', '死', '向', '血', '曲', '安'],
|
6: ['列', '両', '羊', '有', '全', '州', '守', '式', '次', '死', '向', '血', '曲', '安'],
|
||||||
7: ['役', '返', '坂', '豆', '投', '対', '身', '助', '住', '決', '君', '局', '究', '医'],
|
7: ['役', '返', '坂', '豆', '投', '対', '身', '助', '住', '決', '君', '局', '究', '医'],
|
||||||
@@ -178,7 +178,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'岸',
|
'岸',
|
||||||
'泳',
|
'泳',
|
||||||
'育',
|
'育',
|
||||||
'委'
|
'委',
|
||||||
],
|
],
|
||||||
9: [
|
9: [
|
||||||
'洋',
|
'洋',
|
||||||
@@ -210,7 +210,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'急',
|
'急',
|
||||||
'客',
|
'客',
|
||||||
'界',
|
'界',
|
||||||
'屋'
|
'屋',
|
||||||
],
|
],
|
||||||
10: [
|
10: [
|
||||||
'旅',
|
'旅',
|
||||||
@@ -232,7 +232,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'起',
|
'起',
|
||||||
'荷',
|
'荷',
|
||||||
'院',
|
'院',
|
||||||
'員'
|
'員',
|
||||||
],
|
],
|
||||||
11: [
|
11: [
|
||||||
'問',
|
'問',
|
||||||
@@ -253,7 +253,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'終',
|
'終',
|
||||||
'祭',
|
'祭',
|
||||||
'球',
|
'球',
|
||||||
'悪'
|
'悪',
|
||||||
],
|
],
|
||||||
12: [
|
12: [
|
||||||
'落',
|
'落',
|
||||||
@@ -282,13 +282,13 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'開',
|
'開',
|
||||||
'温',
|
'温',
|
||||||
'運',
|
'運',
|
||||||
'飲'
|
'飲',
|
||||||
],
|
],
|
||||||
13: ['路', '福', '農', '鉄', '想', '詩', '業', '漢', '感', '意', '暗'],
|
13: ['路', '福', '農', '鉄', '想', '詩', '業', '漢', '感', '意', '暗'],
|
||||||
14: ['練', '緑', '様', '鼻', '銀', '駅'],
|
14: ['練', '緑', '様', '鼻', '銀', '駅'],
|
||||||
15: ['箱', '調', '談', '横'],
|
15: ['箱', '調', '談', '横'],
|
||||||
16: ['薬', '整', '橋', '館'],
|
16: ['薬', '整', '橋', '館'],
|
||||||
18: ['題']
|
18: ['題'],
|
||||||
},
|
},
|
||||||
4: {
|
4: {
|
||||||
4: ['夫', '不', '井', '氏', '欠'],
|
4: ['夫', '不', '井', '氏', '欠'],
|
||||||
@@ -318,7 +318,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'岐',
|
'岐',
|
||||||
'完',
|
'完',
|
||||||
'改',
|
'改',
|
||||||
'位'
|
'位',
|
||||||
],
|
],
|
||||||
8: [
|
8: [
|
||||||
'例',
|
'例',
|
||||||
@@ -346,7 +346,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'芽',
|
'芽',
|
||||||
'果',
|
'果',
|
||||||
'岡',
|
'岡',
|
||||||
'英'
|
'英',
|
||||||
],
|
],
|
||||||
9: [
|
9: [
|
||||||
'要',
|
'要',
|
||||||
@@ -367,7 +367,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'建',
|
'建',
|
||||||
'軍',
|
'軍',
|
||||||
'栄',
|
'栄',
|
||||||
'茨'
|
'茨',
|
||||||
],
|
],
|
||||||
10: [
|
10: [
|
||||||
'連',
|
'連',
|
||||||
@@ -389,7 +389,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'訓',
|
'訓',
|
||||||
'挙',
|
'挙',
|
||||||
'害',
|
'害',
|
||||||
'案'
|
'案',
|
||||||
],
|
],
|
||||||
11: [
|
11: [
|
||||||
'陸',
|
'陸',
|
||||||
@@ -410,7 +410,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'康',
|
'康',
|
||||||
'健',
|
'健',
|
||||||
'械',
|
'械',
|
||||||
'貨'
|
'貨',
|
||||||
],
|
],
|
||||||
12: [
|
12: [
|
||||||
'量',
|
'量',
|
||||||
@@ -434,7 +434,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'覚',
|
'覚',
|
||||||
'街',
|
'街',
|
||||||
'賀',
|
'賀',
|
||||||
'媛'
|
'媛',
|
||||||
],
|
],
|
||||||
13: ['働', '置', '続', '戦', '節', '照', '辞', '試', '群', '塩', '愛'],
|
13: ['働', '置', '続', '戦', '節', '照', '辞', '試', '群', '塩', '愛'],
|
||||||
14: ['徳', '説', '静', '種', '察', '熊', '漁', '旗', '関', '管'],
|
14: ['徳', '説', '静', '種', '察', '熊', '漁', '旗', '関', '管'],
|
||||||
@@ -442,7 +442,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
16: ['録', '積', '機'],
|
16: ['録', '積', '機'],
|
||||||
18: ['類', '験', '観'],
|
18: ['類', '験', '観'],
|
||||||
19: ['鏡', '願'],
|
19: ['鏡', '願'],
|
||||||
20: ['競', '議']
|
20: ['競', '議'],
|
||||||
},
|
},
|
||||||
5: {
|
5: {
|
||||||
3: ['士', '久'],
|
3: ['士', '久'],
|
||||||
@@ -464,7 +464,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'技',
|
'技',
|
||||||
'快',
|
'快',
|
||||||
'応',
|
'応',
|
||||||
'囲'
|
'囲',
|
||||||
],
|
],
|
||||||
8: [
|
8: [
|
||||||
'武',
|
'武',
|
||||||
@@ -484,7 +484,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'河',
|
'河',
|
||||||
'価',
|
'価',
|
||||||
'往',
|
'往',
|
||||||
'易'
|
'易',
|
||||||
],
|
],
|
||||||
9: ['迷', '保', '独', '則', '祖', '政', '査', '厚', '故', '限', '型', '逆', '紀'],
|
9: ['迷', '保', '独', '則', '祖', '政', '査', '厚', '故', '限', '型', '逆', '紀'],
|
||||||
10: [
|
10: [
|
||||||
@@ -505,7 +505,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'個',
|
'個',
|
||||||
'格',
|
'格',
|
||||||
'桜',
|
'桜',
|
||||||
'益'
|
'益',
|
||||||
],
|
],
|
||||||
11: [
|
11: [
|
||||||
'略',
|
'略',
|
||||||
@@ -537,7 +537,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'基',
|
'基',
|
||||||
'眼',
|
'眼',
|
||||||
'液',
|
'液',
|
||||||
'移'
|
'移',
|
||||||
],
|
],
|
||||||
12: [
|
12: [
|
||||||
'貿',
|
'貿',
|
||||||
@@ -561,7 +561,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'検',
|
'検',
|
||||||
'喜',
|
'喜',
|
||||||
'過',
|
'過',
|
||||||
'営'
|
'営',
|
||||||
],
|
],
|
||||||
13: ['夢', '豊', '墓', '損', '勢', '準', '飼', '資', '罪', '鉱', '禁', '義', '幹', '解'],
|
13: ['夢', '豊', '墓', '損', '勢', '準', '飼', '資', '罪', '鉱', '禁', '義', '幹', '解'],
|
||||||
14: [
|
14: [
|
||||||
@@ -583,14 +583,14 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'構',
|
'構',
|
||||||
'境',
|
'境',
|
||||||
'慣',
|
'慣',
|
||||||
'演'
|
'演',
|
||||||
],
|
],
|
||||||
15: ['暴', '編', '導', '賞', '質', '賛', '潔', '確'],
|
15: ['暴', '編', '導', '賞', '質', '賛', '潔', '確'],
|
||||||
16: ['輸', '燃', '築', '興', '衛'],
|
16: ['輸', '燃', '築', '興', '衛'],
|
||||||
17: ['績', '謝', '講'],
|
17: ['績', '謝', '講'],
|
||||||
18: ['職', '織', '額'],
|
18: ['職', '織', '額'],
|
||||||
19: ['識'],
|
19: ['識'],
|
||||||
20: ['護']
|
20: ['護'],
|
||||||
},
|
},
|
||||||
6: {
|
6: {
|
||||||
3: ['亡', '寸', '己', '干'],
|
3: ['亡', '寸', '己', '干'],
|
||||||
@@ -618,7 +618,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'供',
|
'供',
|
||||||
'拡',
|
'拡',
|
||||||
'沿',
|
'沿',
|
||||||
'延'
|
'延',
|
||||||
],
|
],
|
||||||
9: [
|
9: [
|
||||||
'律',
|
'律',
|
||||||
@@ -641,7 +641,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'巻',
|
'巻',
|
||||||
'革',
|
'革',
|
||||||
'映',
|
'映',
|
||||||
'胃'
|
'胃',
|
||||||
],
|
],
|
||||||
10: [
|
10: [
|
||||||
'朗',
|
'朗',
|
||||||
@@ -667,7 +667,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'降',
|
'降',
|
||||||
'胸',
|
'胸',
|
||||||
'株',
|
'株',
|
||||||
'恩'
|
'恩',
|
||||||
],
|
],
|
||||||
11: [
|
11: [
|
||||||
'翌',
|
'翌',
|
||||||
@@ -689,7 +689,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'済',
|
'済',
|
||||||
'郷',
|
'郷',
|
||||||
'域',
|
'域',
|
||||||
'異'
|
'異',
|
||||||
],
|
],
|
||||||
12: [
|
12: [
|
||||||
'棒',
|
'棒',
|
||||||
@@ -710,7 +710,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'勤',
|
'勤',
|
||||||
'貴',
|
'貴',
|
||||||
'揮',
|
'揮',
|
||||||
'割'
|
'割',
|
||||||
],
|
],
|
||||||
13: [
|
13: [
|
||||||
'裏',
|
'裏',
|
||||||
@@ -727,14 +727,14 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'傷',
|
'傷',
|
||||||
'署',
|
'署',
|
||||||
'源',
|
'源',
|
||||||
'絹'
|
'絹',
|
||||||
],
|
],
|
||||||
14: ['模', '暮', '認', '層', '銭', '障', '磁', '誌', '穀', '誤', '疑', '閣'],
|
14: ['模', '暮', '認', '層', '銭', '障', '磁', '誌', '穀', '誤', '疑', '閣'],
|
||||||
15: ['論', '敵', '潮', '誕', '蔵', '諸', '熟', '権', '劇', '遺'],
|
15: ['論', '敵', '潮', '誕', '蔵', '諸', '熟', '権', '劇', '遺'],
|
||||||
16: ['奮', '糖', '操', '縦', '樹', '鋼', '憲', '激'],
|
16: ['奮', '糖', '操', '縦', '樹', '鋼', '憲', '激'],
|
||||||
17: ['覧', '優', '縮', '厳'],
|
17: ['覧', '優', '縮', '厳'],
|
||||||
18: ['臨', '難', '簡'],
|
18: ['臨', '難', '簡'],
|
||||||
19: ['臓', '警']
|
19: ['臓', '警'],
|
||||||
},
|
},
|
||||||
7: {
|
7: {
|
||||||
1: ['乙'],
|
1: ['乙'],
|
||||||
@@ -760,7 +760,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'斤',
|
'斤',
|
||||||
'凶',
|
'凶',
|
||||||
'刈',
|
'刈',
|
||||||
'介'
|
'介',
|
||||||
],
|
],
|
||||||
5: [
|
5: [
|
||||||
'矛',
|
'矛',
|
||||||
@@ -790,7 +790,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'且',
|
'且',
|
||||||
'瓦',
|
'瓦',
|
||||||
'牙',
|
'牙',
|
||||||
'凹'
|
'凹',
|
||||||
],
|
],
|
||||||
6: [
|
6: [
|
||||||
'劣',
|
'劣',
|
||||||
@@ -831,7 +831,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'汗',
|
'汗',
|
||||||
'汚',
|
'汚',
|
||||||
'芋',
|
'芋',
|
||||||
'扱'
|
'扱',
|
||||||
],
|
],
|
||||||
7: [
|
7: [
|
||||||
'弄',
|
'弄',
|
||||||
@@ -896,7 +896,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'肝',
|
'肝',
|
||||||
'戒',
|
'戒',
|
||||||
'壱',
|
'壱',
|
||||||
'亜'
|
'亜',
|
||||||
],
|
],
|
||||||
8: [
|
8: [
|
||||||
'枠',
|
'枠',
|
||||||
@@ -989,7 +989,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'押',
|
'押',
|
||||||
'炎',
|
'炎',
|
||||||
'依',
|
'依',
|
||||||
'宛'
|
'宛',
|
||||||
],
|
],
|
||||||
9: [
|
9: [
|
||||||
'郎',
|
'郎',
|
||||||
@@ -1081,7 +1081,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'畏',
|
'畏',
|
||||||
'為',
|
'為',
|
||||||
'威',
|
'威',
|
||||||
'哀'
|
'哀',
|
||||||
],
|
],
|
||||||
10: [
|
10: [
|
||||||
'脇',
|
'脇',
|
||||||
@@ -1206,7 +1206,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'浦',
|
'浦',
|
||||||
'畝',
|
'畝',
|
||||||
'唄',
|
'唄',
|
||||||
'挨'
|
'挨',
|
||||||
],
|
],
|
||||||
11: [
|
11: [
|
||||||
'累',
|
'累',
|
||||||
@@ -1323,7 +1323,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'淫',
|
'淫',
|
||||||
'逸',
|
'逸',
|
||||||
'萎',
|
'萎',
|
||||||
'尉'
|
'尉',
|
||||||
],
|
],
|
||||||
12: [
|
12: [
|
||||||
'腕',
|
'腕',
|
||||||
@@ -1435,7 +1435,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'椅',
|
'椅',
|
||||||
'偉',
|
'偉',
|
||||||
'嵐',
|
'嵐',
|
||||||
'握'
|
'握',
|
||||||
],
|
],
|
||||||
13: [
|
13: [
|
||||||
'賄',
|
'賄',
|
||||||
@@ -1552,7 +1552,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'猿',
|
'猿',
|
||||||
'煙',
|
'煙',
|
||||||
'違',
|
'違',
|
||||||
'彙'
|
'彙',
|
||||||
],
|
],
|
||||||
14: [
|
14: [
|
||||||
'漏',
|
'漏',
|
||||||
@@ -1617,7 +1617,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'箇',
|
'箇',
|
||||||
'寡',
|
'寡',
|
||||||
'隠',
|
'隠',
|
||||||
'維'
|
'維',
|
||||||
],
|
],
|
||||||
15: [
|
15: [
|
||||||
'霊',
|
'霊',
|
||||||
@@ -1706,7 +1706,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'謁',
|
'謁',
|
||||||
'鋭',
|
'鋭',
|
||||||
'影',
|
'影',
|
||||||
'慰'
|
'慰',
|
||||||
],
|
],
|
||||||
16: [
|
16: [
|
||||||
'錬',
|
'錬',
|
||||||
@@ -1764,7 +1764,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'壊',
|
'壊',
|
||||||
'穏',
|
'穏',
|
||||||
'憶',
|
'憶',
|
||||||
'緯'
|
'緯',
|
||||||
],
|
],
|
||||||
17: [
|
17: [
|
||||||
'齢',
|
'齢',
|
||||||
@@ -1801,7 +1801,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'轄',
|
'轄',
|
||||||
'嚇',
|
'嚇',
|
||||||
'臆',
|
'臆',
|
||||||
'曖'
|
'曖',
|
||||||
],
|
],
|
||||||
18: [
|
18: [
|
||||||
'糧',
|
'糧',
|
||||||
@@ -1830,7 +1830,7 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'韓',
|
'韓',
|
||||||
'鎌',
|
'鎌',
|
||||||
'顎',
|
'顎',
|
||||||
'穫'
|
'穫',
|
||||||
],
|
],
|
||||||
19: [
|
19: [
|
||||||
'麓',
|
'麓',
|
||||||
@@ -1851,13 +1851,13 @@ const Map<int, Map<int, List<String>>> JOUYOU_KANJI_BY_GRADE_AND_STROKE_COUNT =
|
|||||||
'鶏',
|
'鶏',
|
||||||
'繰',
|
'繰',
|
||||||
'艶',
|
'艶',
|
||||||
'韻'
|
'韻',
|
||||||
],
|
],
|
||||||
20: ['欄', '騰', '籍', '醸', '譲', '鐘', '懸', '響'],
|
20: ['欄', '騰', '籍', '醸', '譲', '鐘', '懸', '響'],
|
||||||
21: ['露', '躍', '魔', '鶴', '顧', '艦'],
|
21: ['露', '躍', '魔', '鶴', '顧', '艦'],
|
||||||
22: ['籠', '襲', '驚'],
|
22: ['籠', '襲', '驚'],
|
||||||
23: ['鑑'],
|
23: ['鑑'],
|
||||||
29: ['鬱']
|
29: ['鬱'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1866,7 +1866,8 @@ final Map<int, List<String>> JOUYOU_KANJI_BY_GRADES =
|
|||||||
.expand((entry) => entry.value.entries)
|
.expand((entry) => entry.value.entries)
|
||||||
.map((entry) => MapEntry(entry.key, entry.value))
|
.map((entry) => MapEntry(entry.key, entry.value))
|
||||||
.fold<Map<int, List<String>>>(
|
.fold<Map<int, List<String>>>(
|
||||||
{},
|
{},
|
||||||
(acc, entry) => acc
|
(acc, entry) => acc
|
||||||
..putIfAbsent(entry.key, () => [])
|
..putIfAbsent(entry.key, () => [])
|
||||||
..update(entry.key, (value) => value..addAll(entry.value)));
|
..update(entry.key, (value) => value..addAll(entry.value)),
|
||||||
|
);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'九',
|
'九',
|
||||||
'ユ',
|
'ユ',
|
||||||
'乃',
|
'乃',
|
||||||
'𠂉'
|
'𠂉',
|
||||||
],
|
],
|
||||||
3: [
|
3: [
|
||||||
'⻌',
|
'⻌',
|
||||||
@@ -78,7 +78,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'也',
|
'也',
|
||||||
'亡',
|
'亡',
|
||||||
'及',
|
'及',
|
||||||
'久'
|
'久',
|
||||||
],
|
],
|
||||||
4: [
|
4: [
|
||||||
'⺹',
|
'⺹',
|
||||||
@@ -124,7 +124,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'五',
|
'五',
|
||||||
'屯',
|
'屯',
|
||||||
'巴',
|
'巴',
|
||||||
'毋'
|
'毋',
|
||||||
],
|
],
|
||||||
5: [
|
5: [
|
||||||
'玄',
|
'玄',
|
||||||
@@ -154,7 +154,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'冊',
|
'冊',
|
||||||
'母',
|
'母',
|
||||||
'⺲',
|
'⺲',
|
||||||
'牙'
|
'牙',
|
||||||
],
|
],
|
||||||
6: [
|
6: [
|
||||||
'瓜',
|
'瓜',
|
||||||
@@ -181,7 +181,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'血',
|
'血',
|
||||||
'行',
|
'行',
|
||||||
'衣',
|
'衣',
|
||||||
'西'
|
'西',
|
||||||
],
|
],
|
||||||
7: [
|
7: [
|
||||||
'臣',
|
'臣',
|
||||||
@@ -204,7 +204,7 @@ const Map<int, List<String>> RADICALS = {
|
|||||||
'釆',
|
'釆',
|
||||||
'里',
|
'里',
|
||||||
'舛',
|
'舛',
|
||||||
'麦'
|
'麦',
|
||||||
],
|
],
|
||||||
8: ['金', '長', '門', '隶', '隹', '雨', '青', '非', '奄', '岡', '免', '斉'],
|
8: ['金', '長', '門', '隶', '隹', '雨', '青', '非', '奄', '岡', '免', '斉'],
|
||||||
9: ['面', '革', '韭', '音', '頁', '風', '飛', '食', '首', '香', '品'],
|
9: ['面', '革', '韭', '音', '頁', '風', '飛', '食', '首', '香', '品'],
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ enum JlptLevel implements Comparable<JlptLevel> {
|
|||||||
int? get asInt =>
|
int? get asInt =>
|
||||||
this == JlptLevel.none ? null : JlptLevel.values.indexOf(this);
|
this == JlptLevel.none ? null : JlptLevel.values.indexOf(this);
|
||||||
|
|
||||||
|
@override
|
||||||
String toString() => toNullableString() ?? 'N/A';
|
String toString() => toNullableString() ?? 'N/A';
|
||||||
|
|
||||||
Object? toJson() => toNullableString();
|
Object? toJson() => toNullableString();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ String migrationDirPath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createEmptyDb(DatabaseExecutor db) async {
|
Future<void> createEmptyDb(DatabaseExecutor db) async {
|
||||||
List<String> migrationFiles = [];
|
final List<String> migrationFiles = [];
|
||||||
for (final file in Directory(migrationDirPath()).listSync()) {
|
for (final file in Directory(migrationDirPath()).listSync()) {
|
||||||
if (file is File && file.path.endsWith('.sql')) {
|
if (file is File && file.path.endsWith('.sql')) {
|
||||||
migrationFiles.add(file.path);
|
migrationFiles.add(file.path);
|
||||||
|
|||||||
@@ -19,20 +19,14 @@ enum JMdictDialect {
|
|||||||
final String id;
|
final String id;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
const JMdictDialect({
|
const JMdictDialect({required this.id, required this.description});
|
||||||
required this.id,
|
|
||||||
required this.description,
|
|
||||||
});
|
|
||||||
|
|
||||||
static JMdictDialect fromId(String id) => JMdictDialect.values.firstWhere(
|
static JMdictDialect fromId(String id) => JMdictDialect.values.firstWhere(
|
||||||
(e) => e.id == id,
|
(e) => e.id == id,
|
||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictDialect fromJson(Map<String, Object?> json) =>
|
static JMdictDialect fromJson(Map<String, Object?> json) =>
|
||||||
JMdictDialect.values.firstWhere(
|
JMdictDialect.values.firstWhere(
|
||||||
|
|||||||
@@ -102,20 +102,14 @@ enum JMdictField {
|
|||||||
final String id;
|
final String id;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
const JMdictField({
|
const JMdictField({required this.id, required this.description});
|
||||||
required this.id,
|
|
||||||
required this.description,
|
|
||||||
});
|
|
||||||
|
|
||||||
static JMdictField fromId(String id) => JMdictField.values.firstWhere(
|
static JMdictField fromId(String id) => JMdictField.values.firstWhere(
|
||||||
(e) => e.id == id,
|
(e) => e.id == id,
|
||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictField fromJson(Map<String, Object?> json) =>
|
static JMdictField fromJson(Map<String, Object?> json) =>
|
||||||
JMdictField.values.firstWhere(
|
JMdictField.values.firstWhere(
|
||||||
|
|||||||
@@ -13,20 +13,14 @@ enum JMdictKanjiInfo {
|
|||||||
final String id;
|
final String id;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
const JMdictKanjiInfo({
|
const JMdictKanjiInfo({required this.id, required this.description});
|
||||||
required this.id,
|
|
||||||
required this.description,
|
|
||||||
});
|
|
||||||
|
|
||||||
static JMdictKanjiInfo fromId(String id) => JMdictKanjiInfo.values.firstWhere(
|
static JMdictKanjiInfo fromId(String id) => JMdictKanjiInfo.values.firstWhere(
|
||||||
(e) => e.id == id,
|
(e) => e.id == id,
|
||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictKanjiInfo fromJson(Map<String, Object?> json) =>
|
static JMdictKanjiInfo fromJson(Map<String, Object?> json) =>
|
||||||
JMdictKanjiInfo.values.firstWhere(
|
JMdictKanjiInfo.values.firstWhere(
|
||||||
|
|||||||
@@ -74,20 +74,14 @@ enum JMdictMisc {
|
|||||||
final String id;
|
final String id;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
const JMdictMisc({
|
const JMdictMisc({required this.id, required this.description});
|
||||||
required this.id,
|
|
||||||
required this.description,
|
|
||||||
});
|
|
||||||
|
|
||||||
static JMdictMisc fromId(String id) => JMdictMisc.values.firstWhere(
|
static JMdictMisc fromId(String id) => JMdictMisc.values.firstWhere(
|
||||||
(e) => e.id == id,
|
(e) => e.id == id,
|
||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictMisc fromJson(Map<String, Object?> json) =>
|
static JMdictMisc fromJson(Map<String, Object?> json) =>
|
||||||
JMdictMisc.values.firstWhere(
|
JMdictMisc.values.firstWhere(
|
||||||
|
|||||||
@@ -202,14 +202,11 @@ enum JMdictPOS {
|
|||||||
String get shortDescription => _shortDescription ?? description;
|
String get shortDescription => _shortDescription ?? description;
|
||||||
|
|
||||||
static JMdictPOS fromId(String id) => JMdictPOS.values.firstWhere(
|
static JMdictPOS fromId(String id) => JMdictPOS.values.firstWhere(
|
||||||
(e) => e.id == id,
|
(e) => e.id == id,
|
||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictPOS fromJson(Map<String, Object?> json) =>
|
static JMdictPOS fromJson(Map<String, Object?> json) =>
|
||||||
JMdictPOS.values.firstWhere(
|
JMdictPOS.values.firstWhere(
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ enum JMdictReadingInfo {
|
|||||||
final String id;
|
final String id;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
const JMdictReadingInfo({
|
const JMdictReadingInfo({required this.id, required this.description});
|
||||||
required this.id,
|
|
||||||
required this.description,
|
|
||||||
});
|
|
||||||
|
|
||||||
static JMdictReadingInfo fromId(String id) =>
|
static JMdictReadingInfo fromId(String id) =>
|
||||||
JMdictReadingInfo.values.firstWhere(
|
JMdictReadingInfo.values.firstWhere(
|
||||||
@@ -26,10 +23,7 @@ enum JMdictReadingInfo {
|
|||||||
orElse: () => throw Exception('Unknown id: $id'),
|
orElse: () => throw Exception('Unknown id: $id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {'id': id, 'description': description};
|
||||||
'id': id,
|
|
||||||
'description': description,
|
|
||||||
};
|
|
||||||
|
|
||||||
static JMdictReadingInfo fromJson(Map<String, Object?> json) =>
|
static JMdictReadingInfo fromJson(Map<String, Object?> json) =>
|
||||||
JMdictReadingInfo.values.firstWhere(
|
JMdictReadingInfo.values.firstWhere(
|
||||||
|
|||||||
@@ -26,19 +26,14 @@ class KanjiSearchRadical extends Equatable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [
|
List<Object> get props => [symbol, names, forms, meanings];
|
||||||
symbol,
|
|
||||||
this.names,
|
|
||||||
forms,
|
|
||||||
meanings,
|
|
||||||
];
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'symbol': symbol,
|
'symbol': symbol,
|
||||||
'names': names,
|
'names': names,
|
||||||
'forms': forms,
|
'forms': forms,
|
||||||
'meanings': meanings,
|
'meanings': meanings,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory KanjiSearchRadical.fromJson(Map<String, dynamic> json) {
|
factory KanjiSearchRadical.fromJson(Map<String, dynamic> json) {
|
||||||
return KanjiSearchRadical(
|
return KanjiSearchRadical(
|
||||||
|
|||||||
@@ -89,46 +89,46 @@ class KanjiSearchResult extends Equatable {
|
|||||||
@override
|
@override
|
||||||
// ignore: public_member_api_docs
|
// ignore: public_member_api_docs
|
||||||
List<Object?> get props => [
|
List<Object?> get props => [
|
||||||
taughtIn,
|
taughtIn,
|
||||||
jlptLevel,
|
jlptLevel,
|
||||||
newspaperFrequencyRank,
|
newspaperFrequencyRank,
|
||||||
strokeCount,
|
strokeCount,
|
||||||
meanings,
|
meanings,
|
||||||
kunyomi,
|
kunyomi,
|
||||||
onyomi,
|
onyomi,
|
||||||
// kunyomiExamples,
|
// kunyomiExamples,
|
||||||
// onyomiExamples,
|
// onyomiExamples,
|
||||||
radical,
|
radical,
|
||||||
parts,
|
parts,
|
||||||
codepoints,
|
codepoints,
|
||||||
kanji,
|
kanji,
|
||||||
nanori,
|
nanori,
|
||||||
alternativeLanguageReadings,
|
alternativeLanguageReadings,
|
||||||
strokeMiscounts,
|
strokeMiscounts,
|
||||||
queryCodes,
|
queryCodes,
|
||||||
dictionaryReferences,
|
dictionaryReferences,
|
||||||
];
|
];
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'kanji': kanji,
|
'kanji': kanji,
|
||||||
'taughtIn': taughtIn,
|
'taughtIn': taughtIn,
|
||||||
'jlptLevel': jlptLevel,
|
'jlptLevel': jlptLevel,
|
||||||
'newspaperFrequencyRank': newspaperFrequencyRank,
|
'newspaperFrequencyRank': newspaperFrequencyRank,
|
||||||
'strokeCount': strokeCount,
|
'strokeCount': strokeCount,
|
||||||
'meanings': meanings,
|
'meanings': meanings,
|
||||||
'kunyomi': kunyomi,
|
'kunyomi': kunyomi,
|
||||||
'onyomi': onyomi,
|
'onyomi': onyomi,
|
||||||
// 'onyomiExamples': onyomiExamples,
|
// 'onyomiExamples': onyomiExamples,
|
||||||
// 'kunyomiExamples': kunyomiExamples,
|
// 'kunyomiExamples': kunyomiExamples,
|
||||||
'radical': radical?.toJson(),
|
'radical': radical?.toJson(),
|
||||||
'parts': parts,
|
'parts': parts,
|
||||||
'codepoints': codepoints,
|
'codepoints': codepoints,
|
||||||
'nanori': nanori,
|
'nanori': nanori,
|
||||||
'alternativeLanguageReadings': alternativeLanguageReadings,
|
'alternativeLanguageReadings': alternativeLanguageReadings,
|
||||||
'strokeMiscounts': strokeMiscounts,
|
'strokeMiscounts': strokeMiscounts,
|
||||||
'queryCodes': queryCodes,
|
'queryCodes': queryCodes,
|
||||||
'dictionaryReferences': dictionaryReferences,
|
'dictionaryReferences': dictionaryReferences,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory KanjiSearchResult.fromJson(Map<String, dynamic> json) {
|
factory KanjiSearchResult.fromJson(Map<String, dynamic> json) {
|
||||||
return KanjiSearchResult(
|
return KanjiSearchResult(
|
||||||
@@ -156,23 +156,20 @@ class KanjiSearchResult extends Equatable {
|
|||||||
nanori: (json['nanori'] as List).map((e) => e as String).toList(),
|
nanori: (json['nanori'] as List).map((e) => e as String).toList(),
|
||||||
alternativeLanguageReadings:
|
alternativeLanguageReadings:
|
||||||
(json['alternativeLanguageReadings'] as Map<String, dynamic>).map(
|
(json['alternativeLanguageReadings'] as Map<String, dynamic>).map(
|
||||||
(key, value) => MapEntry(
|
(key, value) =>
|
||||||
key,
|
MapEntry(key, (value as List).map((e) => e as String).toList()),
|
||||||
(value as List).map((e) => e as String).toList(),
|
),
|
||||||
),
|
strokeMiscounts: (json['strokeMiscounts'] as List)
|
||||||
),
|
.map((e) => e as int)
|
||||||
strokeMiscounts:
|
.toList(),
|
||||||
(json['strokeMiscounts'] as List).map((e) => e as int).toList(),
|
|
||||||
queryCodes: (json['queryCodes'] as Map<String, dynamic>).map(
|
queryCodes: (json['queryCodes'] as Map<String, dynamic>).map(
|
||||||
(key, value) => MapEntry(
|
(key, value) =>
|
||||||
key,
|
MapEntry(key, (value as List).map((e) => e as String).toList()),
|
||||||
(value as List).map((e) => e as String).toList(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
dictionaryReferences:
|
dictionaryReferences:
|
||||||
(json['dictionaryReferences'] as Map<String, dynamic>).map(
|
(json['dictionaryReferences'] as Map<String, dynamic>).map(
|
||||||
(key, value) => MapEntry(key, value as String),
|
(key, value) => MapEntry(key, value as String),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import 'package:sqflite_common/sqlite_api.dart';
|
|||||||
Future<void> verifyTablesWithDbConnection(DatabaseExecutor db) async {
|
Future<void> verifyTablesWithDbConnection(DatabaseExecutor db) async {
|
||||||
final Set<String> tables = await db
|
final Set<String> tables = await db
|
||||||
.query(
|
.query(
|
||||||
'sqlite_master',
|
'sqlite_master',
|
||||||
columns: ['name'],
|
columns: ['name'],
|
||||||
where: 'type = ?',
|
where: 'type = ?',
|
||||||
whereArgs: ['table'],
|
whereArgs: ['table'],
|
||||||
)
|
)
|
||||||
.then((result) {
|
.then((result) {
|
||||||
return result.map((row) => row['name'] as String).toSet();
|
return result.map((row) => row['name'] as String).toSet();
|
||||||
});
|
});
|
||||||
|
|
||||||
final Set<String> expectedTables = {
|
final Set<String> expectedTables = {
|
||||||
...JMdictTableNames.allTables,
|
...JMdictTableNames.allTables,
|
||||||
@@ -26,14 +26,16 @@ Future<void> verifyTablesWithDbConnection(DatabaseExecutor db) async {
|
|||||||
final missingTables = expectedTables.difference(tables);
|
final missingTables = expectedTables.difference(tables);
|
||||||
|
|
||||||
if (missingTables.isNotEmpty) {
|
if (missingTables.isNotEmpty) {
|
||||||
throw Exception([
|
throw Exception(
|
||||||
'Missing tables:',
|
[
|
||||||
missingTables.map((table) => ' - $table').join('\n'),
|
'Missing tables:',
|
||||||
'',
|
missingTables.map((table) => ' - $table').join('\n'),
|
||||||
'Found tables:\n',
|
'',
|
||||||
tables.map((table) => ' - $table').join('\n'),
|
'Found tables:\n',
|
||||||
'',
|
tables.map((table) => ' - $table').join('\n'),
|
||||||
'Please ensure the database is correctly set up.',
|
'',
|
||||||
].join('\n'));
|
'Please ensure the database is correctly set up.',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,18 +47,18 @@ class WordSearchResult {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'_score': score,
|
'_score': score,
|
||||||
'entryId': entryId,
|
'entryId': entryId,
|
||||||
'isCommon': isCommon,
|
'isCommon': isCommon,
|
||||||
'japanese': japanese.map((e) => e.toJson()).toList(),
|
'japanese': japanese.map((e) => e.toJson()).toList(),
|
||||||
'kanjiInfo':
|
'kanjiInfo': kanjiInfo.map((key, value) => MapEntry(key, value.toJson())),
|
||||||
kanjiInfo.map((key, value) => MapEntry(key, value.toJson())),
|
'readingInfo': readingInfo.map(
|
||||||
'readingInfo':
|
(key, value) => MapEntry(key, value.toJson()),
|
||||||
readingInfo.map((key, value) => MapEntry(key, value.toJson())),
|
),
|
||||||
'senses': senses.map((e) => e.toJson()).toList(),
|
'senses': senses.map((e) => e.toJson()).toList(),
|
||||||
'jlptLevel': jlptLevel.toJson(),
|
'jlptLevel': jlptLevel.toJson(),
|
||||||
'sources': sources.toJson(),
|
'sources': sources.toJson(),
|
||||||
};
|
};
|
||||||
|
|
||||||
factory WordSearchResult.fromJson(Map<String, dynamic> json) =>
|
factory WordSearchResult.fromJson(Map<String, dynamic> json) =>
|
||||||
WordSearchResult(
|
WordSearchResult(
|
||||||
@@ -82,16 +82,16 @@ class WordSearchResult {
|
|||||||
);
|
);
|
||||||
|
|
||||||
String _formatJapaneseWord(WordSearchRuby word) =>
|
String _formatJapaneseWord(WordSearchRuby word) =>
|
||||||
word.furigana == null ? word.base : "${word.base} (${word.furigana})";
|
word.furigana == null ? word.base : '${word.base} (${word.furigana})';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
final japaneseWord = _formatJapaneseWord(japanese[0]);
|
final japaneseWord = _formatJapaneseWord(japanese[0]);
|
||||||
final isCommonString = isCommon ? '(C)' : '';
|
final isCommonString = isCommon ? '(C)' : '';
|
||||||
final jlptLevelString = "(${jlptLevel.toString()})";
|
final jlptLevelString = '(${jlptLevel.toString()})';
|
||||||
|
|
||||||
return '''
|
return '''
|
||||||
${score} | [$entryId] $japaneseWord $isCommonString $jlptLevelString
|
$score | [$entryId] $japaneseWord $isCommonString $jlptLevelString
|
||||||
Other forms: ${japanese.skip(1).map(_formatJapaneseWord).join(', ')}
|
Other forms: ${japanese.skip(1).map(_formatJapaneseWord).join(', ')}
|
||||||
Senses: ${senses.map((s) => s.englishDefinitions).join(', ')}
|
Senses: ${senses.map((s) => s.englishDefinitions).join(', ')}
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -6,18 +6,12 @@ class WordSearchRuby {
|
|||||||
/// Furigana, if applicable.
|
/// Furigana, if applicable.
|
||||||
String? furigana;
|
String? furigana;
|
||||||
|
|
||||||
WordSearchRuby({
|
WordSearchRuby({required this.base, this.furigana});
|
||||||
required this.base,
|
|
||||||
this.furigana,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {'base': base, 'furigana': furigana};
|
||||||
'base': base,
|
|
||||||
'furigana': furigana,
|
|
||||||
};
|
|
||||||
|
|
||||||
factory WordSearchRuby.fromJson(Map<String, dynamic> json) => WordSearchRuby(
|
factory WordSearchRuby.fromJson(Map<String, dynamic> json) => WordSearchRuby(
|
||||||
base: json['base'] as String,
|
base: json['base'] as String,
|
||||||
furigana: json['furigana'] as String?,
|
furigana: json['furigana'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,18 +71,18 @@ class WordSearchSense {
|
|||||||
languageSource.isEmpty;
|
languageSource.isEmpty;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'englishDefinitions': englishDefinitions,
|
'englishDefinitions': englishDefinitions,
|
||||||
'partsOfSpeech': partsOfSpeech.map((e) => e.toJson()).toList(),
|
'partsOfSpeech': partsOfSpeech.map((e) => e.toJson()).toList(),
|
||||||
'seeAlso': seeAlso.map((e) => e.toJson()).toList(),
|
'seeAlso': seeAlso.map((e) => e.toJson()).toList(),
|
||||||
'antonyms': antonyms.map((e) => e.toJson()).toList(),
|
'antonyms': antonyms.map((e) => e.toJson()).toList(),
|
||||||
'restrictedToReading': restrictedToReading,
|
'restrictedToReading': restrictedToReading,
|
||||||
'restrictedToKanji': restrictedToKanji,
|
'restrictedToKanji': restrictedToKanji,
|
||||||
'fields': fields.map((e) => e.toJson()).toList(),
|
'fields': fields.map((e) => e.toJson()).toList(),
|
||||||
'dialects': dialects.map((e) => e.toJson()).toList(),
|
'dialects': dialects.map((e) => e.toJson()).toList(),
|
||||||
'misc': misc.map((e) => e.toJson()).toList(),
|
'misc': misc.map((e) => e.toJson()).toList(),
|
||||||
'info': info,
|
'info': info,
|
||||||
'languageSource': languageSource,
|
'languageSource': languageSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory WordSearchSense.fromJson(Map<String, dynamic> json) =>
|
factory WordSearchSense.fromJson(Map<String, dynamic> json) =>
|
||||||
WordSearchSense(
|
WordSearchSense(
|
||||||
@@ -104,8 +104,9 @@ class WordSearchSense {
|
|||||||
dialects: (json['dialects'] as List)
|
dialects: (json['dialects'] as List)
|
||||||
.map((e) => JMdictDialect.fromJson(e))
|
.map((e) => JMdictDialect.fromJson(e))
|
||||||
.toList(),
|
.toList(),
|
||||||
misc:
|
misc: (json['misc'] as List)
|
||||||
(json['misc'] as List).map((e) => JMdictMisc.fromJson(e)).toList(),
|
.map((e) => JMdictMisc.fromJson(e))
|
||||||
|
.toList(),
|
||||||
info: List<String>.from(json['info']),
|
info: List<String>.from(json['info']),
|
||||||
languageSource: (json['languageSource'] as List)
|
languageSource: (json['languageSource'] as List)
|
||||||
.map((e) => WordSearchSenseLanguageSource.fromJson(e))
|
.map((e) => WordSearchSenseLanguageSource.fromJson(e))
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ class WordSearchSenseLanguageSource {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Map<String, Object?> toJson() => {
|
Map<String, Object?> toJson() => {
|
||||||
'language': language,
|
'language': language,
|
||||||
'phrase': phrase,
|
'phrase': phrase,
|
||||||
'fullyDescribesSense': fullyDescribesSense,
|
'fullyDescribesSense': fullyDescribesSense,
|
||||||
'constructedFromSmallerWords': constructedFromSmallerWords,
|
'constructedFromSmallerWords': constructedFromSmallerWords,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory WordSearchSenseLanguageSource.fromJson(Map<String, dynamic> json) =>
|
factory WordSearchSenseLanguageSource.fromJson(Map<String, dynamic> json) =>
|
||||||
WordSearchSenseLanguageSource(
|
WordSearchSenseLanguageSource(
|
||||||
|
|||||||
@@ -7,20 +7,11 @@ class WordSearchSources {
|
|||||||
/// Whether JMnedict was used.
|
/// Whether JMnedict was used.
|
||||||
final bool jmnedict;
|
final bool jmnedict;
|
||||||
|
|
||||||
const WordSearchSources({
|
const WordSearchSources({this.jmdict = true, this.jmnedict = false});
|
||||||
this.jmdict = true,
|
|
||||||
this.jmnedict = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, Object?> get sqlValue => {
|
Map<String, Object?> get sqlValue => {'jmdict': jmdict, 'jmnedict': jmnedict};
|
||||||
'jmdict': jmdict,
|
|
||||||
'jmnedict': jmnedict,
|
|
||||||
};
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {'jmdict': jmdict, 'jmnedict': jmnedict};
|
||||||
'jmdict': jmdict,
|
|
||||||
'jmnedict': jmnedict,
|
|
||||||
};
|
|
||||||
|
|
||||||
factory WordSearchSources.fromJson(Map<String, dynamic> json) =>
|
factory WordSearchSources.fromJson(Map<String, dynamic> json) =>
|
||||||
WordSearchSources(
|
WordSearchSources(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'package:jadb/models/word_search/word_search_result.dart';
|
||||||
|
|
||||||
/// A cross-reference entry from one word-result to another entry.
|
/// A cross-reference entry from one word-result to another entry.
|
||||||
class WordSearchXrefEntry {
|
class WordSearchXrefEntry {
|
||||||
/// The ID of the entry that this entry cross-references to.
|
/// The ID of the entry that this entry cross-references to.
|
||||||
@@ -13,19 +15,24 @@ class WordSearchXrefEntry {
|
|||||||
/// database (and hence might be incorrect).
|
/// database (and hence might be incorrect).
|
||||||
final bool ambiguous;
|
final bool ambiguous;
|
||||||
|
|
||||||
|
/// The result of the cross-reference, may or may not be included in the query.
|
||||||
|
final WordSearchResult? xrefResult;
|
||||||
|
|
||||||
const WordSearchXrefEntry({
|
const WordSearchXrefEntry({
|
||||||
required this.entryId,
|
required this.entryId,
|
||||||
required this.ambiguous,
|
required this.ambiguous,
|
||||||
required this.baseWord,
|
required this.baseWord,
|
||||||
required this.furigana,
|
required this.furigana,
|
||||||
|
required this.xrefResult,
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'entryId': entryId,
|
'entryId': entryId,
|
||||||
'ambiguous': ambiguous,
|
'ambiguous': ambiguous,
|
||||||
'baseWord': baseWord,
|
'baseWord': baseWord,
|
||||||
'furigana': furigana,
|
'furigana': furigana,
|
||||||
};
|
'xrefResult': xrefResult?.toJson(),
|
||||||
|
};
|
||||||
|
|
||||||
factory WordSearchXrefEntry.fromJson(Map<String, dynamic> json) =>
|
factory WordSearchXrefEntry.fromJson(Map<String, dynamic> json) =>
|
||||||
WordSearchXrefEntry(
|
WordSearchXrefEntry(
|
||||||
@@ -33,5 +40,6 @@ class WordSearchXrefEntry {
|
|||||||
ambiguous: json['ambiguous'] as bool,
|
ambiguous: json['ambiguous'] as bool,
|
||||||
baseWord: json['baseWord'] as String,
|
baseWord: json['baseWord'] as String,
|
||||||
furigana: json['furigana'] as String?,
|
furigana: json['furigana'] as String?,
|
||||||
|
xrefResult: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
|
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
|
||||||
import 'package:jadb/models/verify_tables.dart';
|
import 'package:jadb/models/verify_tables.dart';
|
||||||
import 'package:jadb/models/word_search/word_search_result.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';
|
import 'package:jadb/search/filter_kanji.dart';
|
||||||
|
import 'package:jadb/search/kanji_search.dart';
|
||||||
import 'package:jadb/search/radical_search.dart';
|
import 'package:jadb/search/radical_search.dart';
|
||||||
import 'package:jadb/search/word_search/word_search.dart';
|
import 'package:jadb/search/word_search/word_search.dart';
|
||||||
|
|
||||||
import 'package:jadb/search/kanji_search.dart';
|
|
||||||
|
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
extension JaDBConnection on DatabaseExecutor {
|
extension JaDBConnection on DatabaseExecutor {
|
||||||
@@ -19,38 +17,45 @@ extension JaDBConnection on DatabaseExecutor {
|
|||||||
Future<KanjiSearchResult?> jadbSearchKanji(String kanji) =>
|
Future<KanjiSearchResult?> jadbSearchKanji(String kanji) =>
|
||||||
searchKanjiWithDbConnection(this, kanji);
|
searchKanjiWithDbConnection(this, kanji);
|
||||||
|
|
||||||
|
/// Search for a kanji in the database.
|
||||||
|
Future<Map<String, KanjiSearchResult>> jadbGetManyKanji(Set<String> kanji) =>
|
||||||
|
searchManyKanjiWithDbConnection(this, kanji);
|
||||||
|
|
||||||
/// Filter a list of characters, and return the ones that are listed in the kanji dictionary.
|
/// Filter a list of characters, and return the ones that are listed in the kanji dictionary.
|
||||||
Future<List<String>> filterKanji(
|
Future<List<String>> filterKanji(
|
||||||
List<String> kanji, {
|
List<String> kanji, {
|
||||||
bool deduplicate = false,
|
bool deduplicate = false,
|
||||||
}) =>
|
}) => filterKanjiWithDbConnection(this, kanji, deduplicate);
|
||||||
filterKanjiWithDbConnection(this, kanji, deduplicate);
|
|
||||||
|
|
||||||
/// Search for a word in the database.
|
/// Search for a word in the database.
|
||||||
Future<List<WordSearchResult>?> jadbSearchWord(
|
Future<List<WordSearchResult>?> jadbSearchWord(
|
||||||
String word, {
|
String word, {
|
||||||
SearchMode searchMode = SearchMode.Auto,
|
SearchMode searchMode = SearchMode.Auto,
|
||||||
int page = 0,
|
int page = 0,
|
||||||
int pageSize = 10,
|
int? pageSize,
|
||||||
}) =>
|
}) => searchWordWithDbConnection(
|
||||||
searchWordWithDbConnection(
|
this,
|
||||||
this,
|
word,
|
||||||
word,
|
searchMode: searchMode,
|
||||||
searchMode,
|
page: page,
|
||||||
page,
|
pageSize: pageSize,
|
||||||
pageSize,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
Future<WordSearchResult?> jadbGetWordById(int id) =>
|
Future<WordSearchResult?> jadbGetWordById(int id) =>
|
||||||
getWordByIdWithDbConnection(this, id);
|
getWordByIdWithDbConnection(this, id);
|
||||||
|
|
||||||
|
/// Get a list of words by their IDs.
|
||||||
|
///
|
||||||
|
/// IDs for which no result is found are omitted from the returned value.
|
||||||
|
Future<Map<int, WordSearchResult>> jadbGetManyWordsByIds(Set<int> ids) =>
|
||||||
|
getWordsByIdsWithDbConnection(this, ids);
|
||||||
|
|
||||||
/// Search for a word in the database, and return the count of results.
|
/// Search for a word in the database, and return the count of results.
|
||||||
Future<int?> jadbSearchWordCount(
|
Future<int?> jadbSearchWordCount(
|
||||||
String word, {
|
String word, {
|
||||||
SearchMode searchMode = SearchMode.Auto,
|
SearchMode searchMode = SearchMode.Auto,
|
||||||
}) =>
|
}) => searchWordCountWithDbConnection(this, word, searchMode: searchMode);
|
||||||
searchWordCountWithDbConnection(this, word, searchMode);
|
|
||||||
|
|
||||||
/// Given a list of radicals, search which kanji contains all
|
/// Given a list of radicals, search which kanji contains all
|
||||||
/// of the radicals, find their other radicals, and return those.
|
/// of the radicals, find their other radicals, and return those.
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ Future<List<String>> filterKanjiWithDbConnection(
|
|||||||
List<String> kanji,
|
List<String> kanji,
|
||||||
bool deduplicate,
|
bool deduplicate,
|
||||||
) async {
|
) async {
|
||||||
final Set<String> filteredKanji = await connection.rawQuery(
|
final Set<String> filteredKanji = await connection
|
||||||
'''
|
.rawQuery('''
|
||||||
SELECT "literal"
|
SELECT "literal"
|
||||||
FROM "${KANJIDICTableNames.character}"
|
FROM "${KANJIDICTableNames.character}"
|
||||||
WHERE "literal" IN (${kanji.map((_) => '?').join(',')})
|
WHERE "literal" IN (${kanji.map((_) => '?').join(',')})
|
||||||
''',
|
''', kanji)
|
||||||
kanji,
|
.then((value) => value.map((e) => e['literal'] as String).toSet());
|
||||||
).then((value) => value.map((e) => e['literal'] as String).toSet());
|
|
||||||
|
|
||||||
if (deduplicate) {
|
if (deduplicate) {
|
||||||
return filteredKanji.toList();
|
return filteredKanji.toList();
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
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_radical.dart';
|
||||||
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
|
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
|
||||||
|
import 'package:jadb/table_names/kanjidic.dart';
|
||||||
|
import 'package:jadb/table_names/radkfile.dart';
|
||||||
|
import 'package:jadb/util/romaji_transliteration.dart';
|
||||||
import 'package:sqflite_common/sqflite.dart';
|
import 'package:sqflite_common/sqflite.dart';
|
||||||
|
|
||||||
Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
||||||
@@ -10,66 +11,66 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
String kanji,
|
String kanji,
|
||||||
) async {
|
) async {
|
||||||
late final List<Map<String, Object?>> characters;
|
late final List<Map<String, Object?>> characters;
|
||||||
final characters_query = connection.query(
|
final charactersQuery = connection.query(
|
||||||
KANJIDICTableNames.character,
|
KANJIDICTableNames.character,
|
||||||
where: "literal = ?",
|
where: 'literal = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> codepoints;
|
late final List<Map<String, Object?>> codepoints;
|
||||||
final codepoints_query = connection.query(
|
final codepointsQuery = connection.query(
|
||||||
KANJIDICTableNames.codepoint,
|
KANJIDICTableNames.codepoint,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> kunyomis;
|
late final List<Map<String, Object?>> kunyomis;
|
||||||
final kunyomis_query = connection.query(
|
final kunyomisQuery = connection.query(
|
||||||
KANJIDICTableNames.kunyomi,
|
KANJIDICTableNames.kunyomi,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
orderBy: "orderNum",
|
orderBy: 'orderNum',
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> onyomis;
|
late final List<Map<String, Object?>> onyomis;
|
||||||
final onyomis_query = connection.query(
|
final onyomisQuery = connection.query(
|
||||||
KANJIDICTableNames.onyomi,
|
KANJIDICTableNames.onyomi,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
orderBy: "orderNum",
|
orderBy: 'orderNum',
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> meanings;
|
late final List<Map<String, Object?>> meanings;
|
||||||
final meanings_query = connection.query(
|
final meaningsQuery = connection.query(
|
||||||
KANJIDICTableNames.meaning,
|
KANJIDICTableNames.meaning,
|
||||||
where: "kanji = ? AND language = ?",
|
where: 'kanji = ? AND language = ?',
|
||||||
whereArgs: [kanji, 'eng'],
|
whereArgs: [kanji, 'eng'],
|
||||||
orderBy: "orderNum",
|
orderBy: 'orderNum',
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> nanoris;
|
late final List<Map<String, Object?>> nanoris;
|
||||||
final nanoris_query = connection.query(
|
final nanorisQuery = connection.query(
|
||||||
KANJIDICTableNames.nanori,
|
KANJIDICTableNames.nanori,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> dictionary_references;
|
late final List<Map<String, Object?>> dictionaryReferences;
|
||||||
final dictionary_references_query = connection.query(
|
final dictionaryReferencesQuery = connection.query(
|
||||||
KANJIDICTableNames.dictionaryReference,
|
KANJIDICTableNames.dictionaryReference,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> query_codes;
|
late final List<Map<String, Object?>> queryCodes;
|
||||||
final query_codes_query = connection.query(
|
final queryCodesQuery = connection.query(
|
||||||
KANJIDICTableNames.queryCode,
|
KANJIDICTableNames.queryCode,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> radicals;
|
late final List<Map<String, Object?>> radicals;
|
||||||
final radicals_query = connection.rawQuery(
|
final radicalsQuery = connection.rawQuery(
|
||||||
'''
|
'''
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
"XREF__KANJIDIC_Radical__RADKFILE"."radicalSymbol" AS "symbol",
|
"XREF__KANJIDIC_Radical__RADKFILE"."radicalSymbol" AS "symbol",
|
||||||
@@ -87,23 +88,23 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> parts;
|
late final List<Map<String, Object?>> parts;
|
||||||
final parts_query = connection.query(
|
final partsQuery = connection.query(
|
||||||
RADKFILETableNames.radkfile,
|
RADKFILETableNames.radkfile,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> readings;
|
late final List<Map<String, Object?>> readings;
|
||||||
final readings_query = connection.query(
|
final readingsQuery = connection.query(
|
||||||
KANJIDICTableNames.reading,
|
KANJIDICTableNames.reading,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> stroke_miscounts;
|
late final List<Map<String, Object?>> strokeMiscounts;
|
||||||
final stroke_miscounts_query = connection.query(
|
final strokeMiscountsQuery = connection.query(
|
||||||
KANJIDICTableNames.strokeMiscount,
|
KANJIDICTableNames.strokeMiscount,
|
||||||
where: "kanji = ?",
|
where: 'kanji = ?',
|
||||||
whereArgs: [kanji],
|
whereArgs: [kanji],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -115,29 +116,29 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
// whereArgs: [kanji],
|
// whereArgs: [kanji],
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// TODO: Search for kunyomi and onyomi usage of the characters
|
// TODO: Search for kunyomi and onyomi usage of the characters
|
||||||
// from JMDict. We'll need to fuzzy aquery JMDict_KanjiElement for mathces,
|
// from JMDict. We'll need to fuzzy aquery JMDict_KanjiElement for mathces,
|
||||||
// filter JMdict_ReadingElement for kunyomi/onyomi, and then sort the main entry
|
// filter JMdict_ReadingElement for kunyomi/onyomi, and then sort the main entry
|
||||||
// by JLPT, news frequency, etc.
|
// by JLPT, news frequency, etc.
|
||||||
|
|
||||||
await characters_query.then((value) => characters = value);
|
await charactersQuery.then((value) => characters = value);
|
||||||
|
|
||||||
if (characters.isEmpty) {
|
if (characters.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Future.wait({
|
await Future.wait({
|
||||||
codepoints_query.then((value) => codepoints = value),
|
codepointsQuery.then((value) => codepoints = value),
|
||||||
kunyomis_query.then((value) => kunyomis = value),
|
kunyomisQuery.then((value) => kunyomis = value),
|
||||||
onyomis_query.then((value) => onyomis = value),
|
onyomisQuery.then((value) => onyomis = value),
|
||||||
meanings_query.then((value) => meanings = value),
|
meaningsQuery.then((value) => meanings = value),
|
||||||
nanoris_query.then((value) => nanoris = value),
|
nanorisQuery.then((value) => nanoris = value),
|
||||||
dictionary_references_query.then((value) => dictionary_references = value),
|
dictionaryReferencesQuery.then((value) => dictionaryReferences = value),
|
||||||
query_codes_query.then((value) => query_codes = value),
|
queryCodesQuery.then((value) => queryCodes = value),
|
||||||
radicals_query.then((value) => radicals = value),
|
radicalsQuery.then((value) => radicals = value),
|
||||||
parts_query.then((value) => parts = value),
|
partsQuery.then((value) => parts = value),
|
||||||
readings_query.then((value) => readings = value),
|
readingsQuery.then((value) => readings = value),
|
||||||
stroke_miscounts_query.then((value) => stroke_miscounts = value),
|
strokeMiscountsQuery.then((value) => strokeMiscounts = value),
|
||||||
// variants_query.then((value) => variants = value),
|
// variants_query.then((value) => variants = value),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -156,9 +157,7 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
final alternativeLanguageReadings = readings
|
final alternativeLanguageReadings = readings
|
||||||
.groupListsBy(
|
.groupListsBy((item) => item['type'] as String)
|
||||||
(item) => item['type'] as String,
|
|
||||||
)
|
|
||||||
.map(
|
.map(
|
||||||
(key, value) => MapEntry(
|
(key, value) => MapEntry(
|
||||||
key,
|
key,
|
||||||
@@ -167,20 +166,16 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Add `SKIPMisclassification` to the entries
|
// TODO: Add `SKIPMisclassification` to the entries
|
||||||
final queryCodes = query_codes
|
final queryCodes_ = queryCodes
|
||||||
.groupListsBy(
|
.groupListsBy((item) => item['type'] as String)
|
||||||
(item) => item['type'] as String,
|
|
||||||
)
|
|
||||||
.map(
|
.map(
|
||||||
(key, value) => MapEntry(
|
(key, value) =>
|
||||||
key,
|
MapEntry(key, value.map((item) => item['code'] as String).toList()),
|
||||||
value.map((item) => item['code'] as String).toList(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Add `volume` and `page` to the entries
|
// TODO: Add `volume` and `page` to the entries
|
||||||
final dictionaryReferences = {
|
final dictionaryReferences_ = {
|
||||||
for (final entry in dictionary_references)
|
for (final entry in dictionaryReferences)
|
||||||
entry['type'] as String: entry['ref'] as String,
|
entry['type'] as String: entry['ref'] as String,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -209,9 +204,32 @@ Future<KanjiSearchResult?> searchKanjiWithDbConnection(
|
|||||||
},
|
},
|
||||||
nanori: nanoris.map((item) => item['nanori'] as String).toList(),
|
nanori: nanoris.map((item) => item['nanori'] as String).toList(),
|
||||||
alternativeLanguageReadings: alternativeLanguageReadings,
|
alternativeLanguageReadings: alternativeLanguageReadings,
|
||||||
strokeMiscounts:
|
strokeMiscounts: strokeMiscounts
|
||||||
stroke_miscounts.map((item) => item['strokeCount'] as int).toList(),
|
.map((item) => item['strokeCount'] as int)
|
||||||
queryCodes: queryCodes,
|
.toList(),
|
||||||
dictionaryReferences: dictionaryReferences,
|
queryCodes: queryCodes_,
|
||||||
|
dictionaryReferences: dictionaryReferences_,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Use fewer queries with `IN` clauses to reduce the number of queries
|
||||||
|
|
||||||
|
Future<Map<String, KanjiSearchResult>> searchManyKanjiWithDbConnection(
|
||||||
|
DatabaseExecutor connection,
|
||||||
|
Set<String> kanji,
|
||||||
|
) async {
|
||||||
|
if (kanji.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
final results = <String, KanjiSearchResult>{};
|
||||||
|
|
||||||
|
for (final k in kanji) {
|
||||||
|
final result = await searchKanjiWithDbConnection(connection, k);
|
||||||
|
if (result != null) {
|
||||||
|
results[k] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ Future<List<String>> searchRemainingRadicalsWithDbConnection(
|
|||||||
HAVING COUNT(DISTINCT "radical") = ?
|
HAVING COUNT(DISTINCT "radical") = ?
|
||||||
)
|
)
|
||||||
''',
|
''',
|
||||||
[
|
[...radicals, radicals.length],
|
||||||
...radicals,
|
|
||||||
radicals.length,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final remainingRadicals =
|
final remainingRadicals = queryResult
|
||||||
queryResult.map((row) => row['radical'] as String).toList();
|
.map((row) => row['radical'] as String)
|
||||||
|
.toList();
|
||||||
|
|
||||||
return remainingRadicals;
|
return remainingRadicals;
|
||||||
}
|
}
|
||||||
@@ -43,10 +41,7 @@ Future<List<String>> searchKanjiByRadicalsWithDbConnection(
|
|||||||
GROUP BY "kanji"
|
GROUP BY "kanji"
|
||||||
HAVING COUNT(DISTINCT "radical") = ?
|
HAVING COUNT(DISTINCT "radical") = ?
|
||||||
''',
|
''',
|
||||||
[
|
[...radicals, radicals.length],
|
||||||
...radicals,
|
|
||||||
radicals.length,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final kanji = queryResult.map((row) => row['kanji'] as String).toList();
|
final kanji = queryResult.map((row) => row['kanji'] as String).toList();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:jadb/table_names/jmdict.dart';
|
import 'package:jadb/table_names/jmdict.dart';
|
||||||
import 'package:jadb/table_names/tanos_jlpt.dart';
|
import 'package:jadb/table_names/tanos_jlpt.dart';
|
||||||
import 'package:jadb/util/sqlite_utils.dart';
|
|
||||||
import 'package:sqflite_common/sqflite.dart';
|
import 'package:sqflite_common/sqflite.dart';
|
||||||
|
|
||||||
class LinearWordQueryData {
|
class LinearWordQueryData {
|
||||||
@@ -25,6 +24,9 @@ class LinearWordQueryData {
|
|||||||
final List<Map<String, Object?>> readingElementRestrictions;
|
final List<Map<String, Object?>> readingElementRestrictions;
|
||||||
final List<Map<String, Object?>> kanjiElementInfos;
|
final List<Map<String, Object?>> kanjiElementInfos;
|
||||||
|
|
||||||
|
final LinearWordQueryData? senseAntonymData;
|
||||||
|
final LinearWordQueryData? senseSeeAlsoData;
|
||||||
|
|
||||||
const LinearWordQueryData({
|
const LinearWordQueryData({
|
||||||
required this.senses,
|
required this.senses,
|
||||||
required this.readingElements,
|
required this.readingElements,
|
||||||
@@ -46,59 +48,62 @@ class LinearWordQueryData {
|
|||||||
required this.readingElementInfos,
|
required this.readingElementInfos,
|
||||||
required this.readingElementRestrictions,
|
required this.readingElementRestrictions,
|
||||||
required this.kanjiElementInfos,
|
required this.kanjiElementInfos,
|
||||||
|
required this.senseAntonymData,
|
||||||
|
required this.senseSeeAlsoData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<LinearWordQueryData> fetchLinearWordQueryData(
|
Future<LinearWordQueryData> fetchLinearWordQueryData(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
List<int> entryIds,
|
List<int> entryIds, {
|
||||||
) async {
|
bool fetchXrefData = true,
|
||||||
|
}) async {
|
||||||
late final List<Map<String, Object?>> senses;
|
late final List<Map<String, Object?>> senses;
|
||||||
final Future<List<Map<String, Object?>>> senses_query = connection.query(
|
final Future<List<Map<String, Object?>>> sensesQuery = connection.query(
|
||||||
JMdictTableNames.sense,
|
JMdictTableNames.sense,
|
||||||
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
||||||
whereArgs: entryIds,
|
whereArgs: entryIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> readingElements;
|
late final List<Map<String, Object?>> readingElements;
|
||||||
final Future<List<Map<String, Object?>>> readingElements_query =
|
final Future<List<Map<String, Object?>>> readingelementsQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
JMdictTableNames.readingElement,
|
JMdictTableNames.readingElement,
|
||||||
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
||||||
whereArgs: entryIds,
|
whereArgs: entryIds,
|
||||||
orderBy: 'orderNum',
|
orderBy: 'orderNum',
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> kanjiElements;
|
late final List<Map<String, Object?>> kanjiElements;
|
||||||
final Future<List<Map<String, Object?>>> kanjiElements_query =
|
final Future<List<Map<String, Object?>>> kanjielementsQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
JMdictTableNames.kanjiElement,
|
JMdictTableNames.kanjiElement,
|
||||||
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
||||||
whereArgs: entryIds,
|
whereArgs: entryIds,
|
||||||
orderBy: 'orderNum',
|
orderBy: 'orderNum',
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> jlptTags;
|
late final List<Map<String, Object?>> jlptTags;
|
||||||
final Future<List<Map<String, Object?>>> jlptTags_query = connection.query(
|
final Future<List<Map<String, Object?>>> jlpttagsQuery = connection.query(
|
||||||
TanosJLPTTableNames.jlptTag,
|
TanosJLPTTableNames.jlptTag,
|
||||||
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
||||||
whereArgs: entryIds,
|
whereArgs: entryIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> commonEntries;
|
late final List<Map<String, Object?>> commonEntries;
|
||||||
final Future<List<Map<String, Object?>>> commonEntries_query =
|
final Future<List<Map<String, Object?>>> commonentriesQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
'JMdict_EntryCommon',
|
'JMdict_EntryCommon',
|
||||||
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
where: 'entryId IN (${List.filled(entryIds.length, '?').join(',')})',
|
||||||
whereArgs: entryIds,
|
whereArgs: entryIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
senses_query.then((value) => senses = value),
|
sensesQuery.then((value) => senses = value),
|
||||||
readingElements_query.then((value) => readingElements = value),
|
readingelementsQuery.then((value) => readingElements = value),
|
||||||
kanjiElements_query.then((value) => kanjiElements = value),
|
kanjielementsQuery.then((value) => kanjiElements = value),
|
||||||
jlptTags_query.then((value) => jlptTags = value),
|
jlpttagsQuery.then((value) => jlptTags = value),
|
||||||
commonEntries_query.then((value) => commonEntries = value),
|
commonentriesQuery.then((value) => commonEntries = value),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Sense queries
|
// Sense queries
|
||||||
@@ -106,9 +111,9 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
|
|||||||
final senseIds = senses.map((sense) => sense['senseId'] as int).toList();
|
final senseIds = senses.map((sense) => sense['senseId'] as int).toList();
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseAntonyms;
|
late final List<Map<String, Object?>> senseAntonyms;
|
||||||
final Future<List<Map<String, Object?>>> senseAntonyms_query =
|
final Future<List<Map<String, Object?>>> senseantonymsQuery = connection
|
||||||
connection.rawQuery(
|
.rawQuery(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
"${JMdictTableNames.senseAntonyms}".senseId,
|
"${JMdictTableNames.senseAntonyms}".senseId,
|
||||||
"${JMdictTableNames.senseAntonyms}".ambiguous,
|
"${JMdictTableNames.senseAntonyms}".ambiguous,
|
||||||
@@ -125,81 +130,81 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
|
|||||||
"${JMdictTableNames.senseAntonyms}"."senseId",
|
"${JMdictTableNames.senseAntonyms}"."senseId",
|
||||||
"${JMdictTableNames.senseAntonyms}"."xrefEntryId"
|
"${JMdictTableNames.senseAntonyms}"."xrefEntryId"
|
||||||
""",
|
""",
|
||||||
[...senseIds],
|
[...senseIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseDialects;
|
late final List<Map<String, Object?>> senseDialects;
|
||||||
final Future<List<Map<String, Object?>>> senseDialects_query =
|
final Future<List<Map<String, Object?>>> sensedialectsQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
JMdictTableNames.senseDialect,
|
JMdictTableNames.senseDialect,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseFields;
|
late final List<Map<String, Object?>> senseFields;
|
||||||
final Future<List<Map<String, Object?>>> senseFields_query = connection.query(
|
final Future<List<Map<String, Object?>>> sensefieldsQuery = connection.query(
|
||||||
JMdictTableNames.senseField,
|
JMdictTableNames.senseField,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseGlossaries;
|
late final List<Map<String, Object?>> senseGlossaries;
|
||||||
final Future<List<Map<String, Object?>>> senseGlossaries_query =
|
final Future<List<Map<String, Object?>>> senseglossariesQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
JMdictTableNames.senseGlossary,
|
JMdictTableNames.senseGlossary,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseInfos;
|
late final List<Map<String, Object?>> senseInfos;
|
||||||
final Future<List<Map<String, Object?>>> senseInfos_query = connection.query(
|
final Future<List<Map<String, Object?>>> senseinfosQuery = connection.query(
|
||||||
JMdictTableNames.senseInfo,
|
JMdictTableNames.senseInfo,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseLanguageSources;
|
late final List<Map<String, Object?>> senseLanguageSources;
|
||||||
final Future<List<Map<String, Object?>>> senseLanguageSources_query =
|
final Future<List<Map<String, Object?>>> senselanguagesourcesQuery =
|
||||||
connection.query(
|
connection.query(
|
||||||
JMdictTableNames.senseLanguageSource,
|
JMdictTableNames.senseLanguageSource,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseMiscs;
|
late final List<Map<String, Object?>> senseMiscs;
|
||||||
final Future<List<Map<String, Object?>>> senseMiscs_query = connection.query(
|
final Future<List<Map<String, Object?>>> sensemiscsQuery = connection.query(
|
||||||
JMdictTableNames.senseMisc,
|
JMdictTableNames.senseMisc,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> sensePOSs;
|
late final List<Map<String, Object?>> sensePOSs;
|
||||||
final Future<List<Map<String, Object?>>> sensePOSs_query = connection.query(
|
final Future<List<Map<String, Object?>>> sensepossQuery = connection.query(
|
||||||
JMdictTableNames.sensePOS,
|
JMdictTableNames.sensePOS,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseRestrictedToKanjis;
|
late final List<Map<String, Object?>> senseRestrictedToKanjis;
|
||||||
final Future<List<Map<String, Object?>>> senseRestrictedToKanjis_query =
|
final Future<List<Map<String, Object?>>> senserestrictedtokanjisQuery =
|
||||||
connection.query(
|
connection.query(
|
||||||
JMdictTableNames.senseRestrictedToKanji,
|
JMdictTableNames.senseRestrictedToKanji,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseRestrictedToReadings;
|
late final List<Map<String, Object?>> senseRestrictedToReadings;
|
||||||
final Future<List<Map<String, Object?>>> senseRestrictedToReadings_query =
|
final Future<List<Map<String, Object?>>> senserestrictedtoreadingsQuery =
|
||||||
connection.query(
|
connection.query(
|
||||||
JMdictTableNames.senseRestrictedToReading,
|
JMdictTableNames.senseRestrictedToReading,
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> senseSeeAlsos;
|
late final List<Map<String, Object?>> senseSeeAlsos;
|
||||||
final Future<List<Map<String, Object?>>> senseSeeAlsos_query =
|
final Future<List<Map<String, Object?>>> senseseealsosQuery = connection
|
||||||
connection.rawQuery(
|
.rawQuery(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
"${JMdictTableNames.senseSeeAlso}"."senseId",
|
"${JMdictTableNames.senseSeeAlso}"."senseId",
|
||||||
"${JMdictTableNames.senseSeeAlso}"."ambiguous",
|
"${JMdictTableNames.senseSeeAlso}"."ambiguous",
|
||||||
@@ -216,75 +221,106 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
|
|||||||
"${JMdictTableNames.senseSeeAlso}"."senseId",
|
"${JMdictTableNames.senseSeeAlso}"."senseId",
|
||||||
"${JMdictTableNames.senseSeeAlso}"."xrefEntryId"
|
"${JMdictTableNames.senseSeeAlso}"."xrefEntryId"
|
||||||
""",
|
""",
|
||||||
[...senseIds],
|
[...senseIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<Map<String, Object?>> exampleSentences;
|
late final List<Map<String, Object?>> exampleSentences;
|
||||||
final Future<List<Map<String, Object?>>> exampleSentences_query =
|
final Future<List<Map<String, Object?>>> examplesentencesQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
'JMdict_ExampleSentence',
|
'JMdict_ExampleSentence',
|
||||||
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
where: 'senseId IN (${List.filled(senseIds.length, '?').join(',')})',
|
||||||
whereArgs: senseIds,
|
whereArgs: senseIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reading queries
|
// Reading queries
|
||||||
|
|
||||||
final readingIds = readingElements
|
final readingIds = readingElements
|
||||||
.map((element) => (
|
.map((element) => element['elementId'] as int)
|
||||||
element['entryId'] as int,
|
|
||||||
escapeStringValue(element['reading'] as String)
|
|
||||||
))
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
late final List<Map<String, Object?>> readingElementInfos;
|
late final List<Map<String, Object?>> readingElementInfos;
|
||||||
final Future<List<Map<String, Object?>>> readingElementInfos_query =
|
final Future<List<Map<String, Object?>>> readingelementinfosQuery =
|
||||||
connection.query(
|
connection.query(
|
||||||
JMdictTableNames.readingInfo,
|
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;
|
late final List<Map<String, Object?>> readingElementRestrictions;
|
||||||
final Future<List<Map<String, Object?>>> readingElementRestrictions_query =
|
final Future<List<Map<String, Object?>>> readingelementrestrictionsQuery =
|
||||||
connection.query(
|
connection.query(
|
||||||
JMdictTableNames.readingRestriction,
|
JMdictTableNames.readingRestriction,
|
||||||
where: '(entryId, reading) IN (${readingIds.join(',')})',
|
where:
|
||||||
);
|
'(elementId) IN (${List.filled(readingIds.length, '?').join(',')})',
|
||||||
|
whereArgs: readingIds,
|
||||||
|
);
|
||||||
|
|
||||||
// Kanji queries
|
// Kanji queries
|
||||||
|
|
||||||
final kanjiIds = kanjiElements
|
final kanjiIds = kanjiElements
|
||||||
.map((element) => (
|
.map((element) => element['elementId'] as int)
|
||||||
element['entryId'] as int,
|
|
||||||
escapeStringValue(element['reading'] as String)
|
|
||||||
))
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
late final List<Map<String, Object?>> kanjiElementInfos;
|
late final List<Map<String, Object?>> kanjiElementInfos;
|
||||||
final Future<List<Map<String, Object?>>> kanjiElementInfos_query =
|
final Future<List<Map<String, Object?>>> kanjielementinfosQuery = connection
|
||||||
connection.query(
|
.query(
|
||||||
JMdictTableNames.kanjiInfo,
|
JMdictTableNames.kanjiInfo,
|
||||||
where: '(entryId, reading) IN (${kanjiIds.join(',')})',
|
where:
|
||||||
);
|
'(elementId) IN (${List.filled(kanjiIds.length, '?').join(',')})',
|
||||||
|
whereArgs: kanjiIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Xref data queries
|
||||||
|
await Future.wait([
|
||||||
|
senseantonymsQuery.then((value) => senseAntonyms = value),
|
||||||
|
senseseealsosQuery.then((value) => senseSeeAlsos = value),
|
||||||
|
]);
|
||||||
|
|
||||||
|
late final LinearWordQueryData? senseAntonymData;
|
||||||
|
final Future<LinearWordQueryData?> senseantonymdataQuery =
|
||||||
|
fetchXrefData
|
||||||
|
? fetchLinearWordQueryData(
|
||||||
|
connection,
|
||||||
|
senseAntonyms
|
||||||
|
.map((antonym) => antonym['xrefEntryId'] as int)
|
||||||
|
.toList(),
|
||||||
|
fetchXrefData: false,
|
||||||
|
)
|
||||||
|
: Future.value(null);
|
||||||
|
|
||||||
|
late final LinearWordQueryData? senseSeeAlsoData;
|
||||||
|
final Future<LinearWordQueryData?> senseseealsodataQuery =
|
||||||
|
fetchXrefData
|
||||||
|
? fetchLinearWordQueryData(
|
||||||
|
connection,
|
||||||
|
senseSeeAlsos.map((seeAlso) => seeAlso['xrefEntryId'] as int).toList(),
|
||||||
|
fetchXrefData: false,
|
||||||
|
)
|
||||||
|
: Future.value(null);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
senseAntonyms_query.then((value) => senseAntonyms = value),
|
sensedialectsQuery.then((value) => senseDialects = value),
|
||||||
senseDialects_query.then((value) => senseDialects = value),
|
sensefieldsQuery.then((value) => senseFields = value),
|
||||||
senseFields_query.then((value) => senseFields = value),
|
senseglossariesQuery.then((value) => senseGlossaries = value),
|
||||||
senseGlossaries_query.then((value) => senseGlossaries = value),
|
senseinfosQuery.then((value) => senseInfos = value),
|
||||||
senseInfos_query.then((value) => senseInfos = value),
|
senselanguagesourcesQuery.then((value) => senseLanguageSources = value),
|
||||||
senseLanguageSources_query.then((value) => senseLanguageSources = value),
|
sensemiscsQuery.then((value) => senseMiscs = value),
|
||||||
senseMiscs_query.then((value) => senseMiscs = value),
|
sensepossQuery.then((value) => sensePOSs = value),
|
||||||
sensePOSs_query.then((value) => sensePOSs = value),
|
senserestrictedtokanjisQuery.then(
|
||||||
senseRestrictedToKanjis_query
|
(value) => senseRestrictedToKanjis = value,
|
||||||
.then((value) => senseRestrictedToKanjis = value),
|
),
|
||||||
senseRestrictedToReadings_query
|
senserestrictedtoreadingsQuery.then(
|
||||||
.then((value) => senseRestrictedToReadings = value),
|
(value) => senseRestrictedToReadings = value,
|
||||||
senseSeeAlsos_query.then((value) => senseSeeAlsos = value),
|
),
|
||||||
exampleSentences_query.then((value) => exampleSentences = value),
|
examplesentencesQuery.then((value) => exampleSentences = value),
|
||||||
readingElementInfos_query.then((value) => readingElementInfos = value),
|
readingelementinfosQuery.then((value) => readingElementInfos = value),
|
||||||
readingElementRestrictions_query
|
readingelementrestrictionsQuery.then(
|
||||||
.then((value) => readingElementRestrictions = value),
|
(value) => readingElementRestrictions = value,
|
||||||
kanjiElementInfos_query.then((value) => kanjiElementInfos = value),
|
),
|
||||||
|
kanjielementinfosQuery.then((value) => kanjiElementInfos = value),
|
||||||
|
senseantonymdataQuery.then((value) => senseAntonymData = value),
|
||||||
|
senseseealsodataQuery.then((value) => senseSeeAlsoData = value),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return LinearWordQueryData(
|
return LinearWordQueryData(
|
||||||
@@ -308,5 +344,7 @@ Future<LinearWordQueryData> fetchLinearWordQueryData(
|
|||||||
readingElementInfos: readingElementInfos,
|
readingElementInfos: readingElementInfos,
|
||||||
readingElementRestrictions: readingElementRestrictions,
|
readingElementRestrictions: readingElementRestrictions,
|
||||||
kanjiElementInfos: kanjiElementInfos,
|
kanjiElementInfos: kanjiElementInfos,
|
||||||
|
senseAntonymData: senseAntonymData,
|
||||||
|
senseSeeAlsoData: senseSeeAlsoData,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:jadb/table_names/jmdict.dart';
|
|
||||||
import 'package:jadb/search/word_search/word_search.dart';
|
import 'package:jadb/search/word_search/word_search.dart';
|
||||||
|
import 'package:jadb/table_names/jmdict.dart';
|
||||||
import 'package:jadb/util/text_filtering.dart';
|
import 'package:jadb/util/text_filtering.dart';
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
@@ -37,91 +37,105 @@ String _filterFTSSensitiveCharacters(String word) {
|
|||||||
.replaceAll('(', '')
|
.replaceAll('(', '')
|
||||||
.replaceAll(')', '')
|
.replaceAll(')', '')
|
||||||
.replaceAll('^', '')
|
.replaceAll('^', '')
|
||||||
.replaceAll('\"', '');
|
.replaceAll('"', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
(String, List<Object?>) _kanjiReadingTemplate(
|
(String, List<Object?>) _kanjiReadingTemplate(
|
||||||
String tableName,
|
String tableName,
|
||||||
String word, {
|
String word, {
|
||||||
int pageSize = 10,
|
int? pageSize,
|
||||||
|
int? offset,
|
||||||
bool countOnly = false,
|
bool countOnly = false,
|
||||||
}) =>
|
}) {
|
||||||
(
|
assert(
|
||||||
'''
|
tableName == JMdictTableNames.kanjiElement ||
|
||||||
|
tableName == JMdictTableNames.readingElement,
|
||||||
|
);
|
||||||
|
assert(!countOnly || pageSize == null);
|
||||||
|
assert(!countOnly || offset == null);
|
||||||
|
assert(pageSize == null || pageSize > 0);
|
||||||
|
assert(offset == null || offset >= 0);
|
||||||
|
assert(
|
||||||
|
offset == null || pageSize != null,
|
||||||
|
'Offset should only be used with pageSize set',
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
'''
|
||||||
WITH
|
WITH
|
||||||
fts_results AS (
|
fts_results AS (
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
"${tableName}FTS"."entryId",
|
"$tableName"."entryId",
|
||||||
100
|
100
|
||||||
+ (("${tableName}FTS"."reading" = ?) * 50)
|
+ (("${tableName}FTS"."reading" = ?) * 10000)
|
||||||
+ "JMdict_EntryScore"."score"
|
+ "JMdict_EntryScore"."score"
|
||||||
AS "score"
|
AS "score"
|
||||||
FROM "${tableName}FTS"
|
FROM "${tableName}FTS"
|
||||||
JOIN "${tableName}" USING ("entryId", "reading")
|
JOIN "$tableName" USING ("elementId")
|
||||||
JOIN "JMdict_EntryScore" USING ("entryId", "reading")
|
JOIN "JMdict_EntryScore" USING ("elementId")
|
||||||
WHERE "${tableName}FTS"."reading" MATCH ? || '*'
|
WHERE "${tableName}FTS"."reading" MATCH ? || '*'
|
||||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'kanji' : 'reading'}'
|
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
|
||||||
ORDER BY
|
|
||||||
"JMdict_EntryScore"."score" DESC
|
|
||||||
${!countOnly ? 'LIMIT ?' : ''}
|
|
||||||
),
|
),
|
||||||
non_fts_results AS (
|
non_fts_results AS (
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
"${tableName}"."entryId",
|
"$tableName"."entryId",
|
||||||
50
|
50
|
||||||
+ "JMdict_EntryScore"."score"
|
+ "JMdict_EntryScore"."score"
|
||||||
AS "score"
|
AS "score"
|
||||||
FROM "${tableName}"
|
FROM "$tableName"
|
||||||
JOIN "JMdict_EntryScore" USING ("entryId", "reading")
|
JOIN "JMdict_EntryScore" USING ("elementId")
|
||||||
WHERE "reading" LIKE '%' || ? || '%'
|
WHERE "reading" LIKE '%' || ? || '%'
|
||||||
AND "entryId" NOT IN (SELECT "entryId" FROM "fts_results")
|
AND "$tableName"."entryId" NOT IN (SELECT "entryId" FROM "fts_results")
|
||||||
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'kanji' : 'reading'}'
|
AND "JMdict_EntryScore"."type" = '${tableName == JMdictTableNames.kanjiElement ? 'k' : 'r'}'
|
||||||
ORDER BY
|
|
||||||
"JMdict_EntryScore"."score" DESC,
|
|
||||||
"${tableName}"."entryId" ASC
|
|
||||||
${!countOnly ? 'LIMIT ?' : ''}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
${countOnly ? 'SELECT COUNT("entryId") AS count' : 'SELECT "entryId", "score"'}
|
SELECT ${countOnly ? 'COUNT(DISTINCT "entryId") AS count' : '"entryId", MAX("score") AS "score"'}
|
||||||
FROM (
|
FROM (
|
||||||
SELECT * FROM fts_results
|
SELECT * FROM "fts_results"
|
||||||
UNION ALL
|
UNION
|
||||||
SELECT * FROM non_fts_results
|
SELECT * FROM "non_fts_results"
|
||||||
)
|
)
|
||||||
|
${!countOnly ? 'GROUP BY "entryId"' : ''}
|
||||||
|
${!countOnly ? 'ORDER BY "score" DESC, "entryId" ASC' : ''}
|
||||||
|
${pageSize != null ? 'LIMIT ?' : ''}
|
||||||
|
${offset != null ? 'OFFSET ?' : ''}
|
||||||
'''
|
'''
|
||||||
.trim(),
|
.trim(),
|
||||||
[
|
[
|
||||||
_filterFTSSensitiveCharacters(word),
|
_filterFTSSensitiveCharacters(word),
|
||||||
_filterFTSSensitiveCharacters(word),
|
_filterFTSSensitiveCharacters(word),
|
||||||
if (!countOnly) pageSize,
|
_filterFTSSensitiveCharacters(word),
|
||||||
_filterFTSSensitiveCharacters(word),
|
?pageSize,
|
||||||
if (!countOnly) pageSize,
|
?offset,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<ScoredEntryId>> _queryKanji(
|
Future<List<ScoredEntryId>> _queryKanji(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word,
|
||||||
int pageSize,
|
int? pageSize,
|
||||||
int? offset,
|
int? offset,
|
||||||
) {
|
) {
|
||||||
final (query, args) = _kanjiReadingTemplate(
|
final (query, args) = _kanjiReadingTemplate(
|
||||||
JMdictTableNames.kanjiElement,
|
JMdictTableNames.kanjiElement,
|
||||||
word,
|
word,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
|
offset: offset,
|
||||||
);
|
);
|
||||||
return connection.rawQuery(query, args).then((result) => result
|
return connection
|
||||||
.map((row) => ScoredEntryId(
|
.rawQuery(query, args)
|
||||||
row['entryId'] as int,
|
.then(
|
||||||
row['score'] as int,
|
(result) => result
|
||||||
))
|
.map(
|
||||||
.toList());
|
(row) =>
|
||||||
|
ScoredEntryId(row['entryId'] as int, row['score'] as int),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _queryKanjiCount(
|
Future<int> _queryKanjiCount(DatabaseExecutor connection, String word) {
|
||||||
DatabaseExecutor connection,
|
|
||||||
String word,
|
|
||||||
) {
|
|
||||||
final (query, args) = _kanjiReadingTemplate(
|
final (query, args) = _kanjiReadingTemplate(
|
||||||
JMdictTableNames.kanjiElement,
|
JMdictTableNames.kanjiElement,
|
||||||
word,
|
word,
|
||||||
@@ -129,32 +143,34 @@ Future<int> _queryKanjiCount(
|
|||||||
);
|
);
|
||||||
return connection
|
return connection
|
||||||
.rawQuery(query, args)
|
.rawQuery(query, args)
|
||||||
.then((result) => result.first['count'] as int);
|
.then((result) => result.firstOrNull?['count'] as int? ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ScoredEntryId>> _queryKana(
|
Future<List<ScoredEntryId>> _queryKana(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word,
|
||||||
int pageSize,
|
int? pageSize,
|
||||||
int? offset,
|
int? offset,
|
||||||
) {
|
) {
|
||||||
final (query, args) = _kanjiReadingTemplate(
|
final (query, args) = _kanjiReadingTemplate(
|
||||||
JMdictTableNames.readingElement,
|
JMdictTableNames.readingElement,
|
||||||
word,
|
word,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
|
offset: offset,
|
||||||
);
|
);
|
||||||
return connection.rawQuery(query, args).then((result) => result
|
return connection
|
||||||
.map((row) => ScoredEntryId(
|
.rawQuery(query, args)
|
||||||
row['entryId'] as int,
|
.then(
|
||||||
row['score'] as int,
|
(result) => result
|
||||||
))
|
.map(
|
||||||
.toList());
|
(row) =>
|
||||||
|
ScoredEntryId(row['entryId'] as int, row['score'] as int),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _queryKanaCount(
|
Future<int> _queryKanaCount(DatabaseExecutor connection, String word) {
|
||||||
DatabaseExecutor connection,
|
|
||||||
String word,
|
|
||||||
) {
|
|
||||||
final (query, args) = _kanjiReadingTemplate(
|
final (query, args) = _kanjiReadingTemplate(
|
||||||
JMdictTableNames.readingElement,
|
JMdictTableNames.readingElement,
|
||||||
word,
|
word,
|
||||||
@@ -162,15 +178,22 @@ Future<int> _queryKanaCount(
|
|||||||
);
|
);
|
||||||
return connection
|
return connection
|
||||||
.rawQuery(query, args)
|
.rawQuery(query, args)
|
||||||
.then((result) => result.first['count'] as int);
|
.then((result) => result.firstOrNull?['count'] as int? ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ScoredEntryId>> _queryEnglish(
|
Future<List<ScoredEntryId>> _queryEnglish(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word,
|
||||||
int pageSize,
|
int? pageSize,
|
||||||
int? offset,
|
int? offset,
|
||||||
) async {
|
) async {
|
||||||
|
assert(pageSize == null || pageSize > 0);
|
||||||
|
assert(offset == null || offset >= 0);
|
||||||
|
assert(
|
||||||
|
offset == null || pageSize != null,
|
||||||
|
'Offset should only be used with pageSize set',
|
||||||
|
);
|
||||||
|
|
||||||
final result = await connection.rawQuery(
|
final result = await connection.rawQuery(
|
||||||
'''
|
'''
|
||||||
SELECT
|
SELECT
|
||||||
@@ -192,41 +215,25 @@ Future<List<ScoredEntryId>> _queryEnglish(
|
|||||||
OFFSET ?
|
OFFSET ?
|
||||||
'''
|
'''
|
||||||
.trim(),
|
.trim(),
|
||||||
[
|
[word, word, word, '%${word.replaceAll('%', '')}%', pageSize, offset],
|
||||||
word,
|
|
||||||
word,
|
|
||||||
word,
|
|
||||||
'%${word.replaceAll('%', '')}%',
|
|
||||||
pageSize,
|
|
||||||
offset,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return result
|
return result
|
||||||
.map((row) => ScoredEntryId(
|
.map((row) => ScoredEntryId(row['entryId'] as int, row['score'] as int))
|
||||||
row['entryId'] as int,
|
|
||||||
row['score'] as int,
|
|
||||||
))
|
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _queryEnglishCount(
|
Future<int> _queryEnglishCount(DatabaseExecutor connection, String word) async {
|
||||||
DatabaseExecutor connection,
|
|
||||||
String word,
|
|
||||||
) async {
|
|
||||||
final result = await connection.rawQuery(
|
final result = await connection.rawQuery(
|
||||||
'''
|
'''
|
||||||
|
SELECT
|
||||||
SELECT
|
COUNT(DISTINCT "${JMdictTableNames.sense}"."entryId") AS "count"
|
||||||
COUNT(DISTINCT "${JMdictTableNames.sense}"."entryId") AS "count"
|
FROM "${JMdictTableNames.senseGlossary}"
|
||||||
FROM "${JMdictTableNames.senseGlossary}"
|
JOIN "${JMdictTableNames.sense}" USING ("senseId")
|
||||||
JOIN "${JMdictTableNames.sense}" USING ("senseId")
|
WHERE "${JMdictTableNames.senseGlossary}"."phrase" LIKE ?
|
||||||
WHERE "${JMdictTableNames.senseGlossary}"."phrase" LIKE ?
|
'''
|
||||||
'''
|
|
||||||
.trim(),
|
.trim(),
|
||||||
[
|
['%$word%'],
|
||||||
'%$word%',
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return result.first['count'] as int;
|
return result.first['count'] as int;
|
||||||
@@ -236,55 +243,34 @@ Future<List<ScoredEntryId>> fetchEntryIds(
|
|||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word,
|
||||||
SearchMode searchMode,
|
SearchMode searchMode,
|
||||||
int pageSize,
|
int? pageSize,
|
||||||
int? offset,
|
int? offset,
|
||||||
) async {
|
) async {
|
||||||
if (searchMode == SearchMode.Auto) {
|
if (searchMode == SearchMode.Auto) {
|
||||||
searchMode = _determineSearchMode(word);
|
searchMode = _determineSearchMode(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(
|
assert(word.isNotEmpty, 'Word should not be empty when fetching entry IDs');
|
||||||
word.isNotEmpty,
|
|
||||||
'Word should not be empty when fetching entry IDs',
|
|
||||||
);
|
|
||||||
|
|
||||||
late final List<ScoredEntryId> entryIds;
|
late final List<ScoredEntryId> entryIds;
|
||||||
switch (searchMode) {
|
switch (searchMode) {
|
||||||
case SearchMode.Kanji:
|
case SearchMode.Kanji:
|
||||||
entryIds = await _queryKanji(
|
entryIds = await _queryKanji(connection, word, pageSize, offset);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
pageSize,
|
|
||||||
offset,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.Kana:
|
case SearchMode.Kana:
|
||||||
entryIds = await _queryKana(
|
entryIds = await _queryKana(connection, word, pageSize, offset);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
pageSize,
|
|
||||||
offset,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.English:
|
case SearchMode.English:
|
||||||
entryIds = await _queryEnglish(
|
entryIds = await _queryEnglish(connection, word, pageSize, offset);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
pageSize,
|
|
||||||
offset,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.MixedKana:
|
case SearchMode.MixedKana:
|
||||||
case SearchMode.MixedKanji:
|
case SearchMode.MixedKanji:
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError(
|
throw UnimplementedError('Search mode $searchMode is not implemented');
|
||||||
'Search mode $searchMode is not implemented',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
|
||||||
return entryIds;
|
return entryIds;
|
||||||
}
|
}
|
||||||
@@ -298,41 +284,27 @@ Future<int?> fetchEntryIdCount(
|
|||||||
searchMode = _determineSearchMode(word);
|
searchMode = _determineSearchMode(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(
|
assert(word.isNotEmpty, 'Word should not be empty when fetching entry IDs');
|
||||||
word.isNotEmpty,
|
|
||||||
'Word should not be empty when fetching entry IDs',
|
|
||||||
);
|
|
||||||
|
|
||||||
late final int? entryIdCount;
|
late final int? entryIdCount;
|
||||||
|
|
||||||
switch (searchMode) {
|
switch (searchMode) {
|
||||||
case SearchMode.Kanji:
|
case SearchMode.Kanji:
|
||||||
entryIdCount = await _queryKanjiCount(
|
entryIdCount = await _queryKanjiCount(connection, word);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.Kana:
|
case SearchMode.Kana:
|
||||||
entryIdCount = await _queryKanaCount(
|
entryIdCount = await _queryKanaCount(connection, word);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.English:
|
case SearchMode.English:
|
||||||
entryIdCount = await _queryEnglishCount(
|
entryIdCount = await _queryEnglishCount(connection, word);
|
||||||
connection,
|
|
||||||
word,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SearchMode.MixedKana:
|
case SearchMode.MixedKana:
|
||||||
case SearchMode.MixedKanji:
|
case SearchMode.MixedKanji:
|
||||||
default:
|
default:
|
||||||
throw UnimplementedError(
|
throw UnimplementedError('Search mode $searchMode is not implemented');
|
||||||
'Search mode $searchMode is not implemented',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryIdCount;
|
return entryIdCount;
|
||||||
|
|||||||
@@ -12,50 +12,37 @@ 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_sense_language_source.dart';
|
||||||
import 'package:jadb/models/word_search/word_search_sources.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/models/word_search/word_search_xref_entry.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/entry_id_query.dart';
|
||||||
|
|
||||||
List<WordSearchResult> regroupWordSearchResults({
|
List<WordSearchResult> regroupWordSearchResults({
|
||||||
required List<ScoredEntryId> entryIds,
|
required List<ScoredEntryId> entryIds,
|
||||||
required List<Map<String, Object?>> readingElements,
|
required LinearWordQueryData linearWordQueryData,
|
||||||
required List<Map<String, Object?>> kanjiElements,
|
|
||||||
required List<Map<String, Object?>> jlptTags,
|
|
||||||
required List<Map<String, Object?>> commonEntries,
|
|
||||||
required List<Map<String, Object?>> senses,
|
|
||||||
required List<Map<String, Object?>> senseAntonyms,
|
|
||||||
required List<Map<String, Object?>> senseDialects,
|
|
||||||
required List<Map<String, Object?>> senseFields,
|
|
||||||
required List<Map<String, Object?>> senseGlossaries,
|
|
||||||
required List<Map<String, Object?>> senseInfos,
|
|
||||||
required List<Map<String, Object?>> senseLanguageSources,
|
|
||||||
required List<Map<String, Object?>> senseMiscs,
|
|
||||||
required List<Map<String, Object?>> sensePOSs,
|
|
||||||
required List<Map<String, Object?>> senseRestrictedToKanjis,
|
|
||||||
required List<Map<String, Object?>> senseRestrictedToReadings,
|
|
||||||
required List<Map<String, Object?>> senseSeeAlsos,
|
|
||||||
required List<Map<String, Object?>> exampleSentences,
|
|
||||||
required List<Map<String, Object?>> readingElementInfos,
|
|
||||||
required List<Map<String, Object?>> readingElementRestrictions,
|
|
||||||
required List<Map<String, Object?>> kanjiElementInfos,
|
|
||||||
}) {
|
}) {
|
||||||
final List<WordSearchResult> results = [];
|
final List<WordSearchResult> results = [];
|
||||||
|
|
||||||
final commonEntryIds =
|
final commonEntryIds = linearWordQueryData.commonEntries
|
||||||
commonEntries.map((entry) => entry['entryId'] as int).toSet();
|
.map((entry) => entry['entryId'] as int)
|
||||||
|
.toSet();
|
||||||
|
|
||||||
for (final scoredEntryId in entryIds) {
|
for (final scoredEntryId in entryIds) {
|
||||||
final List<Map<String, Object?>> entryReadingElements = readingElements
|
final List<Map<String, Object?>> entryReadingElements = linearWordQueryData
|
||||||
|
.readingElements
|
||||||
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final List<Map<String, Object?>> entryKanjiElements = kanjiElements
|
final List<Map<String, Object?>> entryKanjiElements = linearWordQueryData
|
||||||
|
.kanjiElements
|
||||||
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final List<Map<String, Object?>> entryJlptTags = jlptTags
|
final List<Map<String, Object?>> entryJlptTags = linearWordQueryData
|
||||||
|
.jlptTags
|
||||||
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final jlptLevel = entryJlptTags
|
final jlptLevel =
|
||||||
|
entryJlptTags
|
||||||
.map((e) => JlptLevel.fromString(e['jlptLevel'] as String?))
|
.map((e) => JlptLevel.fromString(e['jlptLevel'] as String?))
|
||||||
.sorted((a, b) => b.compareTo(a))
|
.sorted((a, b) => b.compareTo(a))
|
||||||
.firstOrNull ??
|
.firstOrNull ??
|
||||||
@@ -63,7 +50,7 @@ List<WordSearchResult> regroupWordSearchResults({
|
|||||||
|
|
||||||
final isCommon = commonEntryIds.contains(scoredEntryId.entryId);
|
final isCommon = commonEntryIds.contains(scoredEntryId.entryId);
|
||||||
|
|
||||||
final List<Map<String, Object?>> entrySenses = senses
|
final List<Map<String, Object?>> entrySenses = linearWordQueryData.senses
|
||||||
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
.where((element) => element['entryId'] == scoredEntryId.entryId)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@@ -71,25 +58,28 @@ List<WordSearchResult> regroupWordSearchResults({
|
|||||||
entryId: scoredEntryId.entryId,
|
entryId: scoredEntryId.entryId,
|
||||||
readingElements: entryReadingElements,
|
readingElements: entryReadingElements,
|
||||||
kanjiElements: entryKanjiElements,
|
kanjiElements: entryKanjiElements,
|
||||||
readingElementInfos: readingElementInfos,
|
readingElementInfos: linearWordQueryData.readingElementInfos,
|
||||||
readingElementRestrictions: readingElementRestrictions,
|
readingElementRestrictions:
|
||||||
kanjiElementInfos: kanjiElementInfos,
|
linearWordQueryData.readingElementRestrictions,
|
||||||
|
kanjiElementInfos: linearWordQueryData.kanjiElementInfos,
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<WordSearchSense> entrySensesGrouped = _regroup_senses(
|
final List<WordSearchSense> entrySensesGrouped = _regroup_senses(
|
||||||
senses: entrySenses,
|
senses: entrySenses,
|
||||||
senseAntonyms: senseAntonyms,
|
senseAntonyms: linearWordQueryData.senseAntonyms,
|
||||||
senseDialects: senseDialects,
|
senseDialects: linearWordQueryData.senseDialects,
|
||||||
senseFields: senseFields,
|
senseFields: linearWordQueryData.senseFields,
|
||||||
senseGlossaries: senseGlossaries,
|
senseGlossaries: linearWordQueryData.senseGlossaries,
|
||||||
senseInfos: senseInfos,
|
senseInfos: linearWordQueryData.senseInfos,
|
||||||
senseLanguageSources: senseLanguageSources,
|
senseLanguageSources: linearWordQueryData.senseLanguageSources,
|
||||||
senseMiscs: senseMiscs,
|
senseMiscs: linearWordQueryData.senseMiscs,
|
||||||
sensePOSs: sensePOSs,
|
sensePOSs: linearWordQueryData.sensePOSs,
|
||||||
senseRestrictedToKanjis: senseRestrictedToKanjis,
|
senseRestrictedToKanjis: linearWordQueryData.senseRestrictedToKanjis,
|
||||||
senseRestrictedToReadings: senseRestrictedToReadings,
|
senseRestrictedToReadings: linearWordQueryData.senseRestrictedToReadings,
|
||||||
senseSeeAlsos: senseSeeAlsos,
|
senseSeeAlsos: linearWordQueryData.senseSeeAlsos,
|
||||||
exampleSentences: exampleSentences,
|
exampleSentences: linearWordQueryData.exampleSentences,
|
||||||
|
senseSeeAlsosXrefData: linearWordQueryData.senseSeeAlsoData,
|
||||||
|
senseAntonymsXrefData: linearWordQueryData.senseAntonymData,
|
||||||
);
|
);
|
||||||
|
|
||||||
results.add(
|
results.add(
|
||||||
@@ -102,10 +92,7 @@ List<WordSearchResult> regroupWordSearchResults({
|
|||||||
readingInfo: entryReadingElementsGrouped.readingInfos,
|
readingInfo: entryReadingElementsGrouped.readingInfos,
|
||||||
senses: entrySensesGrouped,
|
senses: entrySensesGrouped,
|
||||||
jlptLevel: jlptLevel,
|
jlptLevel: jlptLevel,
|
||||||
sources: const WordSearchSources(
|
sources: const WordSearchSources(jmdict: true, jmnedict: false),
|
||||||
jmdict: true,
|
|
||||||
jmnedict: false,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -135,8 +122,9 @@ GroupedWordResult _regroup_words({
|
|||||||
}) {
|
}) {
|
||||||
final List<WordSearchRuby> rubys = [];
|
final List<WordSearchRuby> rubys = [];
|
||||||
|
|
||||||
final kanjiElements_ =
|
final kanjiElements_ = kanjiElements
|
||||||
kanjiElements.where((element) => element['entryId'] == entryId).toList();
|
.where((element) => element['entryId'] == entryId)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final readingElements_ = readingElements
|
final readingElements_ = readingElements
|
||||||
.where((element) => element['entryId'] == entryId)
|
.where((element) => element['entryId'] == entryId)
|
||||||
@@ -148,9 +136,7 @@ GroupedWordResult _regroup_words({
|
|||||||
|
|
||||||
for (final readingElement in readingElements_) {
|
for (final readingElement in readingElements_) {
|
||||||
if (readingElement['doesNotMatchKanji'] == 1 || kanjiElements_.isEmpty) {
|
if (readingElement['doesNotMatchKanji'] == 1 || kanjiElements_.isEmpty) {
|
||||||
final ruby = WordSearchRuby(
|
final ruby = WordSearchRuby(base: readingElement['reading'] as String);
|
||||||
base: readingElement['reading'] as String,
|
|
||||||
);
|
|
||||||
rubys.add(ruby);
|
rubys.add(ruby);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -169,29 +155,42 @@ GroupedWordResult _regroup_words({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ruby = WordSearchRuby(
|
final ruby = WordSearchRuby(base: kanji, furigana: reading);
|
||||||
base: kanji,
|
|
||||||
furigana: reading,
|
|
||||||
);
|
|
||||||
rubys.add(ruby);
|
rubys.add(ruby);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(
|
assert(rubys.isNotEmpty, 'No readings found for entryId: $entryId');
|
||||||
rubys.isNotEmpty,
|
|
||||||
'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(
|
return GroupedWordResult(
|
||||||
rubys: rubys,
|
rubys: rubys,
|
||||||
readingInfos: {
|
readingInfos: {
|
||||||
for (final rei in readingElementInfos)
|
for (final rei in readingElementInfos_)
|
||||||
rei['reading'] as String:
|
readingElementIdsToReading[rei['elementId'] as int]!:
|
||||||
JMdictReadingInfo.fromId(rei['info'] as String),
|
JMdictReadingInfo.fromId(rei['info'] as String),
|
||||||
},
|
},
|
||||||
kanjiInfos: {
|
kanjiInfos: {
|
||||||
for (final kei in kanjiElementInfos)
|
for (final kei in kanjiElementInfos_)
|
||||||
kei['reading'] as String: JMdictKanjiInfo.fromId(kei['info'] as String),
|
kanjiElementIdsToReading[kei['elementId'] as int]!:
|
||||||
|
JMdictKanjiInfo.fromId(kei['info'] as String),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -210,29 +209,41 @@ List<WordSearchSense> _regroup_senses({
|
|||||||
required List<Map<String, Object?>> senseRestrictedToReadings,
|
required List<Map<String, Object?>> senseRestrictedToReadings,
|
||||||
required List<Map<String, Object?>> senseSeeAlsos,
|
required List<Map<String, Object?>> senseSeeAlsos,
|
||||||
required List<Map<String, Object?>> exampleSentences,
|
required List<Map<String, Object?>> exampleSentences,
|
||||||
|
required LinearWordQueryData? senseSeeAlsosXrefData,
|
||||||
|
required LinearWordQueryData? senseAntonymsXrefData,
|
||||||
}) {
|
}) {
|
||||||
final groupedSenseAntonyms =
|
final groupedSenseAntonyms = senseAntonyms.groupListsBy(
|
||||||
senseAntonyms.groupListsBy((element) => element['senseId'] as int);
|
(element) => element['senseId'] as int,
|
||||||
final groupedSenseDialects =
|
);
|
||||||
senseDialects.groupListsBy((element) => element['senseId'] as int);
|
final groupedSenseDialects = senseDialects.groupListsBy(
|
||||||
final groupedSenseFields =
|
(element) => element['senseId'] as int,
|
||||||
senseFields.groupListsBy((element) => element['senseId'] as int);
|
);
|
||||||
final groupedSenseGlossaries =
|
final groupedSenseFields = senseFields.groupListsBy(
|
||||||
senseGlossaries.groupListsBy((element) => element['senseId'] as int);
|
(element) => element['senseId'] as int,
|
||||||
final groupedSenseInfos =
|
);
|
||||||
senseInfos.groupListsBy((element) => element['senseId'] as int);
|
final groupedSenseGlossaries = senseGlossaries.groupListsBy(
|
||||||
final groupedSenseLanguageSources =
|
(element) => element['senseId'] as int,
|
||||||
senseLanguageSources.groupListsBy((element) => element['senseId'] as int);
|
);
|
||||||
final groupedSenseMiscs =
|
final groupedSenseInfos = senseInfos.groupListsBy(
|
||||||
senseMiscs.groupListsBy((element) => element['senseId'] as int);
|
(element) => element['senseId'] as int,
|
||||||
final groupedSensePOSs =
|
);
|
||||||
sensePOSs.groupListsBy((element) => element['senseId'] as int);
|
final groupedSenseLanguageSources = senseLanguageSources.groupListsBy(
|
||||||
final groupedSenseRestrictedToKanjis = senseRestrictedToKanjis
|
(element) => element['senseId'] as int,
|
||||||
.groupListsBy((element) => element['senseId'] as int);
|
);
|
||||||
|
final groupedSenseMiscs = senseMiscs.groupListsBy(
|
||||||
|
(element) => element['senseId'] as int,
|
||||||
|
);
|
||||||
|
final groupedSensePOSs = sensePOSs.groupListsBy(
|
||||||
|
(element) => element['senseId'] as int,
|
||||||
|
);
|
||||||
|
final groupedSenseRestrictedToKanjis = senseRestrictedToKanjis.groupListsBy(
|
||||||
|
(element) => element['senseId'] as int,
|
||||||
|
);
|
||||||
final groupedSenseRestrictedToReadings = senseRestrictedToReadings
|
final groupedSenseRestrictedToReadings = senseRestrictedToReadings
|
||||||
.groupListsBy((element) => element['senseId'] as int);
|
.groupListsBy((element) => element['senseId'] as int);
|
||||||
final groupedSenseSeeAlsos =
|
final groupedSenseSeeAlsos = senseSeeAlsos.groupListsBy(
|
||||||
senseSeeAlsos.groupListsBy((element) => element['senseId'] as int);
|
(element) => element['senseId'] as int,
|
||||||
|
);
|
||||||
|
|
||||||
final List<WordSearchSense> result = [];
|
final List<WordSearchSense> result = [];
|
||||||
for (final sense in senses) {
|
for (final sense in senses) {
|
||||||
@@ -251,45 +262,82 @@ List<WordSearchSense> _regroup_senses({
|
|||||||
groupedSenseRestrictedToReadings[senseId] ?? [];
|
groupedSenseRestrictedToReadings[senseId] ?? [];
|
||||||
final seeAlsos = groupedSenseSeeAlsos[senseId] ?? [];
|
final seeAlsos = groupedSenseSeeAlsos[senseId] ?? [];
|
||||||
|
|
||||||
|
final List<WordSearchResult> seeAlsosWordResults =
|
||||||
|
senseSeeAlsosXrefData != null
|
||||||
|
? regroupWordSearchResults(
|
||||||
|
entryIds: seeAlsos
|
||||||
|
.map((e) => ScoredEntryId(e['xrefEntryId'] as int, 0))
|
||||||
|
.toList(),
|
||||||
|
linearWordQueryData: senseSeeAlsosXrefData,
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
final List<WordSearchResult> antonymsWordResults =
|
||||||
|
senseAntonymsXrefData != null
|
||||||
|
? regroupWordSearchResults(
|
||||||
|
entryIds: antonyms
|
||||||
|
.map((e) => ScoredEntryId(e['xrefEntryId'] as int, 0))
|
||||||
|
.toList(),
|
||||||
|
linearWordQueryData: senseAntonymsXrefData,
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
final resultSense = WordSearchSense(
|
final resultSense = WordSearchSense(
|
||||||
englishDefinitions: glossaries.map((e) => e['phrase'] as String).toList(),
|
englishDefinitions: glossaries.map((e) => e['phrase'] as String).toList(),
|
||||||
partsOfSpeech:
|
partsOfSpeech: pos
|
||||||
pos.map((e) => JMdictPOS.fromId(e['pos'] as String)).toList(),
|
.map((e) => JMdictPOS.fromId(e['pos'] as String))
|
||||||
seeAlso: seeAlsos
|
|
||||||
.map((e) => WordSearchXrefEntry(
|
|
||||||
entryId: e['xrefEntryId'] as int,
|
|
||||||
baseWord: e['base'] as String,
|
|
||||||
furigana: e['furigana'] as String?,
|
|
||||||
ambiguous: e['ambiguous'] == 1,
|
|
||||||
))
|
|
||||||
.toList(),
|
.toList(),
|
||||||
antonyms: antonyms
|
seeAlso: seeAlsos.asMap().entries.map<WordSearchXrefEntry>((mapEntry) {
|
||||||
.map((e) => WordSearchXrefEntry(
|
final i = mapEntry.key;
|
||||||
entryId: e['xrefEntryId'] as int,
|
final e = mapEntry.value;
|
||||||
baseWord: e['base'] as String,
|
|
||||||
furigana: e['furigana'] as String?,
|
return WordSearchXrefEntry(
|
||||||
ambiguous: e['ambiguous'] == 1,
|
entryId: e['xrefEntryId'] as int,
|
||||||
))
|
baseWord: e['base'] as String,
|
||||||
|
furigana: e['furigana'] as String?,
|
||||||
|
ambiguous: e['ambiguous'] == 1,
|
||||||
|
xrefResult: seeAlsosWordResults.isNotEmpty
|
||||||
|
? seeAlsosWordResults[i]
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
antonyms: antonyms.asMap().entries.map<WordSearchXrefEntry>((mapEntry) {
|
||||||
|
final i = mapEntry.key;
|
||||||
|
final e = mapEntry.value;
|
||||||
|
|
||||||
|
return WordSearchXrefEntry(
|
||||||
|
entryId: e['xrefEntryId'] as int,
|
||||||
|
baseWord: e['base'] as String,
|
||||||
|
furigana: e['furigana'] as String?,
|
||||||
|
ambiguous: e['ambiguous'] == 1,
|
||||||
|
xrefResult: antonymsWordResults.isNotEmpty
|
||||||
|
? antonymsWordResults[i]
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
restrictedToReading: restrictedToReadings
|
||||||
|
.map((e) => e['reading'] as String)
|
||||||
|
.toList(),
|
||||||
|
restrictedToKanji: restrictedToKanjis
|
||||||
|
.map((e) => e['kanji'] as String)
|
||||||
|
.toList(),
|
||||||
|
fields: fields
|
||||||
|
.map((e) => JMdictField.fromId(e['field'] as String))
|
||||||
.toList(),
|
.toList(),
|
||||||
restrictedToReading:
|
|
||||||
restrictedToReadings.map((e) => e['reading'] as String).toList(),
|
|
||||||
restrictedToKanji:
|
|
||||||
restrictedToKanjis.map((e) => e['kanji'] as String).toList(),
|
|
||||||
fields:
|
|
||||||
fields.map((e) => JMdictField.fromId(e['field'] as String)).toList(),
|
|
||||||
dialects: dialects
|
dialects: dialects
|
||||||
.map((e) => JMdictDialect.fromId(e['dialect'] as String))
|
.map((e) => JMdictDialect.fromId(e['dialect'] as String))
|
||||||
.toList(),
|
.toList(),
|
||||||
misc: miscs.map((e) => JMdictMisc.fromId(e['misc'] as String)).toList(),
|
misc: miscs.map((e) => JMdictMisc.fromId(e['misc'] as String)).toList(),
|
||||||
info: infos.map((e) => e['info'] as String).toList(),
|
info: infos.map((e) => e['info'] as String).toList(),
|
||||||
languageSource: languageSources
|
languageSource: languageSources
|
||||||
.map((e) => WordSearchSenseLanguageSource(
|
.map(
|
||||||
language: e['language'] as String,
|
(e) => WordSearchSenseLanguageSource(
|
||||||
phrase: e['phrase'] as String?,
|
language: e['language'] as String,
|
||||||
fullyDescribesSense: e['fullyDescribesSense'] == 1,
|
phrase: e['phrase'] as String?,
|
||||||
constructedFromSmallerWords:
|
fullyDescribesSense: e['fullyDescribesSense'] == 1,
|
||||||
e['constructedFromSmallerWords'] == 1,
|
constructedFromSmallerWords:
|
||||||
))
|
e['constructedFromSmallerWords'] == 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -13,27 +13,20 @@ import 'package:jadb/search/word_search/regrouping.dart';
|
|||||||
import 'package:jadb/table_names/jmdict.dart';
|
import 'package:jadb/table_names/jmdict.dart';
|
||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
enum SearchMode {
|
enum SearchMode { Auto, English, Kanji, MixedKanji, Kana, MixedKana }
|
||||||
Auto,
|
|
||||||
English,
|
|
||||||
Kanji,
|
|
||||||
MixedKanji,
|
|
||||||
Kana,
|
|
||||||
MixedKana,
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<WordSearchResult>?> searchWordWithDbConnection(
|
Future<List<WordSearchResult>?> searchWordWithDbConnection(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word, {
|
||||||
SearchMode searchMode,
|
SearchMode searchMode = SearchMode.Auto,
|
||||||
int page,
|
int page = 0,
|
||||||
int pageSize,
|
int? pageSize,
|
||||||
) async {
|
}) async {
|
||||||
if (word.isEmpty) {
|
if (word.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final offset = page * pageSize;
|
final int? offset = pageSize != null ? page * pageSize : null;
|
||||||
final List<ScoredEntryId> entryIds = await fetchEntryIds(
|
final List<ScoredEntryId> entryIds = await fetchEntryIds(
|
||||||
connection,
|
connection,
|
||||||
word,
|
word,
|
||||||
@@ -43,37 +36,19 @@ Future<List<WordSearchResult>?> searchWordWithDbConnection(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (entryIds.isEmpty) {
|
if (entryIds.isEmpty) {
|
||||||
|
// TODO: try conjugation search
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
final LinearWordQueryData linearWordQueryData =
|
final LinearWordQueryData linearWordQueryData =
|
||||||
await fetchLinearWordQueryData(
|
await fetchLinearWordQueryData(
|
||||||
connection,
|
connection,
|
||||||
entryIds.map((e) => e.entryId).toList(),
|
entryIds.map((e) => e.entryId).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = regroupWordSearchResults(
|
final result = regroupWordSearchResults(
|
||||||
entryIds: entryIds,
|
entryIds: entryIds,
|
||||||
readingElements: linearWordQueryData.readingElements,
|
linearWordQueryData: linearWordQueryData,
|
||||||
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;
|
return result;
|
||||||
@@ -81,9 +56,9 @@ Future<List<WordSearchResult>?> searchWordWithDbConnection(
|
|||||||
|
|
||||||
Future<int?> searchWordCountWithDbConnection(
|
Future<int?> searchWordCountWithDbConnection(
|
||||||
DatabaseExecutor connection,
|
DatabaseExecutor connection,
|
||||||
String word,
|
String word, {
|
||||||
SearchMode searchMode,
|
SearchMode searchMode = SearchMode.Auto,
|
||||||
) async {
|
}) async {
|
||||||
if (word.isEmpty) {
|
if (word.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -105,43 +80,23 @@ Future<WordSearchResult?> getWordByIdWithDbConnection(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final exists = await connection.rawQuery(
|
final exists = await connection
|
||||||
'SELECT EXISTS(SELECT 1 FROM "${JMdictTableNames.entry}" WHERE "entryId" = ?)',
|
.rawQuery(
|
||||||
[id],
|
'SELECT EXISTS(SELECT 1 FROM "${JMdictTableNames.entry}" WHERE "entryId" = ?)',
|
||||||
).then((value) => value.isNotEmpty && value.first.values.first == 1);
|
[id],
|
||||||
|
)
|
||||||
|
.then((value) => value.isNotEmpty && value.first.values.first == 1);
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final LinearWordQueryData linearWordQueryData =
|
final LinearWordQueryData linearWordQueryData =
|
||||||
await fetchLinearWordQueryData(
|
await fetchLinearWordQueryData(connection, [id]);
|
||||||
connection,
|
|
||||||
[id],
|
|
||||||
);
|
|
||||||
|
|
||||||
final result = regroupWordSearchResults(
|
final result = regroupWordSearchResults(
|
||||||
entryIds: [ScoredEntryId(id, 0)],
|
entryIds: [ScoredEntryId(id, 0)],
|
||||||
readingElements: linearWordQueryData.readingElements,
|
linearWordQueryData: linearWordQueryData,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
@@ -151,3 +106,26 @@ Future<WordSearchResult?> getWordByIdWithDbConnection(
|
|||||||
|
|
||||||
return result.firstOrNull;
|
return result.firstOrNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<int, WordSearchResult>> getWordsByIdsWithDbConnection(
|
||||||
|
DatabaseExecutor connection,
|
||||||
|
Set<int> ids,
|
||||||
|
) async {
|
||||||
|
if (ids.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
final LinearWordQueryData linearWordQueryData =
|
||||||
|
await fetchLinearWordQueryData(connection, ids.toList());
|
||||||
|
|
||||||
|
final List<ScoredEntryId> entryIds = ids
|
||||||
|
.map((id) => ScoredEntryId(id, 0)) // Score is not used here
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final results = regroupWordSearchResults(
|
||||||
|
entryIds: entryIds,
|
||||||
|
linearWordQueryData: linearWordQueryData,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {for (var r in results) r.entryId: r};
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,23 +20,23 @@ abstract class JMdictTableNames {
|
|||||||
static const String senseSeeAlso = 'JMdict_SenseSeeAlso';
|
static const String senseSeeAlso = 'JMdict_SenseSeeAlso';
|
||||||
|
|
||||||
static Set<String> get allTables => {
|
static Set<String> get allTables => {
|
||||||
entry,
|
entry,
|
||||||
kanjiElement,
|
kanjiElement,
|
||||||
kanjiInfo,
|
kanjiInfo,
|
||||||
readingElement,
|
readingElement,
|
||||||
readingInfo,
|
readingInfo,
|
||||||
readingRestriction,
|
readingRestriction,
|
||||||
sense,
|
sense,
|
||||||
senseAntonyms,
|
senseAntonyms,
|
||||||
senseDialect,
|
senseDialect,
|
||||||
senseField,
|
senseField,
|
||||||
senseGlossary,
|
senseGlossary,
|
||||||
senseInfo,
|
senseInfo,
|
||||||
senseMisc,
|
senseMisc,
|
||||||
sensePOS,
|
sensePOS,
|
||||||
senseLanguageSource,
|
senseLanguageSource,
|
||||||
senseRestrictedToKanji,
|
senseRestrictedToKanji,
|
||||||
senseRestrictedToReading,
|
senseRestrictedToReading,
|
||||||
senseSeeAlso
|
senseSeeAlso,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,19 @@ abstract class KANJIDICTableNames {
|
|||||||
static const String nanori = 'KANJIDIC_Nanori';
|
static const String nanori = 'KANJIDIC_Nanori';
|
||||||
|
|
||||||
static Set<String> get allTables => {
|
static Set<String> get allTables => {
|
||||||
character,
|
character,
|
||||||
radicalName,
|
radicalName,
|
||||||
codepoint,
|
codepoint,
|
||||||
radical,
|
radical,
|
||||||
strokeMiscount,
|
strokeMiscount,
|
||||||
variant,
|
variant,
|
||||||
dictionaryReference,
|
dictionaryReference,
|
||||||
dictionaryReferenceMoro,
|
dictionaryReferenceMoro,
|
||||||
queryCode,
|
queryCode,
|
||||||
reading,
|
reading,
|
||||||
kunyomi,
|
kunyomi,
|
||||||
onyomi,
|
onyomi,
|
||||||
meaning,
|
meaning,
|
||||||
nanori
|
nanori,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
abstract class RADKFILETableNames {
|
abstract class RADKFILETableNames {
|
||||||
static const String radkfile = 'RADKFILE';
|
static const String radkfile = 'RADKFILE';
|
||||||
|
|
||||||
static Set<String> get allTables => {
|
static Set<String> get allTables => {radkfile};
|
||||||
radkfile,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -276,29 +276,22 @@ extension on DateTime {
|
|||||||
/// See more info here:
|
/// See more info here:
|
||||||
/// - https://en.wikipedia.org/wiki/Nanboku-ch%C5%8D_period
|
/// - https://en.wikipedia.org/wiki/Nanboku-ch%C5%8D_period
|
||||||
/// - http://www.kumamotokokufu-h.ed.jp/kumamoto/bungaku/nengoui.html
|
/// - http://www.kumamotokokufu-h.ed.jp/kumamoto/bungaku/nengoui.html
|
||||||
String? japaneseEra({bool nanbokuchouPeriodUsesNorth = true}) {
|
String? japaneseEra() {
|
||||||
throw UnimplementedError('This function is not implemented yet.');
|
throw UnimplementedError('This function is not implemented yet.');
|
||||||
|
|
||||||
if (this.year < 645) {
|
if (year < 645) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.year < periodsNanbokuchouNorth.keys.first.$1) {
|
if (year < periodsNanbokuchouNorth.keys.first.$1) {
|
||||||
// TODO: find first where year <= this.year and jump one period back.
|
// TODO: find first where year <= this.year and jump one period back.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get japaneseWeekdayPrefix => [
|
String get japaneseWeekdayPrefix =>
|
||||||
'月',
|
['月', '火', '水', '木', '金', '土', '日'][weekday - 1];
|
||||||
'火',
|
|
||||||
'水',
|
|
||||||
'木',
|
|
||||||
'金',
|
|
||||||
'土',
|
|
||||||
'日',
|
|
||||||
][weekday - 1];
|
|
||||||
|
|
||||||
/// Returns the date in Japanese format.
|
/// Returns the date in Japanese format.
|
||||||
String japaneseDate({bool showWeekday = false}) =>
|
String japaneseDate({bool showWeekday = false}) =>
|
||||||
'$month月$day日' + (showWeekday ? '($japaneseWeekdayPrefix)' : '');
|
'$month月$day日${showWeekday ? '($japaneseWeekdayPrefix)' : ''}';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ enum WordClass {
|
|||||||
input,
|
input,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LemmatizationRuleType {
|
enum LemmatizationRuleType { prefix, suffix }
|
||||||
prefix,
|
|
||||||
suffix,
|
|
||||||
}
|
|
||||||
|
|
||||||
class LemmatizationRule {
|
class LemmatizationRule {
|
||||||
final String name;
|
final String name;
|
||||||
@@ -46,18 +43,18 @@ class LemmatizationRule {
|
|||||||
lookAheadBehind = const [''],
|
lookAheadBehind = const [''],
|
||||||
LemmatizationRuleType type = LemmatizationRuleType.suffix,
|
LemmatizationRuleType type = LemmatizationRuleType.suffix,
|
||||||
}) : this(
|
}) : this(
|
||||||
name: name,
|
name: name,
|
||||||
pattern: AllomorphPattern(
|
pattern: AllomorphPattern(
|
||||||
patterns: {
|
patterns: {
|
||||||
pattern: replacement != null ? [replacement] : null
|
pattern: replacement != null ? [replacement] : null,
|
||||||
},
|
},
|
||||||
type: type,
|
type: type,
|
||||||
lookAheadBehind: lookAheadBehind,
|
lookAheadBehind: lookAheadBehind,
|
||||||
),
|
),
|
||||||
validChildClasses: validChildClasses,
|
validChildClasses: validChildClasses,
|
||||||
terminal: terminal,
|
terminal: terminal,
|
||||||
wordClass: wordClass,
|
wordClass: wordClass,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a set of patterns for matching allomorphs in a word.
|
/// Represents a set of patterns for matching allomorphs in a word.
|
||||||
@@ -132,8 +129,8 @@ class AllomorphPattern {
|
|||||||
if (word.startsWith(p as String)) {
|
if (word.startsWith(p as String)) {
|
||||||
return patterns[affix] != null
|
return patterns[affix] != null
|
||||||
? patterns[affix]!
|
? patterns[affix]!
|
||||||
.map((s) => s + word.substring(affix.length))
|
.map((s) => s + word.substring(affix.length))
|
||||||
.toList()
|
.toList()
|
||||||
: [word.substring(affix.length)];
|
: [word.substring(affix.length)];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -186,7 +183,7 @@ class Lemmatized {
|
|||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
final childrenString = children
|
final childrenString = children
|
||||||
.map((c) => ' - ' + c.toString().split('\n').join('\n '))
|
.map((c) => ' - ${c.toString().split('\n').join('\n ')}')
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
if (children.isEmpty) {
|
if (children.isEmpty) {
|
||||||
@@ -239,9 +236,6 @@ Lemmatized lemmatize(String word) {
|
|||||||
return Lemmatized(
|
return Lemmatized(
|
||||||
original: word,
|
original: word,
|
||||||
rule: inputRule,
|
rule: inputRule,
|
||||||
children: _lemmatize(
|
children: _lemmatize(inputRule, word),
|
||||||
inputRule,
|
|
||||||
word,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -481,9 +481,9 @@ const Map<String, String> latin_to_hiragana = {
|
|||||||
'#~': '〜',
|
'#~': '〜',
|
||||||
};
|
};
|
||||||
|
|
||||||
bool _smallTsu(String for_conversion) => for_conversion == hiragana_small_tsu;
|
bool _smallTsu(String forConversion) => forConversion == hiragana_small_tsu;
|
||||||
bool _nFollowedByYuYeYo(String for_conversion, String kana) =>
|
bool _nFollowedByYuYeYo(String forConversion, String kana) =>
|
||||||
for_conversion == hiragana_syllabic_n &&
|
forConversion == hiragana_syllabic_n &&
|
||||||
kana.length > 1 &&
|
kana.length > 1 &&
|
||||||
'やゆよ'.contains(kana.substring(1, 2));
|
'やゆよ'.contains(kana.substring(1, 2));
|
||||||
|
|
||||||
@@ -495,17 +495,17 @@ String transliterateHiraganaToLatin(String hiragana) {
|
|||||||
while (kana.isNotEmpty) {
|
while (kana.isNotEmpty) {
|
||||||
final lengths = [if (kana.length > 1) 2, 1];
|
final lengths = [if (kana.length > 1) 2, 1];
|
||||||
for (final length in lengths) {
|
for (final length in lengths) {
|
||||||
final String for_conversion = kana.substring(0, length);
|
final String forConversion = kana.substring(0, length);
|
||||||
String? mora;
|
String? mora;
|
||||||
|
|
||||||
if (_smallTsu(for_conversion)) {
|
if (_smallTsu(forConversion)) {
|
||||||
geminate = true;
|
geminate = true;
|
||||||
kana = kana.replaceRange(0, length, '');
|
kana = kana.replaceRange(0, length, '');
|
||||||
break;
|
break;
|
||||||
} else if (_nFollowedByYuYeYo(for_conversion, kana)) {
|
} else if (_nFollowedByYuYeYo(forConversion, kana)) {
|
||||||
mora = "n'";
|
mora = "n'";
|
||||||
}
|
}
|
||||||
mora ??= hiragana_to_latin[for_conversion];
|
mora ??= hiragana_to_latin[forConversion];
|
||||||
|
|
||||||
if (mora != null) {
|
if (mora != null) {
|
||||||
if (geminate) {
|
if (geminate) {
|
||||||
@@ -516,7 +516,7 @@ String transliterateHiraganaToLatin(String hiragana) {
|
|||||||
kana = kana.replaceRange(0, length, '');
|
kana = kana.replaceRange(0, length, '');
|
||||||
break;
|
break;
|
||||||
} else if (length == 1) {
|
} else if (length == 1) {
|
||||||
romaji += for_conversion;
|
romaji += forConversion;
|
||||||
kana = kana.replaceRange(0, length, '');
|
kana = kana.replaceRange(0, length, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,48 +524,46 @@ String transliterateHiraganaToLatin(String hiragana) {
|
|||||||
return romaji;
|
return romaji;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _doubleNFollowedByAIUEO(String for_conversion) =>
|
bool _doubleNFollowedByAIUEO(String forConversion) =>
|
||||||
RegExp(r'^nn[aiueo]$').hasMatch(for_conversion);
|
RegExp(r'^nn[aiueo]$').hasMatch(forConversion);
|
||||||
bool _hasTableMatch(String for_conversion) =>
|
bool _hasTableMatch(String forConversion) =>
|
||||||
latin_to_hiragana[for_conversion] != null;
|
latin_to_hiragana[forConversion] != null;
|
||||||
bool _hasDoubleConsonant(String for_conversion, int length) =>
|
bool _hasDoubleConsonant(String forConversion, int length) =>
|
||||||
for_conversion == 'tch' ||
|
forConversion == 'tch' ||
|
||||||
(length == 2 &&
|
(length == 2 &&
|
||||||
RegExp(r'^([kgsztdnbpmyrlwchf])\1$').hasMatch(for_conversion));
|
RegExp(r'^([kgsztdnbpmyrlwchf])\1$').hasMatch(forConversion));
|
||||||
|
|
||||||
String transliterateLatinToHiragana(String latin) {
|
String transliterateLatinToHiragana(String latin) {
|
||||||
String romaji =
|
String romaji = latin
|
||||||
latin.toLowerCase().replaceAll('mb', 'nb').replaceAll('mp', 'np');
|
.toLowerCase()
|
||||||
|
.replaceAll('mb', 'nb')
|
||||||
|
.replaceAll('mp', 'np');
|
||||||
String kana = '';
|
String kana = '';
|
||||||
|
|
||||||
while (romaji.isNotEmpty) {
|
while (romaji.isNotEmpty) {
|
||||||
final lengths = [
|
final lengths = [if (romaji.length > 2) 3, if (romaji.length > 1) 2, 1];
|
||||||
if (romaji.length > 2) 3,
|
|
||||||
if (romaji.length > 1) 2,
|
|
||||||
1,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (final length in lengths) {
|
for (final length in lengths) {
|
||||||
String? mora;
|
String? mora;
|
||||||
int for_removal = length;
|
int forRemoval = length;
|
||||||
final String for_conversion = romaji.substring(0, length);
|
final String forConversion = romaji.substring(0, length);
|
||||||
|
|
||||||
if (_doubleNFollowedByAIUEO(for_conversion)) {
|
if (_doubleNFollowedByAIUEO(forConversion)) {
|
||||||
mora = hiragana_syllabic_n;
|
mora = hiragana_syllabic_n;
|
||||||
for_removal = 1;
|
forRemoval = 1;
|
||||||
} else if (_hasTableMatch(for_conversion)) {
|
} else if (_hasTableMatch(forConversion)) {
|
||||||
mora = latin_to_hiragana[for_conversion];
|
mora = latin_to_hiragana[forConversion];
|
||||||
} else if (_hasDoubleConsonant(for_conversion, length)) {
|
} else if (_hasDoubleConsonant(forConversion, length)) {
|
||||||
mora = hiragana_small_tsu;
|
mora = hiragana_small_tsu;
|
||||||
for_removal = 1;
|
forRemoval = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mora != null) {
|
if (mora != null) {
|
||||||
kana += mora;
|
kana += mora;
|
||||||
romaji = romaji.replaceRange(0, for_removal, '');
|
romaji = romaji.replaceRange(0, forRemoval, '');
|
||||||
break;
|
break;
|
||||||
} else if (length == 1) {
|
} else if (length == 1) {
|
||||||
kana += for_conversion;
|
kana += forConversion;
|
||||||
romaji = romaji.replaceRange(0, 1, '');
|
romaji = romaji.replaceRange(0, 1, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -579,11 +577,11 @@ String _transposeCodepointsInRange(
|
|||||||
int distance,
|
int distance,
|
||||||
int rangeStart,
|
int rangeStart,
|
||||||
int rangeEnd,
|
int rangeEnd,
|
||||||
) =>
|
) => String.fromCharCodes(
|
||||||
String.fromCharCodes(
|
text.codeUnits.map(
|
||||||
text.codeUnits
|
(c) => c + ((rangeStart <= c && c <= rangeEnd) ? distance : 0),
|
||||||
.map((c) => c + ((rangeStart <= c && c <= rangeEnd) ? distance : 0)),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
String transliterateKanaToLatin(String kana) =>
|
String transliterateKanaToLatin(String kana) =>
|
||||||
transliterateHiraganaToLatin(transliterateKatakanaToHiragana(kana));
|
transliterateHiraganaToLatin(transliterateKatakanaToHiragana(kana));
|
||||||
@@ -599,12 +597,7 @@ String transliterateHiraganaToKatakana(String hiragana) =>
|
|||||||
|
|
||||||
String transliterateFullwidthRomajiToHalfwidth(String halfwidth) =>
|
String transliterateFullwidthRomajiToHalfwidth(String halfwidth) =>
|
||||||
_transposeCodepointsInRange(
|
_transposeCodepointsInRange(
|
||||||
_transposeCodepointsInRange(
|
_transposeCodepointsInRange(halfwidth, -65248, 65281, 65374),
|
||||||
halfwidth,
|
|
||||||
-65248,
|
|
||||||
65281,
|
|
||||||
65374,
|
|
||||||
),
|
|
||||||
-12256,
|
-12256,
|
||||||
12288,
|
12288,
|
||||||
12288,
|
12288,
|
||||||
@@ -612,12 +605,7 @@ String transliterateFullwidthRomajiToHalfwidth(String halfwidth) =>
|
|||||||
|
|
||||||
String transliterateHalfwidthRomajiToFullwidth(String halfwidth) =>
|
String transliterateHalfwidthRomajiToFullwidth(String halfwidth) =>
|
||||||
_transposeCodepointsInRange(
|
_transposeCodepointsInRange(
|
||||||
_transposeCodepointsInRange(
|
_transposeCodepointsInRange(halfwidth, 65248, 33, 126),
|
||||||
halfwidth,
|
|
||||||
65248,
|
|
||||||
33,
|
|
||||||
126,
|
|
||||||
),
|
|
||||||
12256,
|
12256,
|
||||||
32,
|
32,
|
||||||
32,
|
32,
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
String escapeStringValue(String value) {
|
String escapeStringValue(String value) {
|
||||||
return "'" + value.replaceAll("'", "''") + "'";
|
return "'${value.replaceAll("'", "''")}'";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ CREATE TABLE "JMdict_Entry" (
|
|||||||
-- KanjiElement
|
-- KanjiElement
|
||||||
|
|
||||||
CREATE TABLE "JMdict_KanjiElement" (
|
CREATE TABLE "JMdict_KanjiElement" (
|
||||||
|
"elementId" INTEGER PRIMARY KEY,
|
||||||
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||||
"orderNum" INTEGER NOT NULL,
|
"orderNum" INTEGER NOT NULL,
|
||||||
"reading" TEXT NOT NULL,
|
"reading" TEXT NOT NULL,
|
||||||
@@ -47,7 +48,7 @@ CREATE TABLE "JMdict_KanjiElement" (
|
|||||||
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
||||||
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
||||||
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
||||||
PRIMARY KEY ("entryId", "reading"),
|
UNIQUE("entryId", "reading"),
|
||||||
UNIQUE("entryId", "orderNum")
|
UNIQUE("entryId", "orderNum")
|
||||||
) WITHOUT ROWID;
|
) 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 INDEX "JMdict_KanjiElement_byReading" ON "JMdict_KanjiElement"("reading");
|
||||||
|
|
||||||
CREATE TABLE "JMdict_KanjiElementInfo" (
|
CREATE TABLE "JMdict_KanjiElementInfo" (
|
||||||
"entryId" INTEGER NOT NULL,
|
"elementId" INTEGER NOT NULL REFERENCES "JMdict_KanjiElement"("elementId"),
|
||||||
"reading" TEXT NOT NULL,
|
|
||||||
"info" TEXT NOT NULL REFERENCES "JMdict_InfoKanji"("id"),
|
"info" TEXT NOT NULL REFERENCES "JMdict_InfoKanji"("id"),
|
||||||
FOREIGN KEY ("entryId", "reading")
|
PRIMARY KEY ("elementId", "info")
|
||||||
REFERENCES "JMdict_KanjiElement"("entryId", "reading"),
|
|
||||||
PRIMARY KEY ("entryId", "reading", "info")
|
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
-- ReadingElement
|
-- ReadingElement
|
||||||
|
|
||||||
CREATE TABLE "JMdict_ReadingElement" (
|
CREATE TABLE "JMdict_ReadingElement" (
|
||||||
|
"elementId" INTEGER PRIMARY KEY,
|
||||||
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||||
"orderNum" INTEGER NOT NULL,
|
"orderNum" INTEGER NOT NULL,
|
||||||
"reading" TEXT NOT NULL,
|
"reading" TEXT NOT NULL,
|
||||||
@@ -75,7 +74,7 @@ CREATE TABLE "JMdict_ReadingElement" (
|
|||||||
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
"spec" INTEGER CHECK ("spec" BETWEEN 1 AND 2),
|
||||||
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
"gai" INTEGER CHECK ("gai" BETWEEN 1 AND 2),
|
||||||
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
"nf" INTEGER CHECK ("nf" BETWEEN 1 AND 48),
|
||||||
PRIMARY KEY ("entryId", "reading"),
|
UNIQUE("entryId", "reading"),
|
||||||
UNIQUE("entryId", "orderNum")
|
UNIQUE("entryId", "orderNum")
|
||||||
) WITHOUT ROWID;
|
) 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 INDEX "JMdict_ReadingElement_byReading" ON "JMdict_ReadingElement"("reading");
|
||||||
|
|
||||||
CREATE TABLE "JMdict_ReadingElementRestriction" (
|
CREATE TABLE "JMdict_ReadingElementRestriction" (
|
||||||
"entryId" INTEGER NOT NULL,
|
"elementId" INTEGER NOT NULL REFERENCES "JMdict_ReadingElement"("elementId"),
|
||||||
"reading" TEXT NOT NULL,
|
|
||||||
"restriction" TEXT NOT NULL,
|
"restriction" TEXT NOT NULL,
|
||||||
FOREIGN KEY ("entryId", "reading")
|
PRIMARY KEY ("elementId", "restriction")
|
||||||
REFERENCES "JMdict_ReadingElement"("entryId", "reading"),
|
|
||||||
PRIMARY KEY ("entryId", "reading", "restriction")
|
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
CREATE TABLE "JMdict_ReadingElementInfo" (
|
CREATE TABLE "JMdict_ReadingElementInfo" (
|
||||||
"entryId" INTEGER NOT NULL,
|
"elementId" INTEGER NOT NULL REFERENCES "JMdict_ReadingElement"("elementId"),
|
||||||
"reading" TEXT NOT NULL,
|
|
||||||
"info" TEXT NOT NULL REFERENCES "JMdict_InfoReading"("id"),
|
"info" TEXT NOT NULL REFERENCES "JMdict_InfoReading"("id"),
|
||||||
FOREIGN KEY ("entryId", "reading")
|
PRIMARY KEY ("elementId", "info")
|
||||||
REFERENCES "JMdict_ReadingElement"("entryId", "reading"),
|
|
||||||
PRIMARY KEY ("entryId", "reading", "info")
|
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
-- Sense
|
-- 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"
|
CREATE TRIGGER "JMdict_KanjiElement_InsertFTS"
|
||||||
AFTER INSERT ON "JMdict_KanjiElement"
|
AFTER INSERT ON "JMdict_KanjiElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO "JMdict_KanjiElementFTS"("entryId", "reading")
|
INSERT INTO "JMdict_KanjiElementFTS"("elementId", "reading")
|
||||||
VALUES (NEW."entryId", NEW."reading");
|
VALUES (NEW."elementId", NEW."reading");
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_KanjiElement_UpdateFTS"
|
CREATE TRIGGER "JMdict_KanjiElement_UpdateFTS"
|
||||||
AFTER UPDATE OF "entryId", "reading"
|
AFTER UPDATE OF "elementId", "reading"
|
||||||
ON "JMdict_KanjiElement"
|
ON "JMdict_KanjiElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE "JMdict_KanjiElementFTS"
|
UPDATE "JMdict_KanjiElementFTS"
|
||||||
SET
|
SET
|
||||||
"entryId" = NEW."entryId",
|
"elementId" = NEW."elementId",
|
||||||
"reading" = NEW."reading"
|
"reading" = NEW."reading"
|
||||||
WHERE "entryId" = OLD."entryId";
|
WHERE "elementId" = OLD."elementId";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_KanjiElement_DeleteFTS"
|
CREATE TRIGGER "JMdict_KanjiElement_DeleteFTS"
|
||||||
AFTER DELETE ON "JMdict_KanjiElement"
|
AFTER DELETE ON "JMdict_KanjiElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM "JMdict_KanjiElementFTS"
|
DELETE FROM "JMdict_KanjiElementFTS"
|
||||||
WHERE "entryId" = OLD."entryId";
|
WHERE "elementId" = OLD."elementId";
|
||||||
END;
|
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"
|
CREATE TRIGGER "JMdict_ReadingElement_InsertFTS"
|
||||||
AFTER INSERT ON "JMdict_ReadingElement"
|
AFTER INSERT ON "JMdict_ReadingElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO "JMdict_ReadingElementFTS"("entryId", "reading")
|
INSERT INTO "JMdict_ReadingElementFTS"("elementId", "reading")
|
||||||
VALUES (NEW."entryId", NEW."reading");
|
VALUES (NEW."elementId", NEW."reading");
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_ReadingElement_UpdateFTS"
|
CREATE TRIGGER "JMdict_ReadingElement_UpdateFTS"
|
||||||
AFTER UPDATE OF "entryId", "reading"
|
AFTER UPDATE OF "elementId", "reading"
|
||||||
ON "JMdict_ReadingElement"
|
ON "JMdict_ReadingElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE "JMdict_ReadingElementFTS"
|
UPDATE "JMdict_ReadingElementFTS"
|
||||||
SET
|
SET
|
||||||
"entryId" = NEW."entryId",
|
"elementId" = NEW."elementId",
|
||||||
"reading" = NEW."reading"
|
"reading" = NEW."reading"
|
||||||
WHERE "entryId" = OLD."entryId";
|
WHERE "elementId" = OLD."elementId";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_ReadingElement_DeleteFTS"
|
CREATE TRIGGER "JMdict_ReadingElement_DeleteFTS"
|
||||||
AFTER DELETE ON "JMdict_ReadingElement"
|
AFTER DELETE ON "JMdict_ReadingElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM "JMdict_ReadingElementFTS"
|
DELETE FROM "JMdict_ReadingElementFTS"
|
||||||
WHERE "entryId" = OLD."entryId";
|
WHERE "elementId" = OLD."elementId";
|
||||||
END;
|
END;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
CREATE TABLE "JMdict_EntryScore" (
|
CREATE TABLE "JMdict_EntryScore" (
|
||||||
"type" TEXT NOT NULL CHECK ("type" IN ('reading', 'kanji')),
|
"type" CHAR(1) NOT NULL CHECK ("type" IN ('r', 'k')),
|
||||||
"entryId" INTEGER NOT NULL,
|
"entryId" INTEGER NOT NULL REFERENCES "JMdict_Entry"("entryId"),
|
||||||
"reading" TEXT NOT NULL,
|
"elementId" INTEGER NOT NULL,
|
||||||
"score" INTEGER NOT NULL DEFAULT 0,
|
"score" INTEGER NOT NULL DEFAULT 0,
|
||||||
"common" BOOLEAN NOT NULL DEFAULT FALSE,
|
"common" BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
PRIMARY KEY ("type", "entryId", "reading")
|
PRIMARY KEY ("type", "elementId")
|
||||||
) WITHOUT ROWID;
|
) 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_byScore" ON "JMdict_EntryScore"("score");
|
||||||
CREATE INDEX "JMdict_EntryScore_byCommon" ON "JMdict_EntryScore"("common");
|
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_byScore" ON "JMdict_EntryScore"("type", "score");
|
||||||
CREATE INDEX "JMdict_EntryScore_byType_byCommon" ON "JMdict_EntryScore"("type", "common");
|
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
|
CREATE VIEW "JMdict_EntryScoreView_Reading" AS
|
||||||
SELECT
|
SELECT
|
||||||
'reading' AS "type",
|
'r' AS "type",
|
||||||
"JMdict_ReadingElement"."entryId",
|
"JMdict_ReadingElement"."entryId",
|
||||||
"JMdict_ReadingElement"."reading",
|
"JMdict_ReadingElement"."elementId",
|
||||||
(
|
(
|
||||||
"news" IS 1
|
"news" IS 1
|
||||||
OR "ichi" IS 1
|
OR "ichi" IS 1
|
||||||
@@ -52,9 +52,9 @@ LEFT JOIN "JMdict_JLPTTag" USING ("entryId");
|
|||||||
|
|
||||||
CREATE VIEW "JMdict_EntryScoreView_Kanji" AS
|
CREATE VIEW "JMdict_EntryScoreView_Kanji" AS
|
||||||
SELECT
|
SELECT
|
||||||
'kanji' AS "type",
|
'k' AS "type",
|
||||||
"JMdict_KanjiElement"."entryId",
|
"JMdict_KanjiElement"."entryId",
|
||||||
"JMdict_KanjiElement"."reading",
|
"JMdict_KanjiElement"."elementId",
|
||||||
(
|
(
|
||||||
"news" IS 1
|
"news" IS 1
|
||||||
OR "ichi" IS 1
|
OR "ichi" IS 1
|
||||||
@@ -98,14 +98,13 @@ BEGIN
|
|||||||
INSERT INTO "JMdict_EntryScore" (
|
INSERT INTO "JMdict_EntryScore" (
|
||||||
"type",
|
"type",
|
||||||
"entryId",
|
"entryId",
|
||||||
"reading",
|
"elementId",
|
||||||
"score",
|
"score",
|
||||||
"common"
|
"common"
|
||||||
)
|
)
|
||||||
SELECT "type", "entryId", "reading", "score", "common"
|
SELECT "type", "entryId", "elementId", "score", "common"
|
||||||
FROM "JMdict_EntryScoreView_Reading"
|
FROM "JMdict_EntryScoreView_Reading"
|
||||||
WHERE "entryId" = NEW."entryId"
|
WHERE "elementId" = NEW."elementId";
|
||||||
AND "reading" = NEW."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_ReadingElement"
|
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_ReadingElement"
|
||||||
@@ -117,17 +116,15 @@ BEGIN
|
|||||||
"score" = "JMdict_EntryScoreView_Reading"."score",
|
"score" = "JMdict_EntryScoreView_Reading"."score",
|
||||||
"common" = "JMdict_EntryScoreView_Reading"."common"
|
"common" = "JMdict_EntryScoreView_Reading"."common"
|
||||||
FROM "JMdict_EntryScoreView_Reading"
|
FROM "JMdict_EntryScoreView_Reading"
|
||||||
WHERE "entryId" = NEW."entryId"
|
WHERE "elementId" = NEW."elementId";
|
||||||
AND "reading" = NEW."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_ReadingElement"
|
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_ReadingElement"
|
||||||
AFTER DELETE ON "JMdict_ReadingElement"
|
AFTER DELETE ON "JMdict_ReadingElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM "JMdict_EntryScore"
|
DELETE FROM "JMdict_EntryScore"
|
||||||
WHERE "type" = 'reading'
|
WHERE "type" = 'r'
|
||||||
AND "entryId" = OLD."entryId"
|
AND "elementId" = OLD."elementId";
|
||||||
AND "reading" = OLD."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
--- JMdict_KanjiElement triggers
|
--- JMdict_KanjiElement triggers
|
||||||
@@ -138,14 +135,13 @@ BEGIN
|
|||||||
INSERT INTO "JMdict_EntryScore" (
|
INSERT INTO "JMdict_EntryScore" (
|
||||||
"type",
|
"type",
|
||||||
"entryId",
|
"entryId",
|
||||||
"reading",
|
"elementId",
|
||||||
"score",
|
"score",
|
||||||
"common"
|
"common"
|
||||||
)
|
)
|
||||||
SELECT "type", "entryId", "reading", "score", "common"
|
SELECT "type", "entryId", "elementId", "score", "common"
|
||||||
FROM "JMdict_EntryScoreView_Kanji"
|
FROM "JMdict_EntryScoreView_Kanji"
|
||||||
WHERE "entryId" = NEW."entryId"
|
WHERE "elementId" = NEW."elementId";
|
||||||
AND "reading" = NEW."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_KanjiElement"
|
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_KanjiElement"
|
||||||
@@ -157,17 +153,15 @@ BEGIN
|
|||||||
"score" = "JMdict_EntryScoreView_Kanji"."score",
|
"score" = "JMdict_EntryScoreView_Kanji"."score",
|
||||||
"common" = "JMdict_EntryScoreView_Kanji"."common"
|
"common" = "JMdict_EntryScoreView_Kanji"."common"
|
||||||
FROM "JMdict_EntryScoreView_Kanji"
|
FROM "JMdict_EntryScoreView_Kanji"
|
||||||
WHERE "entryId" = NEW."entryId"
|
WHERE "elementId" = NEW."elementId";
|
||||||
AND "reading" = NEW."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_KanjiElement"
|
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_KanjiElement"
|
||||||
AFTER DELETE ON "JMdict_KanjiElement"
|
AFTER DELETE ON "JMdict_KanjiElement"
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM "JMdict_EntryScore"
|
DELETE FROM "JMdict_EntryScore"
|
||||||
WHERE "type" = 'kanji'
|
WHERE "type" = 'k'
|
||||||
AND "entryId" = OLD."entryId"
|
AND "elementId" = OLD."elementId";
|
||||||
AND "reading" = OLD."reading";
|
|
||||||
END;
|
END;
|
||||||
|
|
||||||
--- JMdict_JLPTTag triggers
|
--- JMdict_JLPTTag triggers
|
||||||
@@ -181,8 +175,8 @@ BEGIN
|
|||||||
"common" = "JMdict_EntryScoreView"."common"
|
"common" = "JMdict_EntryScoreView"."common"
|
||||||
FROM "JMdict_EntryScoreView"
|
FROM "JMdict_EntryScoreView"
|
||||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
||||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
AND "JMdict_EntryScore"."entryId" = NEW."entryId"
|
||||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_JLPTTag"
|
CREATE TRIGGER "JMdict_EntryScore_Update_JMdict_JLPTTag"
|
||||||
@@ -195,8 +189,8 @@ BEGIN
|
|||||||
"common" = "JMdict_EntryScoreView"."common"
|
"common" = "JMdict_EntryScoreView"."common"
|
||||||
FROM "JMdict_EntryScoreView"
|
FROM "JMdict_EntryScoreView"
|
||||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
||||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
AND "JMdict_EntryScore"."entryId" = NEW."entryId"
|
||||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_JLPTTag"
|
CREATE TRIGGER "JMdict_EntryScore_Delete_JMdict_JLPTTag"
|
||||||
@@ -207,7 +201,7 @@ BEGIN
|
|||||||
"score" = "JMdict_EntryScoreView"."score",
|
"score" = "JMdict_EntryScoreView"."score",
|
||||||
"common" = "JMdict_EntryScoreView"."common"
|
"common" = "JMdict_EntryScoreView"."common"
|
||||||
FROM "JMdict_EntryScoreView"
|
FROM "JMdict_EntryScoreView"
|
||||||
WHERE "JMdict_EntryScoreView"."entryId" = NEW."entryId"
|
WHERE "JMdict_EntryScoreView"."entryId" = OLD."entryId"
|
||||||
AND "JMdict_EntryScoreView"."entryId" = "JMdict_EntryScore"."entryId"
|
AND "JMdict_EntryScore"."entryId" = OLD."entryId"
|
||||||
AND "JMdict_EntryScoreView"."reading" = "JMdict_EntryScore"."reading";
|
AND "JMdict_EntryScoreView"."elementId" = "JMdict_EntryScore"."elementId";
|
||||||
END;
|
END;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ JOIN "JMdict_KanjiElement"
|
|||||||
ON "JMdict_KanjiElementFTS"."entryId" = "JMdict_KanjiElement"."entryId"
|
ON "JMdict_KanjiElementFTS"."entryId" = "JMdict_KanjiElement"."entryId"
|
||||||
AND "JMdict_KanjiElementFTS"."reading" LIKE '%' || "JMdict_KanjiElement"."reading"
|
AND "JMdict_KanjiElementFTS"."reading" LIKE '%' || "JMdict_KanjiElement"."reading"
|
||||||
JOIN "JMdict_EntryScore"
|
JOIN "JMdict_EntryScore"
|
||||||
ON "JMdict_EntryScore"."type" = 'kanji'
|
ON "JMdict_EntryScore"."type" = 'k'
|
||||||
AND "JMdict_KanjiElement"."entryId" = "JMdict_EntryScore"."entryId"
|
AND "JMdict_KanjiElement"."entryId" = "JMdict_EntryScore"."entryId"
|
||||||
AND "JMdict_KanjiElement"."reading" = "JMdict_EntryScore"."reading"
|
AND "JMdict_KanjiElement"."reading" = "JMdict_EntryScore"."reading"
|
||||||
WHERE "JMdict_EntryScore"."common" = 1;
|
WHERE "JMdict_EntryScore"."common" = 1;
|
||||||
@@ -77,8 +77,13 @@ SELECT DISTINCT "radical" FROM "RADKFILE";
|
|||||||
CREATE VIEW "JMdict_CombinedEntryScore"
|
CREATE VIEW "JMdict_CombinedEntryScore"
|
||||||
AS
|
AS
|
||||||
SELECT
|
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"."score") AS "score",
|
||||||
MAX("JMdict_EntryScore"."common") AS "common"
|
MAX("JMdict_EntryScore"."common") AS "common"
|
||||||
FROM "JMdict_EntryScore"
|
FROM "JMdict_EntryScore"
|
||||||
GROUP BY "JMdict_EntryScore"."entryId";
|
GROUP BY "entryId";
|
||||||
|
|||||||
86
pubspec.lock
86
pubspec.lock
@@ -5,18 +5,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f
|
sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "82.0.0"
|
version: "92.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0"
|
sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.4.5"
|
version: "9.0.0"
|
||||||
args:
|
args:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -69,18 +69,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: coverage
|
name: coverage
|
||||||
sha256: "802bd084fb82e55df091ec8ad1553a7331b61c08251eef19a508b6f3f3a9858d"
|
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.13.1"
|
version: "1.15.0"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.7"
|
||||||
csv:
|
csv:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -153,22 +153,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.2"
|
|
||||||
lints:
|
lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "6.0.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -181,10 +173,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.17"
|
version: "0.12.18"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -218,7 +210,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||||
@@ -229,18 +221,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: petitparser
|
name: petitparser
|
||||||
sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
|
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
version: "7.0.1"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pool
|
name: pool
|
||||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -309,26 +301,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
|
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.5"
|
version: "2.5.6"
|
||||||
sqflite_common_ffi:
|
sqflite_common_ffi:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqflite_common_ffi
|
name: sqflite_common_ffi
|
||||||
sha256: "1f3ef3888d3bfbb47785cc1dda0dc7dd7ebd8c1955d32a9e8e9dae1e38d1c4c1"
|
sha256: "9faa2fedc5385ef238ce772589f7718c24cdddd27419b609bb9c6f703ea27988"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.5"
|
version: "2.3.6"
|
||||||
sqlite3:
|
sqlite3:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
|
sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.5"
|
version: "2.9.4"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -357,10 +349,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: synchronized
|
name: synchronized
|
||||||
sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6"
|
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.1"
|
version: "3.4.0"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -373,26 +365,26 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "0561f3a2cfd33d10232360f16dfcab9351cfb7ad9b23e6cd6e8c7fb0d62c7ac3"
|
sha256: "77cc98ea27006c84e71a7356cf3daf9ddbde2d91d84f77dbfe64cf0e4d9611ae"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.26.1"
|
version: "1.28.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
|
sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.6"
|
version: "0.7.8"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "8619a9a45be044b71fe2cd6b77b54fd60f1c67904c38d48706e2852a2bda1c60"
|
sha256: f1072617a6657e5fc09662e721307f7fb009b4ed89b19f47175d11d5254a62d4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.10"
|
version: "0.6.14"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -405,18 +397,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.0"
|
version: "15.0.2"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
|
sha256: f52385d4f73589977c80797e60fe51014f7f2b957b5e9a62c3f6ada439889249
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.2.0"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -453,10 +445,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: xml
|
name: xml
|
||||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.5.0"
|
version: "6.6.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -466,4 +458,4 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.7.0 <4.0.0"
|
dart: ">=3.9.0 <4.0.0"
|
||||||
|
|||||||
@@ -4,19 +4,21 @@ version: 1.0.0
|
|||||||
homepage: https://git.pvv.ntnu.no/oysteikt/jadb
|
homepage: https://git.pvv.ntnu.no/oysteikt/jadb
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.2.0 <4.0.0'
|
sdk: '^3.9.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
args: ^2.7.0
|
args: ^2.7.0
|
||||||
collection: ^1.19.0
|
collection: ^1.19.0
|
||||||
csv: ^6.0.0
|
csv: ^6.0.0
|
||||||
equatable: ^2.0.0
|
equatable: ^2.0.0
|
||||||
|
path: ^1.9.1
|
||||||
sqflite_common: ^2.5.0
|
sqflite_common: ^2.5.0
|
||||||
sqflite_common_ffi: ^2.3.0
|
sqflite_common_ffi: ^2.3.0
|
||||||
|
sqlite3: ^2.9.4
|
||||||
xml: ^6.5.0
|
xml: ^6.5.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
lints: ^5.0.0
|
lints: ^6.0.0
|
||||||
test: ^1.25.15
|
test: ^1.25.15
|
||||||
|
|
||||||
executables:
|
executables:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:jadb/const_data/kanji_grades.dart';
|
|||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Assert 2136 kanji in jouyou set", () {
|
test('Assert 2136 kanji in jouyou set', () {
|
||||||
expect(JOUYOU_KANJI_BY_GRADES.values.flattenedToSet.length, 2136);
|
expect(JOUYOU_KANJI_BY_GRADES.values.flattenedToSet.length, 2136);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,26 +4,26 @@ import 'dart:io';
|
|||||||
import 'package:jadb/models/create_empty_db.dart';
|
import 'package:jadb/models/create_empty_db.dart';
|
||||||
import 'package:jadb/search.dart';
|
import 'package:jadb/search.dart';
|
||||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:sqlite3/open.dart';
|
import 'package:sqlite3/open.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
Future<DatabaseExecutor> setup_inmemory_database() async {
|
Future<DatabaseExecutor> setup_inmemory_database() async {
|
||||||
final libsqlitePath = Platform.environment['LIBSQLITE_PATH'];
|
final libsqlitePath = Platform.environment['LIBSQLITE_PATH'];
|
||||||
|
|
||||||
if (libsqlitePath == null) {
|
if (libsqlitePath == null) {
|
||||||
throw Exception("LIBSQLITE_PATH is not set");
|
throw Exception('LIBSQLITE_PATH is not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
final db_connection = await createDatabaseFactoryFfi(
|
final dbConnection = await createDatabaseFactoryFfi(
|
||||||
ffiInit: () =>
|
ffiInit: () =>
|
||||||
open.overrideForAll(() => DynamicLibrary.open(libsqlitePath)),
|
open.overrideForAll(() => DynamicLibrary.open(libsqlitePath)),
|
||||||
).openDatabase(':memory:');
|
).openDatabase(':memory:');
|
||||||
|
|
||||||
return db_connection;
|
return dbConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Create empty db", () async {
|
test('Create empty db', () async {
|
||||||
final db = await setup_inmemory_database();
|
final db = await setup_inmemory_database();
|
||||||
|
|
||||||
await createEmptyDb(db);
|
await createEmptyDb(db);
|
||||||
|
|||||||
@@ -4,29 +4,26 @@ import 'package:test/test.dart';
|
|||||||
import 'setup_database_connection.dart';
|
import 'setup_database_connection.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Filter kanji", () async {
|
test('Filter kanji', () async {
|
||||||
final connection = await setup_database_connection();
|
final connection = await setup_database_connection();
|
||||||
|
|
||||||
final result = await connection.filterKanji(
|
final result = await connection.filterKanji([
|
||||||
[
|
'a',
|
||||||
"a",
|
'b',
|
||||||
"b",
|
'c',
|
||||||
"c",
|
'漢',
|
||||||
"漢",
|
'字',
|
||||||
"字",
|
'地',
|
||||||
"地",
|
'字',
|
||||||
"字",
|
'か',
|
||||||
"か",
|
'な',
|
||||||
"な",
|
'.',
|
||||||
".",
|
'!',
|
||||||
"!",
|
'@',
|
||||||
"@",
|
';',
|
||||||
";",
|
'々',
|
||||||
"々",
|
], deduplicate: false);
|
||||||
],
|
|
||||||
deduplicate: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.join(), "漢字地字");
|
expect(result.join(), '漢字地字');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import 'package:test/test.dart';
|
|||||||
import 'setup_database_connection.dart';
|
import 'setup_database_connection.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Search a kanji", () async {
|
test('Search a kanji', () async {
|
||||||
final connection = await setup_database_connection();
|
final connection = await setup_database_connection();
|
||||||
|
|
||||||
final result = await connection.jadbSearchKanji('漢');
|
final result = await connection.jadbSearchKanji('漢');
|
||||||
expect(result, isNotNull);
|
expect(result, isNotNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
group("Search all jouyou kanji", () {
|
group('Search all jouyou kanji', () {
|
||||||
JOUYOU_KANJI_BY_GRADES.forEach((grade, characters) {
|
JOUYOU_KANJI_BY_GRADES.forEach((grade, characters) {
|
||||||
test("Search all kanji in grade $grade", () async {
|
test('Search all kanji in grade $grade', () async {
|
||||||
final connection = await setup_database_connection();
|
final connection = await setup_database_connection();
|
||||||
|
|
||||||
for (final character in characters) {
|
for (final character in characters) {
|
||||||
|
|||||||
@@ -4,21 +4,21 @@ import 'package:jadb/_data_ingestion/open_local_db.dart';
|
|||||||
import 'package:sqflite_common/sqlite_api.dart';
|
import 'package:sqflite_common/sqlite_api.dart';
|
||||||
|
|
||||||
Future<Database> setup_database_connection() async {
|
Future<Database> setup_database_connection() async {
|
||||||
final lib_sqlite_path = Platform.environment['LIBSQLITE_PATH'];
|
final libSqlitePath = Platform.environment['LIBSQLITE_PATH'];
|
||||||
final jadb_path = Platform.environment['JADB_PATH'];
|
final jadbPath = Platform.environment['JADB_PATH'];
|
||||||
|
|
||||||
if (lib_sqlite_path == null) {
|
if (libSqlitePath == null) {
|
||||||
throw Exception("LIBSQLITE_PATH is not set");
|
throw Exception('LIBSQLITE_PATH is not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jadb_path == null) {
|
if (jadbPath == null) {
|
||||||
throw Exception("JADB_PATH is not set");
|
throw Exception('JADB_PATH is not set');
|
||||||
}
|
}
|
||||||
|
|
||||||
final db_connection = await openLocalDb(
|
final dbConnection = await openLocalDb(
|
||||||
libsqlitePath: lib_sqlite_path,
|
libsqlitePath: libSqlitePath,
|
||||||
jadbPath: jadb_path,
|
jadbPath: jadbPath,
|
||||||
);
|
);
|
||||||
|
|
||||||
return db_connection;
|
return dbConnection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,29 +4,59 @@ import 'package:test/test.dart';
|
|||||||
import 'setup_database_connection.dart';
|
import 'setup_database_connection.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Search a word", () async {
|
test('Search a word - english - auto', () async {
|
||||||
final connection = await setup_database_connection();
|
final connection = await setup_database_connection();
|
||||||
final result = await connection.jadbSearchWord("kana");
|
final result = await connection.jadbSearchWord('kana');
|
||||||
expect(result, isNotNull);
|
expect(result, isNotNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Get a word by id", () async {
|
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 connection = await setup_database_connection();
|
||||||
final result = await connection.jadbGetWordById(1577090);
|
final result = await connection.jadbGetWordById(1577090);
|
||||||
expect(result, isNotNull);
|
expect(result, isNotNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
"Serialize all words",
|
'Serialize all words',
|
||||||
() async {
|
() async {
|
||||||
final connection = await setup_database_connection();
|
final connection = await setup_database_connection();
|
||||||
|
|
||||||
// Test serializing all words
|
// Test serializing all words
|
||||||
for (final letter in "aiueoksthnmyrw".split("")) {
|
for (final letter in 'aiueoksthnmyrw'.split('')) {
|
||||||
await connection.jadbSearchWord(letter);
|
await connection.jadbSearchWord(letter);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timeout: Timeout.factor(100),
|
timeout: Timeout.factor(100),
|
||||||
skip: "Very slow test",
|
skip: 'Very slow test',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,65 +2,65 @@ import 'package:jadb/util/romaji_transliteration.dart';
|
|||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group("Romaji -> Hiragana", () {
|
group('Romaji -> Hiragana', () {
|
||||||
test("Basic test", () {
|
test('Basic test', () {
|
||||||
final result = transliterateLatinToHiragana("katamari");
|
final result = transliterateLatinToHiragana('katamari');
|
||||||
expect(result, "かたまり");
|
expect(result, 'かたまり');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Basic test with diacritics", () {
|
test('Basic test with diacritics', () {
|
||||||
final result = transliterateLatinToHiragana("gadamari");
|
final result = transliterateLatinToHiragana('gadamari');
|
||||||
expect(result, "がだまり");
|
expect(result, 'がだまり');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("wi and we", () {
|
test('wi and we', () {
|
||||||
final result = transliterateLatinToHiragana("wiwe");
|
final result = transliterateLatinToHiragana('wiwe');
|
||||||
expect(result, "うぃうぇ");
|
expect(result, 'うぃうぇ');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("nb = mb", () {
|
test('nb = mb', () {
|
||||||
final result = transliterateLatinToHiragana("kanpai");
|
final result = transliterateLatinToHiragana('kanpai');
|
||||||
expect(result, "かんぱい");
|
expect(result, 'かんぱい');
|
||||||
|
|
||||||
final result2 = transliterateLatinToHiragana("kampai");
|
final result2 = transliterateLatinToHiragana('kampai');
|
||||||
expect(result2, "かんぱい");
|
expect(result2, 'かんぱい');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Double n", () {
|
test('Double n', () {
|
||||||
final result = transliterateLatinToHiragana("konnichiha");
|
final result = transliterateLatinToHiragana('konnichiha');
|
||||||
expect(result, "こんにちは");
|
expect(result, 'こんにちは');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Double consonant", () {
|
test('Double consonant', () {
|
||||||
final result = transliterateLatinToHiragana("kappa");
|
final result = transliterateLatinToHiragana('kappa');
|
||||||
expect(result, "かっぱ");
|
expect(result, 'かっぱ');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group("Hiragana -> Romaji", () {
|
group('Hiragana -> Romaji', () {
|
||||||
test("Basic test", () {
|
test('Basic test', () {
|
||||||
final result = transliterateHiraganaToLatin("かたまり");
|
final result = transliterateHiraganaToLatin('かたまり');
|
||||||
expect(result, "katamari");
|
expect(result, 'katamari');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Basic test with diacritics", () {
|
test('Basic test with diacritics', () {
|
||||||
final result = transliterateHiraganaToLatin("がだまり");
|
final result = transliterateHiraganaToLatin('がだまり');
|
||||||
expect(result, "gadamari");
|
expect(result, 'gadamari');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("whi and whe", () {
|
test('whi and whe', () {
|
||||||
final result = transliterateHiraganaToLatin("うぃうぇ");
|
final result = transliterateHiraganaToLatin('うぃうぇ');
|
||||||
expect(result, "whiwhe");
|
expect(result, 'whiwhe');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Double n", () {
|
test('Double n', () {
|
||||||
final result = transliterateHiraganaToLatin("こんにちは");
|
final result = transliterateHiraganaToLatin('こんにちは');
|
||||||
expect(result, "konnichiha");
|
expect(result, 'konnichiha');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Double consonant", () {
|
test('Double consonant', () {
|
||||||
final result = transliterateHiraganaToLatin("かっぱ");
|
final result = transliterateHiraganaToLatin('かっぱ');
|
||||||
expect(result, "kappa");
|
expect(result, 'kappa');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user