feat: dictionaries hold words or characters, and are asked by their source

A dictionary source now says what it holds (`kind`: `words`, the default
for files from before, or `characters`), a string so that an app older
than a new kind leaves it out. Search, countLabelled and labelled take the
dictionary by its source and meaning language, as the unique index names
it, rather than by the language: with KANJIDIC2 beside JMdict, a search
for words would otherwise bring kanji, and JLPT N5 would hold both. The
search reads the language for its query variants from the source's row;
a dictionary the instance doesn't hold finds nothing. The rank index goes
by source too.

Migration: drops and recreates dictionary_entry_rank_idx on (source,
glossLanguage, rank), and adds dictionary_source.kind, text NOT NULL
DEFAULT 'words', so a JMdict loaded before is a dictionary of words. Both
tables are reference data, never synced; the old server keeps working
until the switch (its queries by language just lose the index).

In the app, a studyset's dictionary is one of words unless a kind is
asked for.

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 14:47:46 +02:00
commit a6699b30cb
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -0,0 +1,78 @@
{
"__className__": "serverpod.DatabaseMigration",
"actions": [
{
"__className__": "serverpod.DatabaseMigrationAction",
"type": "alterTable",
"alterTable": {
"__className__": "serverpod.TableMigration",
"name": "dictionary_entry",
"schema": "public",
"addColumns": [],
"deleteColumns": [],
"modifyColumns": [],
"addIndexes": [
{
"__className__": "serverpod.IndexDefinition",
"indexName": "dictionary_entry_rank_idx",
"elements": [
{
"__className__": "serverpod.IndexElementDefinition",
"type": 0,
"definition": "source"
},
{
"__className__": "serverpod.IndexElementDefinition",
"type": 0,
"definition": "glossLanguage"
},
{
"__className__": "serverpod.IndexElementDefinition",
"type": 0,
"definition": "rank"
}
],
"type": "btree",
"isUnique": false,
"isPrimary": false
}
],
"deleteIndexes": [
"dictionary_entry_rank_idx"
],
"addForeignKeys": [],
"deleteForeignKeys": [],
"warnings": []
}
},
{
"__className__": "serverpod.DatabaseMigrationAction",
"type": "alterTable",
"alterTable": {
"__className__": "serverpod.TableMigration",
"name": "dictionary_source",
"schema": "public",
"addColumns": [
{
"__className__": "serverpod.ColumnDefinition",
"name": "kind",
"fieldName": "kind",
"columnType": 0,
"isNullable": false,
"columnDefault": "'words'",
"dartType": "String"
}
],
"deleteColumns": [],
"modifyColumns": [],
"addIndexes": [],
"deleteIndexes": [],
"addForeignKeys": [],
"deleteForeignKeys": [],
"warnings": []
}
}
],
"warnings": [],
"migrationApiVersion": 1
}