From e79fa6922b8b90d77bea51f192b9059b9d677477 Mon Sep 17 00:00:00 2001 From: lila Date: Tue, 7 Apr 2026 01:03:22 +0200 Subject: [PATCH] updating schema --- data-sources/english/.~lock.en_m3.xls# | 1 - ....octanove-vocabulary-profile-c1c2-1.0.csv# | 1 - data-sources/italian/.~lock.it_m3.xls# | 1 - packages/db/drizzle/0003_greedy_revanche.sql | 4 + packages/db/drizzle/meta/0003_snapshot.json | 654 ++++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/src/db/schema.ts | 7 + packages/shared/src/constants.ts | 2 + 8 files changed, 674 insertions(+), 3 deletions(-) delete mode 100644 data-sources/english/.~lock.en_m3.xls# delete mode 100644 data-sources/english/.~lock.octanove-vocabulary-profile-c1c2-1.0.csv# delete mode 100644 data-sources/italian/.~lock.it_m3.xls# create mode 100644 packages/db/drizzle/0003_greedy_revanche.sql create mode 100644 packages/db/drizzle/meta/0003_snapshot.json diff --git a/data-sources/english/.~lock.en_m3.xls# b/data-sources/english/.~lock.en_m3.xls# deleted file mode 100644 index 71905ca..0000000 --- a/data-sources/english/.~lock.en_m3.xls# +++ /dev/null @@ -1 +0,0 @@ -,languagedev,laptop,06.04.2026 23:24,file:///home/languagedev/.config/libreoffice/4; \ No newline at end of file diff --git a/data-sources/english/.~lock.octanove-vocabulary-profile-c1c2-1.0.csv# b/data-sources/english/.~lock.octanove-vocabulary-profile-c1c2-1.0.csv# deleted file mode 100644 index 9f883c1..0000000 --- a/data-sources/english/.~lock.octanove-vocabulary-profile-c1c2-1.0.csv# +++ /dev/null @@ -1 +0,0 @@ -,languagedev,laptop,06.04.2026 23:25,file:///home/languagedev/.config/libreoffice/4; \ No newline at end of file diff --git a/data-sources/italian/.~lock.it_m3.xls# b/data-sources/italian/.~lock.it_m3.xls# deleted file mode 100644 index 62f8687..0000000 --- a/data-sources/italian/.~lock.it_m3.xls# +++ /dev/null @@ -1 +0,0 @@ -,languagedev,laptop,06.04.2026 23:23,file:///home/languagedev/.config/libreoffice/4; \ No newline at end of file diff --git a/packages/db/drizzle/0003_greedy_revanche.sql b/packages/db/drizzle/0003_greedy_revanche.sql new file mode 100644 index 0000000..6a3c547 --- /dev/null +++ b/packages/db/drizzle/0003_greedy_revanche.sql @@ -0,0 +1,4 @@ +DROP INDEX "idx_translations_lang";--> statement-breakpoint +ALTER TABLE "translations" ADD COLUMN "difficulty" varchar(20);--> statement-breakpoint +CREATE INDEX "idx_translations_lang" ON "translations" USING btree ("language_code","difficulty","cefr_level","term_id");--> statement-breakpoint +ALTER TABLE "translations" ADD CONSTRAINT "difficulty_check" CHECK ("translations"."difficulty" IN ('easy', 'intermediate', 'hard')); \ No newline at end of file diff --git a/packages/db/drizzle/meta/0003_snapshot.json b/packages/db/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..018d08d --- /dev/null +++ b/packages/db/drizzle/meta/0003_snapshot.json @@ -0,0 +1,654 @@ +{ + "id": "8b22765b-67bb-4bc3-9549-4206ca080343", + "prevId": "a6e361d8-597a-4a34-be54-9d87bcb61437", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.deck_terms": { + "name": "deck_terms", + "schema": "", + "columns": { + "deck_id": { + "name": "deck_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "term_id": { + "name": "term_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "deck_terms_deck_id_decks_id_fk": { + "name": "deck_terms_deck_id_decks_id_fk", + "tableFrom": "deck_terms", + "tableTo": "decks", + "columnsFrom": [ + "deck_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deck_terms_term_id_terms_id_fk": { + "name": "deck_terms_term_id_terms_id_fk", + "tableFrom": "deck_terms", + "tableTo": "terms", + "columnsFrom": [ + "term_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "deck_terms_deck_id_term_id_pk": { + "name": "deck_terms_deck_id_term_id_pk", + "columns": [ + "deck_id", + "term_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.decks": { + "name": "decks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_language": { + "name": "source_language", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "validated_languages": { + "name": "validated_languages", + "type": "varchar(10)[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "type": { + "name": "type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_decks_type": { + "name": "idx_decks_type", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_language", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_deck_name": { + "name": "unique_deck_name", + "nullsNotDistinct": false, + "columns": [ + "name", + "source_language" + ] + } + }, + "policies": {}, + "checkConstraints": { + "source_language_check": { + "name": "source_language_check", + "value": "\"decks\".\"source_language\" IN ('en', 'it')" + }, + "validated_languages_check": { + "name": "validated_languages_check", + "value": "validated_languages <@ ARRAY['en', 'it']::varchar[]" + }, + "validated_languages_excludes_source": { + "name": "validated_languages_excludes_source", + "value": "NOT (\"decks\".\"source_language\" = ANY(\"decks\".\"validated_languages\"))" + }, + "deck_type_check": { + "name": "deck_type_check", + "value": "\"decks\".\"type\" IN ('grammar', 'media')" + } + }, + "isRLSEnabled": false + }, + "public.term_glosses": { + "name": "term_glosses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "term_id": { + "name": "term_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "language_code": { + "name": "language_code", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "term_glosses_term_id_terms_id_fk": { + "name": "term_glosses_term_id_terms_id_fk", + "tableFrom": "term_glosses", + "tableTo": "terms", + "columnsFrom": [ + "term_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_term_gloss": { + "name": "unique_term_gloss", + "nullsNotDistinct": false, + "columns": [ + "term_id", + "language_code", + "text" + ] + } + }, + "policies": {}, + "checkConstraints": { + "language_code_check": { + "name": "language_code_check", + "value": "\"term_glosses\".\"language_code\" IN ('en', 'it')" + } + }, + "isRLSEnabled": false + }, + "public.term_topics": { + "name": "term_topics", + "schema": "", + "columns": { + "term_id": { + "name": "term_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "topic_id": { + "name": "topic_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "term_topics_term_id_terms_id_fk": { + "name": "term_topics_term_id_terms_id_fk", + "tableFrom": "term_topics", + "tableTo": "terms", + "columnsFrom": [ + "term_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "term_topics_topic_id_topics_id_fk": { + "name": "term_topics_topic_id_topics_id_fk", + "tableFrom": "term_topics", + "tableTo": "topics", + "columnsFrom": [ + "topic_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "term_topics_term_id_topic_id_pk": { + "name": "term_topics_term_id_topic_id_pk", + "columns": [ + "term_id", + "topic_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.terms": { + "name": "terms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source": { + "name": "source", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pos": { + "name": "pos", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_terms_source_pos": { + "name": "idx_terms_source_pos", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pos", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_source_id": { + "name": "unique_source_id", + "nullsNotDistinct": false, + "columns": [ + "source", + "source_id" + ] + } + }, + "policies": {}, + "checkConstraints": { + "pos_check": { + "name": "pos_check", + "value": "\"terms\".\"pos\" IN ('noun', 'verb')" + } + }, + "isRLSEnabled": false + }, + "public.topics": { + "name": "topics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "topics_slug_unique": { + "name": "topics_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.translations": { + "name": "translations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "term_id": { + "name": "term_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "language_code": { + "name": "language_code", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cefr_level": { + "name": "cefr_level", + "type": "varchar(2)", + "primaryKey": false, + "notNull": false + }, + "difficulty": { + "name": "difficulty", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_translations_lang": { + "name": "idx_translations_lang", + "columns": [ + { + "expression": "language_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "difficulty", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cefr_level", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "term_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "translations_term_id_terms_id_fk": { + "name": "translations_term_id_terms_id_fk", + "tableFrom": "translations", + "tableTo": "terms", + "columnsFrom": [ + "term_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_translations": { + "name": "unique_translations", + "nullsNotDistinct": false, + "columns": [ + "term_id", + "language_code", + "text" + ] + } + }, + "policies": {}, + "checkConstraints": { + "language_code_check": { + "name": "language_code_check", + "value": "\"translations\".\"language_code\" IN ('en', 'it')" + }, + "cefr_check": { + "name": "cefr_check", + "value": "\"translations\".\"cefr_level\" IN ('A1', 'A2', 'B1', 'B2', 'C1', 'C2')" + }, + "difficulty_check": { + "name": "difficulty_check", + "value": "\"translations\".\"difficulty\" IN ('easy', 'intermediate', 'hard')" + } + }, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "openauth_sub": { + "name": "openauth_sub", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_login_at": { + "name": "last_login_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_openauth_sub_unique": { + "name": "users_openauth_sub_unique", + "nullsNotDistinct": false, + "columns": [ + "openauth_sub" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_display_name_unique": { + "name": "users_display_name_unique", + "nullsNotDistinct": false, + "columns": [ + "display_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 0b3bbc2..d149500 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1775408266218, "tag": "0002_perfect_arclight", "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1775513042249, + "tag": "0003_greedy_revanche", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/db/schema.ts b/packages/db/src/db/schema.ts index 0932b62..637f127 100644 --- a/packages/db/src/db/schema.ts +++ b/packages/db/src/db/schema.ts @@ -17,6 +17,7 @@ import { SUPPORTED_LANGUAGE_CODES, CEFR_LEVELS, SUPPORTED_DECK_TYPES, + DIFFICULTY_LEVELS, } from "@glossa/shared"; export const terms = pgTable( @@ -72,6 +73,7 @@ export const translations = pgTable( language_code: varchar({ length: 10 }).notNull(), text: text().notNull(), cefr_level: varchar({ length: 2 }), + difficulty: varchar({ length: 20 }), created_at: timestamp({ withTimezone: true }).defaultNow().notNull(), }, (table) => [ @@ -88,8 +90,13 @@ export const translations = pgTable( "cefr_check", sql`${table.cefr_level} IN (${sql.raw(CEFR_LEVELS.map((l) => `'${l}'`).join(", "))})`, ), + check( + "difficulty_check", + sql`${table.difficulty} IN (${sql.raw(DIFFICULTY_LEVELS.map((d) => `'${d}'`).join(", "))})`, + ), index("idx_translations_lang").on( table.language_code, + table.difficulty, table.cefr_level, table.term_id, ), diff --git a/packages/shared/src/constants.ts b/packages/shared/src/constants.ts index 39cfa61..4d87b1d 100644 --- a/packages/shared/src/constants.ts +++ b/packages/shared/src/constants.ts @@ -7,3 +7,5 @@ export const GAME_ROUNDS = ["3", "10"] as const; export const CEFR_LEVELS = ["A1", "A2", "B1", "B2", "C1", "C2"] as const; export const SUPPORTED_DECK_TYPES = ["grammar", "media"] as const; + +export const DIFFICULTY_LEVELS = ["easy", "intermediate", "hard"] as const;