feat(server): dictionaries, loaded from files and searched
The server now holds dictionaries for everyone: `dictionary_entry` and `dictionary_source`, reference data owned by no one, never synced. It loads the dictionary files in its `dictionaries` folder at every start, those whose SHA-256 changed: in the background, each source replaced in one transaction, so searches meanwhile find the old entries; a file it can't read is logged and left out. All of JMdict loads in under half a minute. On an instance the folder is deploy/dictionaries, mounted read-only (compose.yaml); the server's README says how. DictionaryEndpoint (signed in): the dictionaries with their credits; a search (exact key, exact loose key, key starting with the query, loose key starting with it, each in the source's order; katakana as hiragana, macrons written out), some 150-450 ms over all of JMdict; and the entries with a label, counted and a page at a time (all JLPT N5 words). The curator now keeps spellings that aren't quite right apart, as `looseKeys` (romaji with long vowels typed once): "sushi" finds 寿司 before 数詞 (すうし). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
a875a91f40
commit
3013bc04b3
6 changed files with 16048 additions and 73 deletions
|
|
@ -16,6 +16,10 @@ import 'package:halkyon_learn_client/src/protocol/asset/file_usage.dart'
|
|||
as _iimptq0q;
|
||||
import 'package:halkyon_learn_client/src/protocol/auth/device.dart'
|
||||
as _ieqh4yr9;
|
||||
import 'package:halkyon_learn_client/src/protocol/dictionary/dictionary_hit.dart'
|
||||
as _iqbqiphu;
|
||||
import 'package:halkyon_learn_client/src/protocol/dictionary/dictionary_source.dart'
|
||||
as _i8vj64sp;
|
||||
import 'package:halkyon_learn_client/src/protocol/instance/instance_info.dart'
|
||||
as _i26u8vl4;
|
||||
import 'package:http/http.dart' as _i85jenna;
|
||||
|
|
@ -220,6 +224,82 @@ class EndpointGitHubUpgrade extends _isc.EndpointRef {
|
|||
);
|
||||
}
|
||||
|
||||
/// The dictionaries the instance holds, to look words up in and to take
|
||||
/// words from by a label (all JLPT N5 words). Reference data: any signed-in
|
||||
/// person may read all of it.
|
||||
/// {@category Endpoint}
|
||||
class EndpointDictionary extends _isc.EndpointRef {
|
||||
EndpointDictionary(_isc.EndpointCaller caller) : super(caller);
|
||||
|
||||
@override
|
||||
String get name => 'dictionary';
|
||||
|
||||
/// The dictionaries there are, with whose work they are.
|
||||
_ida.Future<List<_i8vj64sp.DictionarySource>> dictionaries() =>
|
||||
caller.callServerEndpoint<List<_i8vj64sp.DictionarySource>>(
|
||||
'dictionary',
|
||||
'dictionaries',
|
||||
{},
|
||||
);
|
||||
|
||||
/// The entries of the dictionary of [language] with meanings in
|
||||
/// [glossLanguage] that [query] finds, best first: those with a key that
|
||||
/// is the query, then a loose key that is (`sushi` for すうし), then a key
|
||||
/// starting with it, then a loose key; each in the dictionary's order. At
|
||||
/// most [limit] (30 unless given).
|
||||
_ida.Future<List<_iqbqiphu.DictionaryHit>> search(
|
||||
String language,
|
||||
String glossLanguage,
|
||||
String query, {
|
||||
int? limit,
|
||||
}) => caller.callServerEndpoint<List<_iqbqiphu.DictionaryHit>>(
|
||||
'dictionary',
|
||||
'search',
|
||||
{
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'query': query,
|
||||
'limit': limit,
|
||||
},
|
||||
);
|
||||
|
||||
/// How many entries of the dictionary of [language] with meanings in
|
||||
/// [glossLanguage] carry [label].
|
||||
_ida.Future<int> countLabelled(
|
||||
String language,
|
||||
String glossLanguage,
|
||||
String label,
|
||||
) => caller.callServerEndpoint<int>(
|
||||
'dictionary',
|
||||
'countLabelled',
|
||||
{
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'label': label,
|
||||
},
|
||||
);
|
||||
|
||||
/// The entries that carry [label], in the dictionary's order: [limit] of
|
||||
/// them (100 unless given, at most [maxPage]) after the first [offset].
|
||||
_ida.Future<List<_iqbqiphu.DictionaryHit>> labelled(
|
||||
String language,
|
||||
String glossLanguage,
|
||||
String label, {
|
||||
int? offset,
|
||||
int? limit,
|
||||
}) => caller.callServerEndpoint<List<_iqbqiphu.DictionaryHit>>(
|
||||
'dictionary',
|
||||
'labelled',
|
||||
{
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'label': label,
|
||||
'offset': offset,
|
||||
'limit': limit,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// What this instance offers. Public: the app asks before anyone is signed in.
|
||||
/// {@category Endpoint}
|
||||
class EndpointInstance extends _isc.EndpointRef {
|
||||
|
|
@ -285,6 +365,7 @@ class Client extends _isc.ServerpodClientShared {
|
|||
devices = EndpointDevices(this);
|
||||
gitHubSignIn = EndpointGitHubSignIn(this);
|
||||
gitHubUpgrade = EndpointGitHubUpgrade(this);
|
||||
dictionary = EndpointDictionary(this);
|
||||
instance = EndpointInstance(this);
|
||||
modules = Modules(this);
|
||||
}
|
||||
|
|
@ -301,6 +382,8 @@ class Client extends _isc.ServerpodClientShared {
|
|||
|
||||
late final EndpointGitHubUpgrade gitHubUpgrade;
|
||||
|
||||
late final EndpointDictionary dictionary;
|
||||
|
||||
late final EndpointInstance instance;
|
||||
|
||||
late final Modules modules;
|
||||
|
|
@ -313,6 +396,7 @@ class Client extends _isc.ServerpodClientShared {
|
|||
'devices': devices,
|
||||
'gitHubSignIn': gitHubSignIn,
|
||||
'gitHubUpgrade': gitHubUpgrade,
|
||||
'dictionary': dictionary,
|
||||
'instance': instance,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
|
||||
/// Who made what a dictionary is drawn from, under which licence.
|
||||
abstract class DictionaryCredit
|
||||
implements _isc.SerializableModel, _isc.ProtocolSerialization {
|
||||
DictionaryCredit._({
|
||||
required this.name,
|
||||
required this.by,
|
||||
required this.license,
|
||||
required this.url,
|
||||
});
|
||||
|
||||
factory DictionaryCredit({
|
||||
required String name,
|
||||
required String by,
|
||||
required String license,
|
||||
required String url,
|
||||
}) = _DictionaryCreditImpl;
|
||||
|
||||
factory DictionaryCredit.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return DictionaryCredit(
|
||||
name: jsonSerialization['name'] as String,
|
||||
by: jsonSerialization['by'] as String,
|
||||
license: jsonSerialization['license'] as String,
|
||||
url: jsonSerialization['url'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
/// What it is (`JMdict`).
|
||||
String name;
|
||||
|
||||
/// Who made it.
|
||||
String by;
|
||||
|
||||
/// Its licence, an SPDX identifier.
|
||||
String license;
|
||||
|
||||
/// Where it is described.
|
||||
String url;
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryCredit]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
DictionaryCredit copyWith({
|
||||
String? name,
|
||||
String? by,
|
||||
String? license,
|
||||
String? url,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'DictionaryCredit',
|
||||
'name': name,
|
||||
'by': by,
|
||||
'license': license,
|
||||
'url': url,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'DictionaryCredit',
|
||||
'name': name,
|
||||
'by': by,
|
||||
'license': license,
|
||||
'url': url,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _DictionaryCreditImpl extends DictionaryCredit {
|
||||
_DictionaryCreditImpl({
|
||||
required String name,
|
||||
required String by,
|
||||
required String license,
|
||||
required String url,
|
||||
}) : super._(
|
||||
name: name,
|
||||
by: by,
|
||||
license: license,
|
||||
url: url,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryCredit]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
DictionaryCredit copyWith({
|
||||
String? name,
|
||||
String? by,
|
||||
String? license,
|
||||
String? url,
|
||||
}) {
|
||||
return DictionaryCredit(
|
||||
name: name ?? this.name,
|
||||
by: by ?? this.by,
|
||||
license: license ?? this.license,
|
||||
url: url ?? this.url,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
|
||||
/// An entry of a dictionary the instance holds (JMdict, …): reference data for
|
||||
/// everyone, owned by no one and never synced. The server loads it from a
|
||||
/// dictionary file (dictionary_loader.dart; the format is the curator's README).
|
||||
/// A card made from it copies what it needs and keeps the source and id only as
|
||||
/// a soft reference, so loading a newer version never touches cards.
|
||||
abstract class DictionaryEntry
|
||||
implements _isc.SerializableModel, _isc.ProtocolSerialization {
|
||||
DictionaryEntry._({
|
||||
this.id,
|
||||
required this.source,
|
||||
required this.sourceId,
|
||||
required this.language,
|
||||
required this.glossLanguage,
|
||||
required this.headword,
|
||||
this.reading,
|
||||
required this.rank,
|
||||
required this.labels,
|
||||
required this.searchKeys,
|
||||
required this.looseKeys,
|
||||
required this.entry,
|
||||
});
|
||||
|
||||
factory DictionaryEntry({
|
||||
int? id,
|
||||
required String source,
|
||||
required String sourceId,
|
||||
required String language,
|
||||
required String glossLanguage,
|
||||
required String headword,
|
||||
String? reading,
|
||||
required int rank,
|
||||
required String labels,
|
||||
required String searchKeys,
|
||||
required String looseKeys,
|
||||
required String entry,
|
||||
}) = _DictionaryEntryImpl;
|
||||
|
||||
factory DictionaryEntry.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return DictionaryEntry(
|
||||
id: jsonSerialization['id'] as int?,
|
||||
source: jsonSerialization['source'] as String,
|
||||
sourceId: jsonSerialization['sourceId'] as String,
|
||||
language: jsonSerialization['language'] as String,
|
||||
glossLanguage: jsonSerialization['glossLanguage'] as String,
|
||||
headword: jsonSerialization['headword'] as String,
|
||||
reading: jsonSerialization['reading'] as String?,
|
||||
rank: jsonSerialization['rank'] as int,
|
||||
labels: jsonSerialization['labels'] as String,
|
||||
searchKeys: jsonSerialization['searchKeys'] as String,
|
||||
looseKeys: jsonSerialization['looseKeys'] as String,
|
||||
entry: jsonSerialization['entry'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
/// The database id, set if the object has been inserted into the
|
||||
/// database or if it has been fetched from the database. Otherwise,
|
||||
/// the id will be null.
|
||||
int? id;
|
||||
|
||||
/// The source its file names (`jmdict`).
|
||||
String source;
|
||||
|
||||
/// Its id in the source.
|
||||
String sourceId;
|
||||
|
||||
/// The words' language, a BCP 47 tag (`ja`).
|
||||
String language;
|
||||
|
||||
/// The meanings' language (`en`).
|
||||
String glossLanguage;
|
||||
|
||||
/// How the word is shown.
|
||||
String headword;
|
||||
|
||||
/// How it is read; null when the headword is its own reading.
|
||||
String? reading;
|
||||
|
||||
/// Its order among the source's entries, lower first.
|
||||
int rank;
|
||||
|
||||
/// Its labels between bars (`|common|jlpt:n5|`), for LIKE to find one.
|
||||
String labels;
|
||||
|
||||
/// What a search matches, lower case, between bars
|
||||
/// (`|食べる|たべる|taberu|eat|`).
|
||||
String searchKeys;
|
||||
|
||||
/// What a search matches after every searchKeys match: spellings people
|
||||
/// type that aren't quite right (`sushi` for すうし), between bars too.
|
||||
String looseKeys;
|
||||
|
||||
/// The entry as cards take it: its JSON, as the file holds it.
|
||||
String entry;
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryEntry]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
DictionaryEntry copyWith({
|
||||
int? id,
|
||||
String? source,
|
||||
String? sourceId,
|
||||
String? language,
|
||||
String? glossLanguage,
|
||||
String? headword,
|
||||
String? reading,
|
||||
int? rank,
|
||||
String? labels,
|
||||
String? searchKeys,
|
||||
String? looseKeys,
|
||||
String? entry,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'DictionaryEntry',
|
||||
if (id != null) 'id': id,
|
||||
'source': source,
|
||||
'sourceId': sourceId,
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'headword': headword,
|
||||
if (reading != null) 'reading': reading,
|
||||
'rank': rank,
|
||||
'labels': labels,
|
||||
'searchKeys': searchKeys,
|
||||
'looseKeys': looseKeys,
|
||||
'entry': entry,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'DictionaryEntry',
|
||||
if (id != null) 'id': id,
|
||||
'source': source,
|
||||
'sourceId': sourceId,
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'headword': headword,
|
||||
if (reading != null) 'reading': reading,
|
||||
'rank': rank,
|
||||
'labels': labels,
|
||||
'searchKeys': searchKeys,
|
||||
'looseKeys': looseKeys,
|
||||
'entry': entry,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _DictionaryEntryImpl extends DictionaryEntry {
|
||||
_DictionaryEntryImpl({
|
||||
int? id,
|
||||
required String source,
|
||||
required String sourceId,
|
||||
required String language,
|
||||
required String glossLanguage,
|
||||
required String headword,
|
||||
String? reading,
|
||||
required int rank,
|
||||
required String labels,
|
||||
required String searchKeys,
|
||||
required String looseKeys,
|
||||
required String entry,
|
||||
}) : super._(
|
||||
id: id,
|
||||
source: source,
|
||||
sourceId: sourceId,
|
||||
language: language,
|
||||
glossLanguage: glossLanguage,
|
||||
headword: headword,
|
||||
reading: reading,
|
||||
rank: rank,
|
||||
labels: labels,
|
||||
searchKeys: searchKeys,
|
||||
looseKeys: looseKeys,
|
||||
entry: entry,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryEntry]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
DictionaryEntry copyWith({
|
||||
Object? id = _Undefined,
|
||||
String? source,
|
||||
String? sourceId,
|
||||
String? language,
|
||||
String? glossLanguage,
|
||||
String? headword,
|
||||
Object? reading = _Undefined,
|
||||
int? rank,
|
||||
String? labels,
|
||||
String? searchKeys,
|
||||
String? looseKeys,
|
||||
String? entry,
|
||||
}) {
|
||||
return DictionaryEntry(
|
||||
id: id is int? ? id : this.id,
|
||||
source: source ?? this.source,
|
||||
sourceId: sourceId ?? this.sourceId,
|
||||
language: language ?? this.language,
|
||||
glossLanguage: glossLanguage ?? this.glossLanguage,
|
||||
headword: headword ?? this.headword,
|
||||
reading: reading is String? ? reading : this.reading,
|
||||
rank: rank ?? this.rank,
|
||||
labels: labels ?? this.labels,
|
||||
searchKeys: searchKeys ?? this.searchKeys,
|
||||
looseKeys: looseKeys ?? this.looseKeys,
|
||||
entry: entry ?? this.entry,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:halkyon_learn_client/src/protocol/protocol.dart' as _itx5j3f5;
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
|
||||
/// A dictionary entry as the app receives it: what it shows and turns into a
|
||||
/// card, without what only the search needs.
|
||||
abstract class DictionaryHit
|
||||
implements _isc.SerializableModel, _isc.ProtocolSerialization {
|
||||
DictionaryHit._({
|
||||
required this.source,
|
||||
required this.sourceId,
|
||||
required this.headword,
|
||||
this.reading,
|
||||
required this.labels,
|
||||
required this.entry,
|
||||
});
|
||||
|
||||
factory DictionaryHit({
|
||||
required String source,
|
||||
required String sourceId,
|
||||
required String headword,
|
||||
String? reading,
|
||||
required List<String> labels,
|
||||
required String entry,
|
||||
}) = _DictionaryHitImpl;
|
||||
|
||||
factory DictionaryHit.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return DictionaryHit(
|
||||
source: jsonSerialization['source'] as String,
|
||||
sourceId: jsonSerialization['sourceId'] as String,
|
||||
headword: jsonSerialization['headword'] as String,
|
||||
reading: jsonSerialization['reading'] as String?,
|
||||
labels: _itx5j3f5.Protocol().deserialize<List<String>>(
|
||||
jsonSerialization['labels'],
|
||||
),
|
||||
entry: jsonSerialization['entry'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
/// The source and the entry's id in it: a card keeps them, to find the
|
||||
/// word again and not to add it twice.
|
||||
String source;
|
||||
|
||||
String sourceId;
|
||||
|
||||
String headword;
|
||||
|
||||
/// Null when the headword is its own reading.
|
||||
String? reading;
|
||||
|
||||
/// `common`, `jlpt:n5`, …
|
||||
List<String> labels;
|
||||
|
||||
/// The entry as cards take it, as JSON (the curator's README).
|
||||
String entry;
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryHit]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
DictionaryHit copyWith({
|
||||
String? source,
|
||||
String? sourceId,
|
||||
String? headword,
|
||||
String? reading,
|
||||
List<String>? labels,
|
||||
String? entry,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'DictionaryHit',
|
||||
'source': source,
|
||||
'sourceId': sourceId,
|
||||
'headword': headword,
|
||||
if (reading != null) 'reading': reading,
|
||||
'labels': labels.toJson(),
|
||||
'entry': entry,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'DictionaryHit',
|
||||
'source': source,
|
||||
'sourceId': sourceId,
|
||||
'headword': headword,
|
||||
if (reading != null) 'reading': reading,
|
||||
'labels': labels.toJson(),
|
||||
'entry': entry,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _DictionaryHitImpl extends DictionaryHit {
|
||||
_DictionaryHitImpl({
|
||||
required String source,
|
||||
required String sourceId,
|
||||
required String headword,
|
||||
String? reading,
|
||||
required List<String> labels,
|
||||
required String entry,
|
||||
}) : super._(
|
||||
source: source,
|
||||
sourceId: sourceId,
|
||||
headword: headword,
|
||||
reading: reading,
|
||||
labels: labels,
|
||||
entry: entry,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [DictionaryHit]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
DictionaryHit copyWith({
|
||||
String? source,
|
||||
String? sourceId,
|
||||
String? headword,
|
||||
Object? reading = _Undefined,
|
||||
List<String>? labels,
|
||||
String? entry,
|
||||
}) {
|
||||
return DictionaryHit(
|
||||
source: source ?? this.source,
|
||||
sourceId: sourceId ?? this.sourceId,
|
||||
headword: headword ?? this.headword,
|
||||
reading: reading is String? ? reading : this.reading,
|
||||
labels: labels ?? this.labels.map((e0) => e0).toList(),
|
||||
entry: entry ?? this.entry,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:halkyon_learn_client/src/protocol/protocol.dart' as _itx5j3f5;
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
import '../dictionary/dictionary_credit.dart' as _it7o1p0g;
|
||||
|
||||
/// A dictionary the instance holds: one source in one meaning language, as
|
||||
/// loaded from its file. The app lists the credits where it names its data
|
||||
/// sources; the file's hash tells the loader whether it changed since.
|
||||
abstract class DictionarySource
|
||||
implements _isc.SerializableModel, _isc.ProtocolSerialization {
|
||||
DictionarySource._({
|
||||
this.id,
|
||||
required this.source,
|
||||
required this.sourceVersion,
|
||||
required this.language,
|
||||
required this.glossLanguage,
|
||||
required this.license,
|
||||
required this.credits,
|
||||
required this.entryCount,
|
||||
required this.fileName,
|
||||
required this.fileHash,
|
||||
required this.loadedAt,
|
||||
});
|
||||
|
||||
factory DictionarySource({
|
||||
int? id,
|
||||
required String source,
|
||||
required String sourceVersion,
|
||||
required String language,
|
||||
required String glossLanguage,
|
||||
required String license,
|
||||
required List<_it7o1p0g.DictionaryCredit> credits,
|
||||
required int entryCount,
|
||||
required String fileName,
|
||||
required String fileHash,
|
||||
required DateTime loadedAt,
|
||||
}) = _DictionarySourceImpl;
|
||||
|
||||
factory DictionarySource.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return DictionarySource(
|
||||
id: jsonSerialization['id'] as int?,
|
||||
source: jsonSerialization['source'] as String,
|
||||
sourceVersion: jsonSerialization['sourceVersion'] as String,
|
||||
language: jsonSerialization['language'] as String,
|
||||
glossLanguage: jsonSerialization['glossLanguage'] as String,
|
||||
license: jsonSerialization['license'] as String,
|
||||
credits: _itx5j3f5.Protocol()
|
||||
.deserialize<List<_it7o1p0g.DictionaryCredit>>(
|
||||
jsonSerialization['credits'],
|
||||
),
|
||||
entryCount: jsonSerialization['entryCount'] as int,
|
||||
fileName: jsonSerialization['fileName'] as String,
|
||||
fileHash: jsonSerialization['fileHash'] as String,
|
||||
loadedAt: _isc.DateTimeJsonExtension.fromJson(
|
||||
jsonSerialization['loadedAt'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// The database id, set if the object has been inserted into the
|
||||
/// database or if it has been fetched from the database. Otherwise,
|
||||
/// the id will be null.
|
||||
int? id;
|
||||
|
||||
/// The source (`jmdict`).
|
||||
String source;
|
||||
|
||||
/// Its version (`3.6.2 (2026-10-05)`).
|
||||
String sourceVersion;
|
||||
|
||||
/// The words' language (`ja`).
|
||||
String language;
|
||||
|
||||
/// The meanings' language (`en`).
|
||||
String glossLanguage;
|
||||
|
||||
/// The data's licence, an SPDX identifier.
|
||||
String license;
|
||||
|
||||
/// Everything it is drawn from.
|
||||
List<_it7o1p0g.DictionaryCredit> credits;
|
||||
|
||||
/// How many entries it has.
|
||||
int entryCount;
|
||||
|
||||
/// The file it was loaded from, and the file's SHA-256.
|
||||
String fileName;
|
||||
|
||||
String fileHash;
|
||||
|
||||
/// When it was loaded, in UTC.
|
||||
DateTime loadedAt;
|
||||
|
||||
/// Returns a shallow copy of this [DictionarySource]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
DictionarySource copyWith({
|
||||
int? id,
|
||||
String? source,
|
||||
String? sourceVersion,
|
||||
String? language,
|
||||
String? glossLanguage,
|
||||
String? license,
|
||||
List<_it7o1p0g.DictionaryCredit>? credits,
|
||||
int? entryCount,
|
||||
String? fileName,
|
||||
String? fileHash,
|
||||
DateTime? loadedAt,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'DictionarySource',
|
||||
if (id != null) 'id': id,
|
||||
'source': source,
|
||||
'sourceVersion': sourceVersion,
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'license': license,
|
||||
'credits': credits.toJson(valueToJson: (v) => v.toJson()),
|
||||
'entryCount': entryCount,
|
||||
'fileName': fileName,
|
||||
'fileHash': fileHash,
|
||||
'loadedAt': loadedAt.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'DictionarySource',
|
||||
if (id != null) 'id': id,
|
||||
'source': source,
|
||||
'sourceVersion': sourceVersion,
|
||||
'language': language,
|
||||
'glossLanguage': glossLanguage,
|
||||
'license': license,
|
||||
'credits': credits.toJson(valueToJson: (v) => v.toJsonForProtocol()),
|
||||
'entryCount': entryCount,
|
||||
'fileName': fileName,
|
||||
'fileHash': fileHash,
|
||||
'loadedAt': loadedAt.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _DictionarySourceImpl extends DictionarySource {
|
||||
_DictionarySourceImpl({
|
||||
int? id,
|
||||
required String source,
|
||||
required String sourceVersion,
|
||||
required String language,
|
||||
required String glossLanguage,
|
||||
required String license,
|
||||
required List<_it7o1p0g.DictionaryCredit> credits,
|
||||
required int entryCount,
|
||||
required String fileName,
|
||||
required String fileHash,
|
||||
required DateTime loadedAt,
|
||||
}) : super._(
|
||||
id: id,
|
||||
source: source,
|
||||
sourceVersion: sourceVersion,
|
||||
language: language,
|
||||
glossLanguage: glossLanguage,
|
||||
license: license,
|
||||
credits: credits,
|
||||
entryCount: entryCount,
|
||||
fileName: fileName,
|
||||
fileHash: fileHash,
|
||||
loadedAt: loadedAt,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [DictionarySource]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
DictionarySource copyWith({
|
||||
Object? id = _Undefined,
|
||||
String? source,
|
||||
String? sourceVersion,
|
||||
String? language,
|
||||
String? glossLanguage,
|
||||
String? license,
|
||||
List<_it7o1p0g.DictionaryCredit>? credits,
|
||||
int? entryCount,
|
||||
String? fileName,
|
||||
String? fileHash,
|
||||
DateTime? loadedAt,
|
||||
}) {
|
||||
return DictionarySource(
|
||||
id: id is int? ? id : this.id,
|
||||
source: source ?? this.source,
|
||||
sourceVersion: sourceVersion ?? this.sourceVersion,
|
||||
language: language ?? this.language,
|
||||
glossLanguage: glossLanguage ?? this.glossLanguage,
|
||||
license: license ?? this.license,
|
||||
credits: credits ?? this.credits.map((e0) => e0.copyWith()).toList(),
|
||||
entryCount: entryCount ?? this.entryCount,
|
||||
fileName: fileName ?? this.fileName,
|
||||
fileHash: fileHash ?? this.fileHash,
|
||||
loadedAt: loadedAt ?? this.loadedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,10 @@
|
|||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:halkyon_learn_client/src/protocol/auth/device.dart'
|
||||
as _ieqh4yr9;
|
||||
import 'package:halkyon_learn_client/src/protocol/dictionary/dictionary_hit.dart'
|
||||
as _iqbqiphu;
|
||||
import 'package:halkyon_learn_client/src/protocol/dictionary/dictionary_source.dart'
|
||||
as _i8vj64sp;
|
||||
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
|
||||
as _iacc;
|
||||
import 'package:serverpod_auth_idp_client/serverpod_auth_idp_client.dart'
|
||||
|
|
@ -31,6 +35,10 @@ import 'auth/github_sign_in_refused_exception.dart' as _i0xfcu5n;
|
|||
import 'card/card.dart' as _ipiw1cmx;
|
||||
import 'card/card_revision.dart' as _ipbyuef1;
|
||||
import 'common/not_found_exception.dart' as _i8oee73b;
|
||||
import 'dictionary/dictionary_credit.dart' as _ii4hopsr;
|
||||
import 'dictionary/dictionary_entry.dart' as _i4ipxv77;
|
||||
import 'dictionary/dictionary_hit.dart' as _ivbh47kc;
|
||||
import 'dictionary/dictionary_source.dart' as _ie12eb65;
|
||||
import 'instance/instance_info.dart' as _iskrg2g3;
|
||||
import 'learning_path/learning_path.dart' as _ivt5m868;
|
||||
import 'learning_path/learning_path_answer.dart' as _iy9sv3bs;
|
||||
|
|
@ -57,6 +65,10 @@ export 'auth/github_sign_in_refused_exception.dart';
|
|||
export 'card/card.dart';
|
||||
export 'card/card_revision.dart';
|
||||
export 'common/not_found_exception.dart';
|
||||
export 'dictionary/dictionary_credit.dart';
|
||||
export 'dictionary/dictionary_entry.dart';
|
||||
export 'dictionary/dictionary_hit.dart';
|
||||
export 'dictionary/dictionary_source.dart';
|
||||
export 'instance/instance_info.dart';
|
||||
export 'learning_path/learning_path.dart';
|
||||
export 'learning_path/learning_path_answer.dart';
|
||||
|
|
@ -1993,6 +2005,18 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
if (t == _i8oee73b.NotFoundException) {
|
||||
return _i8oee73b.NotFoundException.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ii4hopsr.DictionaryCredit) {
|
||||
return _ii4hopsr.DictionaryCredit.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i4ipxv77.DictionaryEntry) {
|
||||
return _i4ipxv77.DictionaryEntry.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ivbh47kc.DictionaryHit) {
|
||||
return _ivbh47kc.DictionaryHit.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ie12eb65.DictionarySource) {
|
||||
return _ie12eb65.DictionarySource.fromJson(data) as T;
|
||||
}
|
||||
if (t == _iskrg2g3.InstanceInfo) {
|
||||
return _iskrg2g3.InstanceInfo.fromJson(data) as T;
|
||||
}
|
||||
|
|
@ -2082,6 +2106,22 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
return (data != null ? _i8oee73b.NotFoundException.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ii4hopsr.DictionaryCredit?>()) {
|
||||
return (data != null ? _ii4hopsr.DictionaryCredit.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_i4ipxv77.DictionaryEntry?>()) {
|
||||
return (data != null ? _i4ipxv77.DictionaryEntry.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ivbh47kc.DictionaryHit?>()) {
|
||||
return (data != null ? _ivbh47kc.DictionaryHit.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ie12eb65.DictionarySource?>()) {
|
||||
return (data != null ? _ie12eb65.DictionarySource.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_iskrg2g3.InstanceInfo?>()) {
|
||||
return (data != null ? _iskrg2g3.InstanceInfo.fromJson(data) : null) as T;
|
||||
}
|
||||
|
|
@ -2141,12 +2181,33 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
return (data as List).map((e) => deserialize<_isc.UuidValue>(e)).toList()
|
||||
as T;
|
||||
}
|
||||
if (t == List<String>) {
|
||||
return (data as List).map((e) => deserialize<String>(e)).toList() as T;
|
||||
}
|
||||
if (t == List<_ii4hopsr.DictionaryCredit>) {
|
||||
return (data as List)
|
||||
.map((e) => deserialize<_ii4hopsr.DictionaryCredit>(e))
|
||||
.toList()
|
||||
as T;
|
||||
}
|
||||
if (t == List<_ieqh4yr9.Device>) {
|
||||
return (data as List)
|
||||
.map((e) => deserialize<_ieqh4yr9.Device>(e))
|
||||
.toList()
|
||||
as T;
|
||||
}
|
||||
if (t == List<_i8vj64sp.DictionarySource>) {
|
||||
return (data as List)
|
||||
.map((e) => deserialize<_i8vj64sp.DictionarySource>(e))
|
||||
.toList()
|
||||
as T;
|
||||
}
|
||||
if (t == List<_iqbqiphu.DictionaryHit>) {
|
||||
return (data as List)
|
||||
.map((e) => deserialize<_iqbqiphu.DictionaryHit>(e))
|
||||
.toList()
|
||||
as T;
|
||||
}
|
||||
try {
|
||||
return _iaic.Protocol().deserialize<T>(data, t);
|
||||
} on _isc.DeserializationTypeNotFoundException catch (_) {}
|
||||
|
|
@ -2171,6 +2232,10 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
_ipiw1cmx.Card => 'Card',
|
||||
_ipbyuef1.CardRevision => 'CardRevision',
|
||||
_i8oee73b.NotFoundException => 'NotFoundException',
|
||||
_ii4hopsr.DictionaryCredit => 'DictionaryCredit',
|
||||
_i4ipxv77.DictionaryEntry => 'DictionaryEntry',
|
||||
_ivbh47kc.DictionaryHit => 'DictionaryHit',
|
||||
_ie12eb65.DictionarySource => 'DictionarySource',
|
||||
_iskrg2g3.InstanceInfo => 'InstanceInfo',
|
||||
_ivt5m868.LearningPath => 'LearningPath',
|
||||
_iy9sv3bs.LearningPathAnswer => 'LearningPathAnswer',
|
||||
|
|
@ -2224,6 +2289,14 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
return 'CardRevision';
|
||||
case _i8oee73b.NotFoundException():
|
||||
return 'NotFoundException';
|
||||
case _ii4hopsr.DictionaryCredit():
|
||||
return 'DictionaryCredit';
|
||||
case _i4ipxv77.DictionaryEntry():
|
||||
return 'DictionaryEntry';
|
||||
case _ivbh47kc.DictionaryHit():
|
||||
return 'DictionaryHit';
|
||||
case _ie12eb65.DictionarySource():
|
||||
return 'DictionarySource';
|
||||
case _iskrg2g3.InstanceInfo():
|
||||
return 'InstanceInfo';
|
||||
case _ivt5m868.LearningPath():
|
||||
|
|
@ -2314,6 +2387,18 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
if (dataClassName == 'NotFoundException') {
|
||||
return deserialize<_i8oee73b.NotFoundException>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'DictionaryCredit') {
|
||||
return deserialize<_ii4hopsr.DictionaryCredit>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'DictionaryEntry') {
|
||||
return deserialize<_i4ipxv77.DictionaryEntry>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'DictionaryHit') {
|
||||
return deserialize<_ivbh47kc.DictionaryHit>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'DictionarySource') {
|
||||
return deserialize<_ie12eb65.DictionarySource>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'InstanceInfo') {
|
||||
return deserialize<_iskrg2g3.InstanceInfo>(data['data']);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue