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:
Tizian 「ティツィアーン」 2026-10-09 00:51:27 +02:00
commit 3013bc04b3
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
48 changed files with 16048 additions and 73 deletions

View file

@ -20,3 +20,7 @@ config/firebase_service_account_key.json
# SQLite databases created by the ephemeral test database
**/sp_*.db*
# Dictionary files: made by halkyon_learn_curator, not kept in git.
/dictionaries/*.jsonl
/dictionaries/*.jsonl.gz

View file

@ -9,6 +9,26 @@ Start your server by running:
When you are finished, you can shut down the running server with `Q`.
## Dictionaries
The dictionaries people look words up in (JMdict, …) are reference data the
server holds for everyone. They come as dictionary files, which
`halkyon_learn_curator` makes from the sources' downloads (its README says how).
At every start, the server loads the files in its `dictionaries` folder that
changed since they were last loaded (by their SHA-256): in the background, a
source at a time, and all at once, so searches meanwhile still find the old
entries. A file it can't read is logged and left out.
- **Development:** put the file into `halkyon_learn_server/dictionaries/` and
restart `serverpod start`.
- **An instance:** put it into `deploy/dictionaries/` beside `compose.yaml`
(mounted read-only as `/app/dictionaries`) and restart the server container.
`DICTIONARIES_DIR` names another folder.
JMdict in English, with the JLPT levels, is about 17 MB gzipped and takes the
server half a minute to load (219,000 entries). Its licence (CC BY-SA 4.0) asks
for attribution: the app lists the credits each file carries.
## Licence
Copyright (C) 2026 The Halkyon Learn contributors

View file

@ -0,0 +1,5 @@
# Dictionary files
Dictionary files (`*.jsonl`, `*.jsonl.gz`) for the server to load at start; see
the server's README. They are downloads turned into files by `halkyon_learn_curator`,
not kept in git.

View file

@ -1,4 +1,8 @@
import 'dart:async';
import 'dart:io';
import 'package:halkyon_learn_server/src/auth/auth_config.dart';
import 'package:halkyon_learn_server/src/dictionary/dictionary_loader.dart';
import 'package:halkyon_learn_server/src/generated/serverpod.dart';
import 'package:serverpod_auth_idp_server/core.dart';
@ -37,6 +41,17 @@ Future<void> run(List<String> args) async {
.cron('47 3 * * *')
.filePruning
.pruneFiles();
// The dictionaries the operator put into the server's folder, those that
// changed since; in the background, as loading takes a minute or two.
unawaited(
pod.withSession(
(session) => loadDictionaries(
session,
Directory(Platform.environment['DICTIONARIES_DIR'] ?? 'dictionaries'),
),
),
);
}
/// The identifier of the daily pruning.

View file

@ -0,0 +1,11 @@
### Who made what a dictionary is drawn from, under which licence.
class: DictionaryCredit
fields:
### What it is (`JMdict`).
name: String
### Who made it.
by: String
### Its licence, an SPDX identifier.
license: String
### Where it is described.
url: String

View file

@ -0,0 +1,139 @@
import 'package:halkyon_learn_server/src/dictionary/dictionary_search.dart';
import 'package:halkyon_learn_server/src/generated/protocol.dart';
import 'package:serverpod/serverpod.dart';
/// 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.
class DictionaryEndpoint extends Endpoint {
@override
bool get requireLogin => true;
/// The most a search returns.
static const maxSearchResults = 50;
/// The most one page of labelled entries holds.
static const maxPage = 500;
/// The dictionaries there are, with whose work they are.
Future<List<DictionarySource>> dictionaries(Session session) =>
DictionarySource.db.find(
session,
orderBy: (t) => t.language,
);
/// 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).
Future<List<DictionaryHit>> search(
Session session,
String language,
String glossLanguage,
String query, {
int? limit,
}) async {
final variants = queryVariants(language, query);
if (variants.isEmpty) {
return const [];
}
final count = (limit ?? 30).clamp(1, maxSearchResults);
Future<List<DictionaryEntry>> matching(String Function(String) pattern) =>
DictionaryEntry.db.find(
session,
where: (t) {
Expression<Object?> keys = Constant.bool(false);
for (final variant in variants) {
final like = pattern(likeEscaped(variant));
keys = keys | t.searchKeys.like(like) | t.looseKeys.like(like);
}
return t.language.equals(language) &
t.glossLanguage.equals(glossLanguage) &
keys;
},
orderBy: (t) => t.rank,
limit: count,
);
// SELECT … WHERE "searchKeys" LIKE '%|eat|%' OR "looseKeys" LIKE … ORDER
// BY "rank" LIMIT …, then LIKE '%|eat%' for keys starting with it.
final candidates = {
for (final entry in [
...await matching((key) => '%|$key|%'),
...await matching((key) => '%|$key%'),
])
entry.id: entry,
}.values.toList();
int tier(DictionaryEntry entry) {
bool any(String keys, String Function(String) pattern) => variants.any(
(variant) => keys.contains(pattern(variant.replaceAll('|', ' '))),
);
return any(entry.searchKeys, (key) => '|$key|')
? 0
: any(entry.looseKeys, (key) => '|$key|')
? 1
: any(entry.searchKeys, (key) => '|$key')
? 2
: 3;
}
final tiers = {for (final entry in candidates) entry.id: tier(entry)};
candidates.sort(
(a, b) => switch (tiers[a.id]!.compareTo(tiers[b.id]!)) {
0 => a.rank.compareTo(b.rank),
final order => order,
},
);
return [for (final entry in candidates.take(count)) _hit(entry)];
}
/// How many entries of the dictionary of [language] with meanings in
/// [glossLanguage] carry [label].
Future<int> countLabelled(
Session session,
String language,
String glossLanguage,
String label,
) => DictionaryEntry.db.count(
session,
where: (t) =>
t.language.equals(language) &
t.glossLanguage.equals(glossLanguage) &
t.labels.like('%|${likeEscaped(label)}|%'),
);
/// The entries that carry [label], in the dictionary's order: [limit] of
/// them (100 unless given, at most [maxPage]) after the first [offset].
Future<List<DictionaryHit>> labelled(
Session session,
String language,
String glossLanguage,
String label, {
int? offset,
int? limit,
}) async => [
for (final entry in await DictionaryEntry.db.find(
session,
where: (t) =>
t.language.equals(language) &
t.glossLanguage.equals(glossLanguage) &
t.labels.like('%|${likeEscaped(label)}|%'),
orderBy: (t) => t.rank,
offset: (offset ?? 0).clamp(0, 1 << 30),
limit: (limit ?? 100).clamp(1, maxPage),
))
_hit(entry),
];
DictionaryHit _hit(DictionaryEntry entry) => DictionaryHit(
source: entry.source,
sourceId: entry.sourceId,
headword: entry.headword,
reading: entry.reading,
labels: [
for (final label in entry.labels.split('|'))
if (label.isNotEmpty) label,
],
entry: entry.entry,
);
}

View file

@ -0,0 +1,40 @@
### 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.
class: DictionaryEntry
table: dictionary_entry
fields:
### The source its file names (`jmdict`).
source: String
### Its id in the source.
sourceId: String
### The words' language, a BCP 47 tag (`ja`).
language: String
### The meanings' language (`en`).
glossLanguage: String
### How the word is shown.
headword: String
### How it is read; null when the headword is its own reading.
reading: String?
### Its order among the source's entries, lower first.
rank: int
### Its labels between bars (`|common|jlpt:n5|`), for LIKE to find one.
labels: String
### What a search matches, lower case, between bars
### (`|食べる|たべる|taberu|eat|`).
searchKeys: String
### What a search matches after every searchKeys match: spellings people
### type that aren't quite right (`sushi` for すうし), between bars too.
looseKeys: String
### The entry as cards take it: its JSON, as the file holds it.
entry: String
indexes:
# An entry by its source and id; loading replaces one source at a time.
dictionary_entry_source_idx:
fields: source, glossLanguage, sourceId
unique: true
# A language's entries in their order, for what is picked by a label.
dictionary_entry_rank_idx:
fields: language, glossLanguage, rank

View file

@ -0,0 +1,15 @@
### A dictionary entry as the app receives it: what it shows and turns into a
### card, without what only the search needs.
class: DictionaryHit
fields:
### The source and the entry's id in it: a card keeps them, to find the
### word again and not to add it twice.
source: String
sourceId: String
headword: String
### Null when the headword is its own reading.
reading: String?
### `common`, `jlpt:n5`, …
labels: List<String>
### The entry as cards take it, as JSON (the curator's README).
entry: String

View file

@ -0,0 +1,174 @@
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:halkyon_learn_server/src/dictionary/dictionary_search.dart';
import 'package:halkyon_learn_server/src/generated/protocol.dart';
import 'package:serverpod/serverpod.dart';
/// The dictionary file format the loader reads, and the newest version of
/// it (the curator's README describes it).
const dictionaryFormat = 'halkyon-dictionary';
const dictionaryFormatVersion = 1;
/// How many entries go into the database at once.
const _batch = 1000;
/// Loads every dictionary file in [directory] (`*.jsonl`, or gzipped
/// `*.jsonl.gz`) that changed since it was loaded: the operator drops a
/// file the curator wrote into the server's `dictionaries` folder, and the
/// server loads it on its next start. A file that can't be read is logged
/// and left out, the others still load. No folder, nothing to load.
Future<void> loadDictionaries(Session session, Directory directory) async {
if (!directory.existsSync()) {
return;
}
final files = [
for (final entity in directory.listSync())
if (entity is File &&
(entity.path.endsWith('.jsonl') || entity.path.endsWith('.jsonl.gz')))
entity,
]..sort((a, b) => a.path.compareTo(b.path));
for (final file in files) {
try {
await loadDictionaryFile(session, file);
} on Object catch (error, st) {
session.log(
'Loading the dictionary ${file.path} failed.',
level: LogLevel.error,
exception: error,
stackTrace: st,
);
}
}
}
/// Loads the dictionary [file] unless it is loaded as it is: its source's
/// entries in its meaning language are replaced by the file's, all at once,
/// so a search meanwhile finds the old ones. Returns whether it loaded.
Future<bool> loadDictionaryFile(Session session, File file) async {
final hash = (await sha256.bind(file.openRead()).first).toString();
final lines = _lines(file);
final header = await _header(await lines.first);
final source = header['source']! as String;
final glossLanguage = header['glossLanguage']! as String;
final loaded = await DictionarySource.db.findFirstRow(
session,
where: (t) =>
t.source.equals(source) & t.glossLanguage.equals(glossLanguage),
);
if (loaded?.fileHash == hash) {
return false;
}
final watch = Stopwatch()..start();
final language = header['language']! as String;
final name = file.uri.pathSegments.last;
var count = 0;
await session.db.transaction((transaction) async {
await DictionaryEntry.db.deleteWhere(
session,
where: (t) =>
t.source.equals(source) & t.glossLanguage.equals(glossLanguage),
transaction: transaction,
);
final batch = <DictionaryEntry>[];
Future<void> flush() async {
await DictionaryEntry.db.insert(
session,
batch,
transaction: transaction,
);
count += batch.length;
batch.clear();
}
await for (final line in _lines(file).skip(1)) {
if (line.trim().isEmpty) {
continue;
}
final json = jsonDecode(line) as Map<String, Object?>;
batch.add(
DictionaryEntry(
source: source,
sourceId: json['id']! as String,
language: language,
glossLanguage: glossLanguage,
headword: json['headword']! as String,
reading: json['reading'] as String?,
rank: json['rank']! as int,
labels: barred((json['labels']! as List).cast<String>()),
searchKeys: barred((json['keys']! as List).cast<String>()),
looseKeys: barred(
(json['looseKeys'] as List? ?? const []).cast<String>(),
),
entry: jsonEncode(json['entry']),
),
);
if (batch.length == _batch) {
await flush();
}
}
await flush();
final row = DictionarySource(
id: loaded?.id,
source: source,
sourceVersion: header['sourceVersion']! as String,
language: language,
glossLanguage: glossLanguage,
license: header['license']! as String,
credits: [
for (final credit
in (header['credits']! as List).cast<Map<String, Object?>>())
DictionaryCredit.fromJson(credit),
],
entryCount: count,
fileName: name,
fileHash: hash,
loadedAt: DateTime.now().toUtc(),
);
if (loaded == null) {
await DictionarySource.db.insertRow(
session,
row,
transaction: transaction,
);
} else {
await DictionarySource.db.updateRow(
session,
row,
transaction: transaction,
);
}
});
session.log(
'Loaded the dictionary $name: $count entries of $source '
'(${header['sourceVersion']}) in ${watch.elapsed.inSeconds} s.',
);
return true;
}
/// The lines of [file], unzipped when its name ends in `.gz`.
Stream<String> _lines(File file) {
final bytes = file.openRead();
return (file.path.endsWith('.gz') ? bytes.transform(gzip.decoder) : bytes)
.transform(utf8.decoder)
.transform(const LineSplitter());
}
/// The file's first line, if it is a header the loader understands.
Future<Map<String, Object?>> _header(String line) async {
final header = jsonDecode(line);
if (header is! Map<String, Object?> || header['format'] != dictionaryFormat) {
throw const FormatException('Not a dictionary file.');
}
final version = header['formatVersion'];
if (version is! int || version > dictionaryFormatVersion) {
throw FormatException(
'Dictionary format $version; this server reads up to '
'$dictionaryFormatVersion.',
);
}
return header;
}

View file

@ -0,0 +1,43 @@
/// What a search for [query] in a dictionary of [language] looks for: the
/// query as typed, in lower case, trimmed. In Japanese also with katakana as
/// hiragana, and long vowels with macrons written out (`tōkyō` as
/// `toukyou`), as the keys hold them. Empty for nothing to look for.
///
/// Everything else specific to a language is in the keys, which the curator
/// made. Romaji in the Kunrei style (`si`, `tu`) isn't turned into Hepburn:
/// meanings would turn with it (`time` into `chime`).
List<String> queryVariants(String language, String query) {
final typed = query.trim().toLowerCase().replaceAll(RegExp(r'\s+'), ' ');
if (typed.isEmpty) {
return const [];
}
return {
typed,
if (language == 'ja') ...[_toHiragana(typed), _withoutMacrons(typed)],
}.toList();
}
/// [text] for a LIKE pattern: its wildcards and the escape character
/// itself escaped, and the bars between keys taken out.
String likeEscaped(String text) => text
.replaceAll(r'\', r'\\')
.replaceAll('%', r'\%')
.replaceAll('_', r'\_')
.replaceAll('|', ' ');
/// [values] between bars, as a dictionary entry's labels and search keys
/// are kept, for LIKE to find one whole (`%|eat|%`) or by its start.
String barred(Iterable<String> values) =>
'|${[for (final value in values) value.replaceAll('|', ' ')].join('|')}|';
String _toHiragana(String text) => String.fromCharCodes([
for (final code in text.runes)
if (code >= 0x30A1 && code <= 0x30F6) code - 0x60 else code,
]);
String _withoutMacrons(String text) => text
.replaceAll('ā', 'aa')
.replaceAll('ī', 'ii')
.replaceAll('ū', 'uu')
.replaceAll('ē', 'ee')
.replaceAll('ō', 'ou');

View file

@ -0,0 +1,29 @@
### 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.
class: DictionarySource
table: dictionary_source
fields:
### The source (`jmdict`).
source: String
### Its version (`3.6.2 (2026-10-05)`).
sourceVersion: String
### The words' language (`ja`).
language: String
### The meanings' language (`en`).
glossLanguage: String
### The data's licence, an SPDX identifier.
license: String
### Everything it is drawn from.
credits: List<DictionaryCredit>
### How many entries it has.
entryCount: int
### The file it was loaded from, and the file's SHA-256.
fileName: String
fileHash: String
### When it was loaded, in UTC.
loadedAt: DateTime
indexes:
dictionary_source_idx:
fields: source, glossLanguage
unique: true

View file

@ -11,6 +11,7 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:typed_data' as _idt;
import 'package:serverpod/serverpod.dart' as _is;
/// A file in a person's content, an image or a sound (ADR 0004). This row is synced;

View file

@ -11,6 +11,7 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:serverpod/serverpod.dart' as _is;
import '../auth/github_sign_in_refusal.dart' as _irgbwy1y;
/// Signing in with GitHub, or linking a GitHub account, was refused; nothing

View file

@ -13,6 +13,7 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_learn_server/src/generated/protocol.dart' as _i5lsenq5;
import 'package:serverpod/serverpod.dart' as _is;
import '../studyset/studyset.dart' as _ie5k1jc2;
/// A flashcard in a studyset. Its content lives in its revisions

View file

@ -12,8 +12,10 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:typed_data' as _idt;
import 'package:halkyon_learn_server/src/generated/protocol.dart' as _i5lsenq5;
import 'package:serverpod/serverpod.dart' as _is;
import '../card/card.dart' as _i4926i81;
/// One version of a card's content, never changed once written (ADR 0001,

View file

@ -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/serverpod.dart' as _is;
/// Who made what a dictionary is drawn from, under which licence.
abstract class DictionaryCredit
implements _is.SerializableModel, _is.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.
@_is.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 _is.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.
@_is.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,
);
}
}

View file

@ -0,0 +1,851 @@
/* 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/serverpod.dart' as _is;
/// 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 _is.TableRow<int?>, _is.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,
);
}
static final t = DictionaryEntryTable();
static const db = DictionaryEntryRepository._();
@override
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;
@override
_is.Table<int?> get table => t;
/// Returns a shallow copy of this [DictionaryEntry]
/// with some or all fields replaced by the given arguments.
@_is.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,
};
}
static DictionaryEntryInclude include() {
return DictionaryEntryInclude._();
}
static DictionaryEntryIncludeList includeList({
_is.WhereExpressionBuilder<DictionaryEntryTable>? where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
DictionaryEntryInclude? include,
}) {
return DictionaryEntryIncludeList._(
where: where,
limit: limit,
offset: offset,
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
include: include,
);
}
@override
String toString() {
return _is.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.
@_is.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,
);
}
}
class DictionaryEntryUpdateTable extends _is.UpdateTable<DictionaryEntryTable> {
DictionaryEntryUpdateTable(super.table);
_is.ColumnValue<String, String> source(String value) => _is.ColumnValue(
table.source,
value,
);
_is.ColumnValue<String, String> sourceId(String value) => _is.ColumnValue(
table.sourceId,
value,
);
_is.ColumnValue<String, String> language(String value) => _is.ColumnValue(
table.language,
value,
);
_is.ColumnValue<String, String> glossLanguage(String value) =>
_is.ColumnValue(
table.glossLanguage,
value,
);
_is.ColumnValue<String, String> headword(String value) => _is.ColumnValue(
table.headword,
value,
);
_is.ColumnValue<String, String> reading(String? value) => _is.ColumnValue(
table.reading,
value,
);
_is.ColumnValue<int, int> rank(int value) => _is.ColumnValue(
table.rank,
value,
);
_is.ColumnValue<String, String> labels(String value) => _is.ColumnValue(
table.labels,
value,
);
_is.ColumnValue<String, String> searchKeys(String value) => _is.ColumnValue(
table.searchKeys,
value,
);
_is.ColumnValue<String, String> looseKeys(String value) => _is.ColumnValue(
table.looseKeys,
value,
);
_is.ColumnValue<String, String> entry(String value) => _is.ColumnValue(
table.entry,
value,
);
}
class DictionaryEntryTable extends _is.Table<int?> {
DictionaryEntryTable({super.tableRelation})
: super(tableName: 'dictionary_entry') {
updateTable = DictionaryEntryUpdateTable(this);
source = _is.ColumnString(
'source',
this,
);
sourceId = _is.ColumnString(
'sourceId',
this,
);
language = _is.ColumnString(
'language',
this,
);
glossLanguage = _is.ColumnString(
'glossLanguage',
this,
);
headword = _is.ColumnString(
'headword',
this,
);
reading = _is.ColumnString(
'reading',
this,
);
rank = _is.ColumnInt(
'rank',
this,
);
labels = _is.ColumnString(
'labels',
this,
);
searchKeys = _is.ColumnString(
'searchKeys',
this,
);
looseKeys = _is.ColumnString(
'looseKeys',
this,
);
entry = _is.ColumnString(
'entry',
this,
);
}
late final DictionaryEntryUpdateTable updateTable;
/// The source its file names (`jmdict`).
late final _is.ColumnString source;
/// Its id in the source.
late final _is.ColumnString sourceId;
/// The words' language, a BCP 47 tag (`ja`).
late final _is.ColumnString language;
/// The meanings' language (`en`).
late final _is.ColumnString glossLanguage;
/// How the word is shown.
late final _is.ColumnString headword;
/// How it is read; null when the headword is its own reading.
late final _is.ColumnString reading;
/// Its order among the source's entries, lower first.
late final _is.ColumnInt rank;
/// Its labels between bars (`|common|jlpt:n5|`), for LIKE to find one.
late final _is.ColumnString labels;
/// What a search matches, lower case, between bars
/// (`|食べる|たべる|taberu|eat|`).
late final _is.ColumnString searchKeys;
/// What a search matches after every searchKeys match: spellings people
/// type that aren't quite right (`sushi` for すうし), between bars too.
late final _is.ColumnString looseKeys;
/// The entry as cards take it: its JSON, as the file holds it.
late final _is.ColumnString entry;
@override
List<_is.Column> get columns => [
id,
source,
sourceId,
language,
glossLanguage,
headword,
reading,
rank,
labels,
searchKeys,
looseKeys,
entry,
];
}
class DictionaryEntryInclude extends _is.IncludeObject {
DictionaryEntryInclude._();
@override
Map<String, _is.Include?> get includes => {};
@override
_is.Table<int?> get table => DictionaryEntry.t;
}
class DictionaryEntryIncludeList extends _is.IncludeList {
DictionaryEntryIncludeList._({
_is.WhereExpressionBuilder<DictionaryEntryTable>? where,
super.limit,
super.offset,
super.orderBy,
super.orderByList,
super.include,
}) {
super.where = where?.call(DictionaryEntry.t);
}
@override
Map<String, _is.Include?> get includes => include?.includes ?? {};
@override
_is.Table<int?> get table => DictionaryEntry.t;
}
class DictionaryEntryRepository {
const DictionaryEntryRepository._();
/// Returns a list of [DictionaryEntry]s matching the given query parameters.
///
/// Use [where] to specify which items to include in the return value.
/// If none is specified, all items will be returned.
///
/// To specify the order of the items use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// The maximum number of items can be set by [limit]. If no limit is set,
/// all items matching the query will be returned.
///
/// [offset] defines how many items to skip, after which [limit] (or all)
/// items are read from the database.
///
/// ```dart
/// var persons = await Persons.db.find(
/// session,
/// where: (t) => t.lastName.equals('Jones'),
/// orderBy: (t) => t.firstName,
/// limit: 100,
/// );
/// ```
Future<List<DictionaryEntry>> find(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionaryEntryTable>? where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.find<DictionaryEntry>(
where: where?.call(DictionaryEntry.t),
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
limit: limit,
offset: offset,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Returns the first matching [DictionaryEntry] matching the given query parameters.
///
/// Use [where] to specify which items to include in the return value.
/// If none is specified, all items will be returned.
///
/// To specify the order use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// [offset] defines how many items to skip, after which the next one will be picked.
///
/// ```dart
/// var youngestPerson = await Persons.db.findFirstRow(
/// session,
/// where: (t) => t.lastName.equals('Jones'),
/// orderBy: (t) => t.age,
/// );
/// ```
Future<DictionaryEntry?> findFirstRow(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionaryEntryTable>? where,
int? offset,
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.findFirstRow<DictionaryEntry>(
where: where?.call(DictionaryEntry.t),
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
offset: offset,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Finds a single [DictionaryEntry] by its [id] or null if no such row exists.
Future<DictionaryEntry?> findById(
_is.DatabaseSession session,
int id, {
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.findById<DictionaryEntry>(
id,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Inserts all [DictionaryEntry]s in the list and returns the inserted rows.
///
/// The returned [DictionaryEntry]s will have their `id` fields set.
///
/// This is an atomic operation, meaning that if one of the rows fails to
/// insert, none of the rows will be inserted.
///
/// If [ignoreConflicts] is set to `true`, rows that conflict with existing
/// rows are silently skipped, and only the successfully inserted rows are
/// returned.
///
/// If [noReturn] is set to `true`, the inserted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> insert(
_is.DatabaseSession session,
List<DictionaryEntry> rows, {
_is.Transaction? transaction,
bool ignoreConflicts = false,
bool noReturn = false,
}) async {
return session.db.insert<DictionaryEntry>(
rows,
transaction: transaction,
ignoreConflicts: ignoreConflicts,
noReturn: noReturn,
);
}
/// Inserts a single [DictionaryEntry] and returns the inserted row.
///
/// The returned [DictionaryEntry] will have its `id` field set.
Future<DictionaryEntry> insertRow(
_is.DatabaseSession session,
DictionaryEntry row, {
_is.Transaction? transaction,
}) async {
return session.db.insertRow<DictionaryEntry>(
row,
transaction: transaction,
);
}
/// Upserts all [DictionaryEntry]s in the list and returns the resulting rows.
///
/// If a row conflicts on the given [conflictColumns], the existing row is
/// updated with the new values. Otherwise, a new row is inserted.
///
/// If [updateColumns] is provided, only those columns will be updated on
/// conflict. If null, all non-conflict, non-id columns are updated.
///
/// If [updateWhere] is provided, the update only applies to rows matching the
/// given expression. Conflicting rows that don't match are skipped and not
/// returned, so the resulting list may be shorter than [rows].
///
/// The returned [DictionaryEntry]s will have their `id` fields set.
///
/// This is an atomic operation, meaning that if one of the rows fails,
/// none of the rows will be affected.
///
/// If [noReturn] is set to `true`, the resulting rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> upsert(
_is.DatabaseSession session,
List<DictionaryEntry> rows, {
required _is.ColumnSelections<DictionaryEntryTable> conflictColumns,
_is.ColumnSelections<DictionaryEntryTable>? updateColumns,
_is.WhereExpressionBuilder<DictionaryEntryTable>? updateWhere,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.upsert<DictionaryEntry>(
rows,
conflictColumns: conflictColumns(DictionaryEntry.t),
updateColumns: updateColumns?.call(DictionaryEntry.t),
updateWhere: updateWhere?.call(DictionaryEntry.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Upserts a single [DictionaryEntry] and returns the resulting row.
///
/// If the row conflicts on the given [conflictColumns], the existing row is
/// updated. Otherwise, a new row is inserted.
///
/// If [updateColumns] is provided, only those columns will be updated on
/// conflict. If null, all non-conflict, non-id columns are updated.
///
/// If [updateWhere] is provided, the update only applies when the existing
/// row matches the expression. Returns `null` if no row was affected — for
/// example when [updateWhere] does not match the conflicting row.
///
/// The returned [DictionaryEntry] will have its `id` field set.
Future<DictionaryEntry?> upsertRow(
_is.DatabaseSession session,
DictionaryEntry row, {
required _is.ColumnSelections<DictionaryEntryTable> conflictColumns,
_is.ColumnSelections<DictionaryEntryTable>? updateColumns,
_is.WhereExpressionBuilder<DictionaryEntryTable>? updateWhere,
_is.Transaction? transaction,
}) async {
return session.db.upsertRow<DictionaryEntry>(
row,
conflictColumns: conflictColumns(DictionaryEntry.t),
updateColumns: updateColumns?.call(DictionaryEntry.t),
updateWhere: updateWhere?.call(DictionaryEntry.t),
transaction: transaction,
);
}
/// Updates all [DictionaryEntry]s in the list and returns the updated rows. If
/// [columns] is provided, only those columns will be updated. Defaults to
/// all columns.
/// This is an atomic operation, meaning that if one of the rows fails to
/// update, none of the rows will be updated.
///
/// If [noReturn] is set to `true`, the updated rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> update(
_is.DatabaseSession session,
List<DictionaryEntry> rows, {
_is.ColumnSelections<DictionaryEntryTable>? columns,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.update<DictionaryEntry>(
rows,
columns: columns?.call(DictionaryEntry.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Updates a single [DictionaryEntry]. The row needs to have its id set.
/// Optionally, a list of [columns] can be provided to only update those
/// columns. Defaults to all columns.
Future<DictionaryEntry> updateRow(
_is.DatabaseSession session,
DictionaryEntry row, {
_is.ColumnSelections<DictionaryEntryTable>? columns,
_is.Transaction? transaction,
}) async {
return session.db.updateRow<DictionaryEntry>(
row,
columns: columns?.call(DictionaryEntry.t),
transaction: transaction,
);
}
/// Updates a single [DictionaryEntry] by its [id] with the specified [columnValues].
/// Returns the updated row or null if no row with the given id exists.
Future<DictionaryEntry?> updateById(
_is.DatabaseSession session,
int id, {
required _is.ColumnValueListBuilder<DictionaryEntryUpdateTable>
columnValues,
_is.Transaction? transaction,
}) async {
return session.db.updateById<DictionaryEntry>(
id,
columnValues: columnValues(DictionaryEntry.t.updateTable),
transaction: transaction,
);
}
/// Updates all [DictionaryEntry]s matching the [where] expression with the specified [columnValues].
/// Returns the list of updated rows.
///
/// If [noReturn] is set to `true`, the updated rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> updateWhere(
_is.DatabaseSession session, {
required _is.ColumnValueListBuilder<DictionaryEntryUpdateTable>
columnValues,
required _is.WhereExpressionBuilder<DictionaryEntryTable> where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.updateWhere<DictionaryEntry>(
columnValues: columnValues(DictionaryEntry.t.updateTable),
where: where(DictionaryEntry.t),
limit: limit,
offset: offset,
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Deletes all [DictionaryEntry]s in the list and returns the deleted rows.
///
/// To specify the order of the returned rows use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// This is an atomic operation, meaning that if one of the rows fail to
/// be deleted, none of the rows will be deleted.
///
/// If [noReturn] is set to `true`, the deleted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> delete(
_is.DatabaseSession session,
List<DictionaryEntry> rows, {
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.delete<DictionaryEntry>(
rows,
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Deletes a single [DictionaryEntry].
Future<DictionaryEntry> deleteRow(
_is.DatabaseSession session,
DictionaryEntry row, {
_is.Transaction? transaction,
}) async {
return session.db.deleteRow<DictionaryEntry>(
row,
transaction: transaction,
);
}
/// Deletes all rows matching the [where] expression.
///
/// To specify the order of the returned rows use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// If [noReturn] is set to `true`, the deleted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionaryEntry>> deleteWhere(
_is.DatabaseSession session, {
required _is.WhereExpressionBuilder<DictionaryEntryTable> where,
_is.OrderByBuilder<DictionaryEntryTable>? orderBy,
_is.OrderByListBuilder<DictionaryEntryTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.deleteWhere<DictionaryEntry>(
where: where(DictionaryEntry.t),
orderBy: orderBy?.call(DictionaryEntry.t),
orderByList: orderByList?.call(DictionaryEntry.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Counts the number of rows matching the [where] expression. If omitted,
/// will return the count of all rows in the table.
Future<int> count(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionaryEntryTable>? where,
int? limit,
_is.Transaction? transaction,
}) async {
return session.db.count<DictionaryEntry>(
where: where?.call(DictionaryEntry.t),
limit: limit,
transaction: transaction,
);
}
/// Acquires row-level locks on [DictionaryEntry] rows matching the [where] expression.
Future<void> lockRows(
_is.DatabaseSession session, {
required _is.WhereExpressionBuilder<DictionaryEntryTable> where,
required _is.LockMode lockMode,
required _is.Transaction transaction,
_is.LockBehavior lockBehavior = _is.LockBehavior.wait,
}) async {
return session.db.lockRows<DictionaryEntry>(
where: where(DictionaryEntry.t),
lockMode: lockMode,
lockBehavior: lockBehavior,
transaction: transaction,
);
}
}

View file

@ -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_server/src/generated/protocol.dart' as _i5lsenq5;
import 'package:serverpod/serverpod.dart' as _is;
/// 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 _is.SerializableModel, _is.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: _i5lsenq5.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.
@_is.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 _is.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.
@_is.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,
);
}
}

View file

@ -0,0 +1,832 @@
/* 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_server/src/generated/protocol.dart' as _i5lsenq5;
import 'package:serverpod/serverpod.dart' as _is;
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 _is.TableRow<int?>, _is.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: _i5lsenq5.Protocol()
.deserialize<List<_it7o1p0g.DictionaryCredit>>(
jsonSerialization['credits'],
),
entryCount: jsonSerialization['entryCount'] as int,
fileName: jsonSerialization['fileName'] as String,
fileHash: jsonSerialization['fileHash'] as String,
loadedAt: _is.DateTimeJsonExtension.fromJson(
jsonSerialization['loadedAt'],
),
);
}
static final t = DictionarySourceTable();
static const db = DictionarySourceRepository._();
@override
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;
@override
_is.Table<int?> get table => t;
/// Returns a shallow copy of this [DictionarySource]
/// with some or all fields replaced by the given arguments.
@_is.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(),
};
}
static DictionarySourceInclude include() {
return DictionarySourceInclude._();
}
static DictionarySourceIncludeList includeList({
_is.WhereExpressionBuilder<DictionarySourceTable>? where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
DictionarySourceInclude? include,
}) {
return DictionarySourceIncludeList._(
where: where,
limit: limit,
offset: offset,
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
include: include,
);
}
@override
String toString() {
return _is.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.
@_is.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,
);
}
}
class DictionarySourceUpdateTable
extends _is.UpdateTable<DictionarySourceTable> {
DictionarySourceUpdateTable(super.table);
_is.ColumnValue<String, String> source(String value) => _is.ColumnValue(
table.source,
value,
);
_is.ColumnValue<String, String> sourceVersion(String value) =>
_is.ColumnValue(
table.sourceVersion,
value,
);
_is.ColumnValue<String, String> language(String value) => _is.ColumnValue(
table.language,
value,
);
_is.ColumnValue<String, String> glossLanguage(String value) =>
_is.ColumnValue(
table.glossLanguage,
value,
);
_is.ColumnValue<String, String> license(String value) => _is.ColumnValue(
table.license,
value,
);
_is.ColumnValue<
List<_it7o1p0g.DictionaryCredit>,
List<_it7o1p0g.DictionaryCredit>
>
credits(List<_it7o1p0g.DictionaryCredit> value) => _is.ColumnValue(
table.credits,
value,
);
_is.ColumnValue<int, int> entryCount(int value) => _is.ColumnValue(
table.entryCount,
value,
);
_is.ColumnValue<String, String> fileName(String value) => _is.ColumnValue(
table.fileName,
value,
);
_is.ColumnValue<String, String> fileHash(String value) => _is.ColumnValue(
table.fileHash,
value,
);
_is.ColumnValue<DateTime, DateTime> loadedAt(DateTime value) =>
_is.ColumnValue(
table.loadedAt,
value,
);
}
class DictionarySourceTable extends _is.Table<int?> {
DictionarySourceTable({super.tableRelation})
: super(tableName: 'dictionary_source') {
updateTable = DictionarySourceUpdateTable(this);
source = _is.ColumnString(
'source',
this,
);
sourceVersion = _is.ColumnString(
'sourceVersion',
this,
);
language = _is.ColumnString(
'language',
this,
);
glossLanguage = _is.ColumnString(
'glossLanguage',
this,
);
license = _is.ColumnString(
'license',
this,
);
credits = _is.ColumnSerializable<List<_it7o1p0g.DictionaryCredit>>(
'credits',
this,
);
entryCount = _is.ColumnInt(
'entryCount',
this,
);
fileName = _is.ColumnString(
'fileName',
this,
);
fileHash = _is.ColumnString(
'fileHash',
this,
);
loadedAt = _is.ColumnDateTime(
'loadedAt',
this,
);
}
late final DictionarySourceUpdateTable updateTable;
/// The source (`jmdict`).
late final _is.ColumnString source;
/// Its version (`3.6.2 (2026-10-05)`).
late final _is.ColumnString sourceVersion;
/// The words' language (`ja`).
late final _is.ColumnString language;
/// The meanings' language (`en`).
late final _is.ColumnString glossLanguage;
/// The data's licence, an SPDX identifier.
late final _is.ColumnString license;
/// Everything it is drawn from.
late final _is.ColumnSerializable<List<_it7o1p0g.DictionaryCredit>> credits;
/// How many entries it has.
late final _is.ColumnInt entryCount;
/// The file it was loaded from, and the file's SHA-256.
late final _is.ColumnString fileName;
late final _is.ColumnString fileHash;
/// When it was loaded, in UTC.
late final _is.ColumnDateTime loadedAt;
@override
List<_is.Column> get columns => [
id,
source,
sourceVersion,
language,
glossLanguage,
license,
credits,
entryCount,
fileName,
fileHash,
loadedAt,
];
}
class DictionarySourceInclude extends _is.IncludeObject {
DictionarySourceInclude._();
@override
Map<String, _is.Include?> get includes => {};
@override
_is.Table<int?> get table => DictionarySource.t;
}
class DictionarySourceIncludeList extends _is.IncludeList {
DictionarySourceIncludeList._({
_is.WhereExpressionBuilder<DictionarySourceTable>? where,
super.limit,
super.offset,
super.orderBy,
super.orderByList,
super.include,
}) {
super.where = where?.call(DictionarySource.t);
}
@override
Map<String, _is.Include?> get includes => include?.includes ?? {};
@override
_is.Table<int?> get table => DictionarySource.t;
}
class DictionarySourceRepository {
const DictionarySourceRepository._();
/// Returns a list of [DictionarySource]s matching the given query parameters.
///
/// Use [where] to specify which items to include in the return value.
/// If none is specified, all items will be returned.
///
/// To specify the order of the items use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// The maximum number of items can be set by [limit]. If no limit is set,
/// all items matching the query will be returned.
///
/// [offset] defines how many items to skip, after which [limit] (or all)
/// items are read from the database.
///
/// ```dart
/// var persons = await Persons.db.find(
/// session,
/// where: (t) => t.lastName.equals('Jones'),
/// orderBy: (t) => t.firstName,
/// limit: 100,
/// );
/// ```
Future<List<DictionarySource>> find(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionarySourceTable>? where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.find<DictionarySource>(
where: where?.call(DictionarySource.t),
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
limit: limit,
offset: offset,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Returns the first matching [DictionarySource] matching the given query parameters.
///
/// Use [where] to specify which items to include in the return value.
/// If none is specified, all items will be returned.
///
/// To specify the order use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// [offset] defines how many items to skip, after which the next one will be picked.
///
/// ```dart
/// var youngestPerson = await Persons.db.findFirstRow(
/// session,
/// where: (t) => t.lastName.equals('Jones'),
/// orderBy: (t) => t.age,
/// );
/// ```
Future<DictionarySource?> findFirstRow(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionarySourceTable>? where,
int? offset,
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.findFirstRow<DictionarySource>(
where: where?.call(DictionarySource.t),
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
offset: offset,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Finds a single [DictionarySource] by its [id] or null if no such row exists.
Future<DictionarySource?> findById(
_is.DatabaseSession session,
int id, {
_is.Transaction? transaction,
_is.LockMode? lockMode,
_is.LockBehavior? lockBehavior,
}) async {
return session.db.findById<DictionarySource>(
id,
transaction: transaction,
lockMode: lockMode,
lockBehavior: lockBehavior,
);
}
/// Inserts all [DictionarySource]s in the list and returns the inserted rows.
///
/// The returned [DictionarySource]s will have their `id` fields set.
///
/// This is an atomic operation, meaning that if one of the rows fails to
/// insert, none of the rows will be inserted.
///
/// If [ignoreConflicts] is set to `true`, rows that conflict with existing
/// rows are silently skipped, and only the successfully inserted rows are
/// returned.
///
/// If [noReturn] is set to `true`, the inserted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> insert(
_is.DatabaseSession session,
List<DictionarySource> rows, {
_is.Transaction? transaction,
bool ignoreConflicts = false,
bool noReturn = false,
}) async {
return session.db.insert<DictionarySource>(
rows,
transaction: transaction,
ignoreConflicts: ignoreConflicts,
noReturn: noReturn,
);
}
/// Inserts a single [DictionarySource] and returns the inserted row.
///
/// The returned [DictionarySource] will have its `id` field set.
Future<DictionarySource> insertRow(
_is.DatabaseSession session,
DictionarySource row, {
_is.Transaction? transaction,
}) async {
return session.db.insertRow<DictionarySource>(
row,
transaction: transaction,
);
}
/// Upserts all [DictionarySource]s in the list and returns the resulting rows.
///
/// If a row conflicts on the given [conflictColumns], the existing row is
/// updated with the new values. Otherwise, a new row is inserted.
///
/// If [updateColumns] is provided, only those columns will be updated on
/// conflict. If null, all non-conflict, non-id columns are updated.
///
/// If [updateWhere] is provided, the update only applies to rows matching the
/// given expression. Conflicting rows that don't match are skipped and not
/// returned, so the resulting list may be shorter than [rows].
///
/// The returned [DictionarySource]s will have their `id` fields set.
///
/// This is an atomic operation, meaning that if one of the rows fails,
/// none of the rows will be affected.
///
/// If [noReturn] is set to `true`, the resulting rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> upsert(
_is.DatabaseSession session,
List<DictionarySource> rows, {
required _is.ColumnSelections<DictionarySourceTable> conflictColumns,
_is.ColumnSelections<DictionarySourceTable>? updateColumns,
_is.WhereExpressionBuilder<DictionarySourceTable>? updateWhere,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.upsert<DictionarySource>(
rows,
conflictColumns: conflictColumns(DictionarySource.t),
updateColumns: updateColumns?.call(DictionarySource.t),
updateWhere: updateWhere?.call(DictionarySource.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Upserts a single [DictionarySource] and returns the resulting row.
///
/// If the row conflicts on the given [conflictColumns], the existing row is
/// updated. Otherwise, a new row is inserted.
///
/// If [updateColumns] is provided, only those columns will be updated on
/// conflict. If null, all non-conflict, non-id columns are updated.
///
/// If [updateWhere] is provided, the update only applies when the existing
/// row matches the expression. Returns `null` if no row was affected — for
/// example when [updateWhere] does not match the conflicting row.
///
/// The returned [DictionarySource] will have its `id` field set.
Future<DictionarySource?> upsertRow(
_is.DatabaseSession session,
DictionarySource row, {
required _is.ColumnSelections<DictionarySourceTable> conflictColumns,
_is.ColumnSelections<DictionarySourceTable>? updateColumns,
_is.WhereExpressionBuilder<DictionarySourceTable>? updateWhere,
_is.Transaction? transaction,
}) async {
return session.db.upsertRow<DictionarySource>(
row,
conflictColumns: conflictColumns(DictionarySource.t),
updateColumns: updateColumns?.call(DictionarySource.t),
updateWhere: updateWhere?.call(DictionarySource.t),
transaction: transaction,
);
}
/// Updates all [DictionarySource]s in the list and returns the updated rows. If
/// [columns] is provided, only those columns will be updated. Defaults to
/// all columns.
/// This is an atomic operation, meaning that if one of the rows fails to
/// update, none of the rows will be updated.
///
/// If [noReturn] is set to `true`, the updated rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> update(
_is.DatabaseSession session,
List<DictionarySource> rows, {
_is.ColumnSelections<DictionarySourceTable>? columns,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.update<DictionarySource>(
rows,
columns: columns?.call(DictionarySource.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Updates a single [DictionarySource]. The row needs to have its id set.
/// Optionally, a list of [columns] can be provided to only update those
/// columns. Defaults to all columns.
Future<DictionarySource> updateRow(
_is.DatabaseSession session,
DictionarySource row, {
_is.ColumnSelections<DictionarySourceTable>? columns,
_is.Transaction? transaction,
}) async {
return session.db.updateRow<DictionarySource>(
row,
columns: columns?.call(DictionarySource.t),
transaction: transaction,
);
}
/// Updates a single [DictionarySource] by its [id] with the specified [columnValues].
/// Returns the updated row or null if no row with the given id exists.
Future<DictionarySource?> updateById(
_is.DatabaseSession session,
int id, {
required _is.ColumnValueListBuilder<DictionarySourceUpdateTable>
columnValues,
_is.Transaction? transaction,
}) async {
return session.db.updateById<DictionarySource>(
id,
columnValues: columnValues(DictionarySource.t.updateTable),
transaction: transaction,
);
}
/// Updates all [DictionarySource]s matching the [where] expression with the specified [columnValues].
/// Returns the list of updated rows.
///
/// If [noReturn] is set to `true`, the updated rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> updateWhere(
_is.DatabaseSession session, {
required _is.ColumnValueListBuilder<DictionarySourceUpdateTable>
columnValues,
required _is.WhereExpressionBuilder<DictionarySourceTable> where,
int? limit,
int? offset,
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.updateWhere<DictionarySource>(
columnValues: columnValues(DictionarySource.t.updateTable),
where: where(DictionarySource.t),
limit: limit,
offset: offset,
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Deletes all [DictionarySource]s in the list and returns the deleted rows.
///
/// To specify the order of the returned rows use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// This is an atomic operation, meaning that if one of the rows fail to
/// be deleted, none of the rows will be deleted.
///
/// If [noReturn] is set to `true`, the deleted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> delete(
_is.DatabaseSession session,
List<DictionarySource> rows, {
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.delete<DictionarySource>(
rows,
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Deletes a single [DictionarySource].
Future<DictionarySource> deleteRow(
_is.DatabaseSession session,
DictionarySource row, {
_is.Transaction? transaction,
}) async {
return session.db.deleteRow<DictionarySource>(
row,
transaction: transaction,
);
}
/// Deletes all rows matching the [where] expression.
///
/// To specify the order of the returned rows use [orderBy] or [orderByList]
/// when sorting by multiple columns.
///
/// If [noReturn] is set to `true`, the deleted rows are not read back from
/// the database and an empty list is returned. This avoids the overhead of
/// transferring and deserializing the rows when the result is not needed.
Future<List<DictionarySource>> deleteWhere(
_is.DatabaseSession session, {
required _is.WhereExpressionBuilder<DictionarySourceTable> where,
_is.OrderByBuilder<DictionarySourceTable>? orderBy,
_is.OrderByListBuilder<DictionarySourceTable>? orderByList,
_is.Transaction? transaction,
bool noReturn = false,
}) async {
return session.db.deleteWhere<DictionarySource>(
where: where(DictionarySource.t),
orderBy: orderBy?.call(DictionarySource.t),
orderByList: orderByList?.call(DictionarySource.t),
transaction: transaction,
noReturn: noReturn,
);
}
/// Counts the number of rows matching the [where] expression. If omitted,
/// will return the count of all rows in the table.
Future<int> count(
_is.DatabaseSession session, {
_is.WhereExpressionBuilder<DictionarySourceTable>? where,
int? limit,
_is.Transaction? transaction,
}) async {
return session.db.count<DictionarySource>(
where: where?.call(DictionarySource.t),
limit: limit,
transaction: transaction,
);
}
/// Acquires row-level locks on [DictionarySource] rows matching the [where] expression.
Future<void> lockRows(
_is.DatabaseSession session, {
required _is.WhereExpressionBuilder<DictionarySourceTable> where,
required _is.LockMode lockMode,
required _is.Transaction transaction,
_is.LockBehavior lockBehavior = _is.LockBehavior.wait,
}) async {
return session.db.lockRows<DictionarySource>(
where: where(DictionarySource.t),
lockMode: lockMode,
lockBehavior: lockBehavior,
transaction: transaction,
);
}
}

View file

@ -19,12 +19,14 @@ import 'package:serverpod_auth_idp_server/serverpod_auth_idp_server.dart'
as _iais;
import 'package:serverpod_offline_sync_server/serverpod_offline_sync_server.dart'
as _izehhkf5;
import '../asset/asset_endpoint.dart' as _ibwtj1i8;
import '../auth/account_endpoint.dart' as _ii6ycf6v;
import '../auth/anonymous_idp_endpoint.dart' as _in0zita6;
import '../auth/devices_endpoint.dart' as _iduct7ue;
import '../auth/github_sign_in_endpoint.dart' as _iasw79m5;
import '../auth/github_upgrade_endpoint.dart' as _ivnugbf2;
import '../dictionary/dictionary_endpoint.dart' as _ilgtwlto;
import '../instance/instance_endpoint.dart' as _i3g8bfc2;
export 'future_calls.dart' show ServerpodFutureCallsGetter;
@ -68,6 +70,12 @@ class Endpoints extends _is.EndpointDispatch {
'gitHubUpgrade',
null,
),
'dictionary': _ilgtwlto.DictionaryEndpoint()
..initialize(
server,
'dictionary',
null,
),
'instance': _i3g8bfc2.InstanceEndpoint()
..initialize(
server,
@ -309,6 +317,137 @@ class Endpoints extends _is.EndpointDispatch {
),
},
);
connectors['dictionary'] = _is.EndpointConnector(
name: 'dictionary',
endpoint: endpoints['dictionary']!,
methodConnectors: {
'dictionaries': _is.MethodConnector(
name: 'dictionaries',
params: {},
call:
(
_is.Session session,
Map<String, dynamic> params,
) async =>
(endpoints['dictionary'] as _ilgtwlto.DictionaryEndpoint)
.dictionaries(session),
),
'search': _is.MethodConnector(
name: 'search',
params: {
'language': _is.ParameterDescription(
name: 'language',
type: _is.getType<String>(),
nullable: false,
),
'glossLanguage': _is.ParameterDescription(
name: 'glossLanguage',
type: _is.getType<String>(),
nullable: false,
),
'query': _is.ParameterDescription(
name: 'query',
type: _is.getType<String>(),
nullable: false,
),
'limit': _is.ParameterDescription(
name: 'limit',
type: _is.getType<int?>(),
nullable: true,
),
},
call:
(
_is.Session session,
Map<String, dynamic> params,
) async =>
(endpoints['dictionary'] as _ilgtwlto.DictionaryEndpoint)
.search(
session,
params['language'],
params['glossLanguage'],
params['query'],
limit: params['limit'],
),
),
'countLabelled': _is.MethodConnector(
name: 'countLabelled',
params: {
'language': _is.ParameterDescription(
name: 'language',
type: _is.getType<String>(),
nullable: false,
),
'glossLanguage': _is.ParameterDescription(
name: 'glossLanguage',
type: _is.getType<String>(),
nullable: false,
),
'label': _is.ParameterDescription(
name: 'label',
type: _is.getType<String>(),
nullable: false,
),
},
call:
(
_is.Session session,
Map<String, dynamic> params,
) async =>
(endpoints['dictionary'] as _ilgtwlto.DictionaryEndpoint)
.countLabelled(
session,
params['language'],
params['glossLanguage'],
params['label'],
),
),
'labelled': _is.MethodConnector(
name: 'labelled',
params: {
'language': _is.ParameterDescription(
name: 'language',
type: _is.getType<String>(),
nullable: false,
),
'glossLanguage': _is.ParameterDescription(
name: 'glossLanguage',
type: _is.getType<String>(),
nullable: false,
),
'label': _is.ParameterDescription(
name: 'label',
type: _is.getType<String>(),
nullable: false,
),
'offset': _is.ParameterDescription(
name: 'offset',
type: _is.getType<int?>(),
nullable: true,
),
'limit': _is.ParameterDescription(
name: 'limit',
type: _is.getType<int?>(),
nullable: true,
),
},
call:
(
_is.Session session,
Map<String, dynamic> params,
) async =>
(endpoints['dictionary'] as _ilgtwlto.DictionaryEndpoint)
.labelled(
session,
params['language'],
params['glossLanguage'],
params['label'],
offset: params['offset'],
limit: params['limit'],
),
),
},
);
connectors['instance'] = _is.EndpointConnector(
name: 'instance',
endpoint: endpoints['instance']!,

Some files were not shown because too many files have changed in this diff Show more