adding new schema for words, senses and translations incl. relations
This commit is contained in:
parent
0770ff9ec6
commit
de3ebf66a9
1 changed files with 106 additions and 0 deletions
|
|
@ -21,6 +21,7 @@ import {
|
||||||
CEFR_LEVELS,
|
CEFR_LEVELS,
|
||||||
DIFFICULTY_LEVELS,
|
DIFFICULTY_LEVELS,
|
||||||
LOBBY_STATUSES,
|
LOBBY_STATUSES,
|
||||||
|
NOUN_GENDERS,
|
||||||
} from "@lila/shared";
|
} from "@lila/shared";
|
||||||
|
|
||||||
// ── Vocabulary ────────────────────────────────────────────────────────────────
|
// ── Vocabulary ────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -112,6 +113,95 @@ export const entry_translations = pgTable(
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const words = pgTable(
|
||||||
|
"words",
|
||||||
|
{
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
headword: text().notNull(),
|
||||||
|
language_code: varchar({ length: 10 }).notNull(),
|
||||||
|
pos: varchar({ length: 20 }).notNull(),
|
||||||
|
created_at: timestamp({ withTimezone: true }).defaultNow().notNull(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
unique("unique_word_per_language_and_pos").on(
|
||||||
|
table.headword,
|
||||||
|
table.language_code,
|
||||||
|
table.pos,
|
||||||
|
),
|
||||||
|
check(
|
||||||
|
"words_language_code_check",
|
||||||
|
sql`${table.language_code} IN (${sql.raw(SUPPORTED_LANGUAGE_CODES.map((code) => `'${code}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
check(
|
||||||
|
"words_pos_check",
|
||||||
|
sql`${table.pos} IN (${sql.raw(SUPPORTED_POS.map((pos) => `'${pos}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
index("idx_language_code_pos").on(table.language_code, table.pos),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const senses = pgTable(
|
||||||
|
"senses",
|
||||||
|
{
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
word_id: uuid()
|
||||||
|
.notNull()
|
||||||
|
.references(() => words.id, { onDelete: "cascade" }),
|
||||||
|
sense_index: smallint().default(0).notNull(),
|
||||||
|
difficulty: varchar({ length: 20 }).notNull(),
|
||||||
|
definitions: text().array().notNull().default([]),
|
||||||
|
examples: text().array().notNull().default([]),
|
||||||
|
created_at: timestamp({ withTimezone: true }).defaultNow().notNull(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
unique("unique_sense_per_word").on(table.word_id, table.sense_index),
|
||||||
|
check(
|
||||||
|
"senses_difficulty_check",
|
||||||
|
sql`${table.difficulty} IN (${sql.raw(DIFFICULTY_LEVELS.map((lvl) => `'${lvl}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
index("idx_word_sense_difficulty").on(table.word_id, table.difficulty),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const translations = pgTable(
|
||||||
|
"translations",
|
||||||
|
{
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
sense_id: uuid()
|
||||||
|
.notNull()
|
||||||
|
.references(() => senses.id, { onDelete: "cascade" }),
|
||||||
|
target_language_code: varchar({ length: 10 }).notNull(),
|
||||||
|
translation: text().notNull(),
|
||||||
|
gender: varchar({ length: 20 }),
|
||||||
|
difficulty: varchar({ length: 20 }).notNull(),
|
||||||
|
created_at: timestamp({ withTimezone: true }).defaultNow().notNull(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
unique("unique_translation_per_sense").on(
|
||||||
|
table.sense_id,
|
||||||
|
table.target_language_code,
|
||||||
|
table.translation,
|
||||||
|
),
|
||||||
|
check(
|
||||||
|
"translations_language_code_check",
|
||||||
|
sql`${table.target_language_code} IN (${sql.raw(SUPPORTED_LANGUAGE_CODES.map((code) => `'${code}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
check(
|
||||||
|
"translations_difficulty_check",
|
||||||
|
sql`${table.difficulty} IN (${sql.raw(DIFFICULTY_LEVELS.map((lvl) => `'${lvl}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
check(
|
||||||
|
"translations_gender_check",
|
||||||
|
sql`${table.gender} IS NULL OR ${table.gender} IN (${sql.raw(NOUN_GENDERS.map((gender) => `'${gender}'`).join(", "))})`,
|
||||||
|
),
|
||||||
|
index("idx_translations_sense_language_difficulty").on(
|
||||||
|
table.sense_id,
|
||||||
|
table.target_language_code,
|
||||||
|
table.difficulty,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
// ── Auth (managed by Better Auth) ─────────────────────────────────────────────
|
// ── Auth (managed by Better Auth) ─────────────────────────────────────────────
|
||||||
|
|
||||||
export const user = pgTable("user", {
|
export const user = pgTable("user", {
|
||||||
|
|
@ -243,6 +333,22 @@ export const entryTranslationRelations = relations(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const wordRelations = relations(words, ({ many }) => ({
|
||||||
|
senses: many(senses),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const senseRelations = relations(senses, ({ one, many }) => ({
|
||||||
|
word: one(words, { fields: [senses.word_id], references: [words.id] }),
|
||||||
|
translations: many(translations),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const translationRelations = relations(translations, ({ one }) => ({
|
||||||
|
sense: one(senses, {
|
||||||
|
fields: [translations.sense_id],
|
||||||
|
references: [senses.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
export const userRelations = relations(user, ({ many }) => ({
|
export const userRelations = relations(user, ({ many }) => ({
|
||||||
sessions: many(session),
|
sessions: many(session),
|
||||||
accounts: many(account),
|
accounts: many(account),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue