173 lines
6.8 KiB
TypeScript
173 lines
6.8 KiB
TypeScript
import { integer, sqliteTable, text, real, unique } from 'drizzle-orm/sqlite-core';
|
|
import { user } from './auth.schema';
|
|
import type { InferSelectModel } from 'drizzle-orm';
|
|
|
|
// Define devil fruit types
|
|
export type DevilFruitType = 'Paramecia' | 'Zoan' | 'Logia' | 'Smile' | 'Unknown';
|
|
|
|
export type Status = 'Alive' | 'Dead' | 'Unknown';
|
|
export type FriendshipStatus = 'pending' | 'accepted' | 'declined';
|
|
|
|
// Define the site config table schema
|
|
export const config = sqliteTable('config', {
|
|
key: text('key').primaryKey(),
|
|
value: text('value')
|
|
});
|
|
|
|
// Define the arc table schema
|
|
export const arc = sqliteTable('arc', {
|
|
id: text('id').primaryKey(),
|
|
name: text('name').notNull(),
|
|
frName: text('fr_name'),
|
|
startChapter: integer('start_chapter').notNull(),
|
|
endChapter: integer('end_chapter'),
|
|
url: text('url')
|
|
});
|
|
|
|
export type Arc = InferSelectModel<typeof arc>;
|
|
|
|
// Define the devil fruit table schema
|
|
export const devilFruit = sqliteTable('devil_fruit', {
|
|
id: text('id').primaryKey(),
|
|
name: text('name').notNull().unique(),
|
|
type: text('type').$type<DevilFruitType>(),
|
|
url: text('url')
|
|
});
|
|
|
|
export type DevilFruit = InferSelectModel<typeof devilFruit>;
|
|
|
|
// Define the character table schema
|
|
export const character = sqliteTable('character', {
|
|
id: text('id').primaryKey(),
|
|
name: text('name').notNull(),
|
|
frName: text('fr_name'),
|
|
gender: text('gender'),
|
|
age: integer('age'),
|
|
affiliations: text('affiliations', { mode: 'json' }).$type<string[]>(),
|
|
devilFruitId: text('devil_fruit_id').references(() => devilFruit.id),
|
|
hakiObservation: integer('haki_observation', { mode: 'boolean' }).default(false),
|
|
hakiArmament: integer('haki_armament', { mode: 'boolean' }).default(false),
|
|
hakiConqueror: integer('haki_conqueror', { mode: 'boolean' }).default(false),
|
|
bounty: integer('bounty').default(0),
|
|
height: real('height'),
|
|
origin: text('origin'),
|
|
frOrigin: text('fr_origin'),
|
|
firstAppearance: integer('first_appearance').notNull(),
|
|
pictureUrl: text('picture_url'),
|
|
epithets: text('epithets', { mode: 'json' }).$type<string[]>(),
|
|
frEpithets: text('fr_epithets', { mode: 'json' }).$type<string[]>(),
|
|
status: text('status').$type<Status | null>(),
|
|
arcId: text('arc_id').references(() => arc.id, { onDelete: 'set null' }),
|
|
url: text('url'),
|
|
frUrl: text('fr_url'),
|
|
isInDailyMode: integer('is_in_daily_mode', { mode: 'boolean' }).default(false)
|
|
});
|
|
|
|
export type Character = InferSelectModel<typeof character>;
|
|
|
|
// Define the character override table schema
|
|
export const characterOverride = sqliteTable('character_override', {
|
|
characterId: text('character_id').primaryKey().references(() => character.id, { onDelete: 'cascade' }),
|
|
name: text('name'),
|
|
gender: text('gender'),
|
|
age: integer('age'),
|
|
affiliations: text('affiliations', { mode: 'json' }).$type<string[]>(),
|
|
devilFruitId: text('devil_fruit_id').references(() => devilFruit.id, { onDelete: 'set null' }),
|
|
hakiObservation: integer('haki_observation', { mode: 'boolean' }),
|
|
hakiArmament: integer('haki_armament', { mode: 'boolean' }),
|
|
hakiConqueror: integer('haki_conqueror', { mode: 'boolean' }),
|
|
bounty: integer('bounty'),
|
|
height: real('height'),
|
|
origin: text('origin'),
|
|
firstAppearance: integer('first_appearance'),
|
|
pictureUrl: text('picture_url'),
|
|
epithets: text('epithets', { mode: 'json' }).$type<string[]>(),
|
|
status: text('status').$type<Status | null>(),
|
|
arcId: text('arc_id').references(() => arc.id, { onDelete: 'set null' }),
|
|
url: text('url'),
|
|
frUrl: text('fr_url'),
|
|
notes: text('notes')
|
|
});
|
|
|
|
export type CharacterOverride = InferSelectModel<typeof characterOverride>;
|
|
|
|
// Define the character scrape validation table schema
|
|
export const characterScrapeValidation = sqliteTable('character_scrape_validation', {
|
|
id: text('id').primaryKey(),
|
|
name: text('name').notNull(),
|
|
frName: text('fr_name'),
|
|
gender: text('gender'),
|
|
age: integer('age'),
|
|
affiliations: text('affiliations', { mode: 'json' }).$type<string[]>(),
|
|
devilFruitId: text('devil_fruit_id').references(() => devilFruit.id, { onDelete: 'set null' }),
|
|
hakiObservation: integer('haki_observation', { mode: 'boolean' }).default(false),
|
|
hakiArmament: integer('haki_armament', { mode: 'boolean' }).default(false),
|
|
hakiConqueror: integer('haki_conqueror', { mode: 'boolean' }).default(false),
|
|
bounty: integer('bounty'),
|
|
height: real('height'),
|
|
origin: text('origin'),
|
|
frOrigin: text('fr_origin'),
|
|
firstAppearance: integer('first_appearance').notNull(),
|
|
pictureUrl: text('picture_url'),
|
|
epithets: text('epithets', { mode: 'json' }).$type<string[]>(),
|
|
frEpithets: text('fr_epithets', { mode: 'json' }).$type<string[]>(),
|
|
status: text('status').$type<Status | null>(),
|
|
arcId: text('arc_id').references(() => arc.id, { onDelete: 'set null' }),
|
|
url: text('url'),
|
|
frUrl: text('fr_url')
|
|
});
|
|
|
|
export type CharacterScrapeValidation = InferSelectModel<typeof characterScrapeValidation>;
|
|
|
|
// Define the character history table schema
|
|
export const characterHistory = sqliteTable('character_history', {
|
|
id: text('id')
|
|
.primaryKey()
|
|
.$defaultFn(() => crypto.randomUUID()),
|
|
characterId: text('character_id').references(() => character.id, { onDelete: 'cascade' }),
|
|
date: integer('date').notNull().unique(),
|
|
won: integer('won').notNull().default(0),
|
|
createdAt: integer('created_at').notNull().$default(() => Date.now()),
|
|
updatedAt: integer('updated_at').notNull().$default(() => Date.now()),
|
|
});
|
|
|
|
export type CharacterHistory = InferSelectModel<typeof characterHistory>;
|
|
|
|
// Define the user character history table schema
|
|
export const userCharacterHistory = sqliteTable('user_character_history', {
|
|
id: text('id')
|
|
.primaryKey()
|
|
.$defaultFn(() => crypto.randomUUID()),
|
|
userId: text('user_id').references(() => user.id, { onDelete: 'cascade' }),
|
|
characterHistoryId: text('character_history_id').references(() => characterHistory.id, { onDelete: 'cascade' }),
|
|
tryCount: integer('try_count').notNull(),
|
|
triedCharacterIds: text('tried_character_ids', { mode: 'json' }).$type<string[]>(),
|
|
createdAt: integer('created_at').notNull().$default(() => Date.now())
|
|
}, (table) => [
|
|
unique().on(table.userId, table.characterHistoryId)
|
|
]);
|
|
|
|
export type UserCharacterHistory = InferSelectModel<typeof userCharacterHistory>;
|
|
|
|
// Define the friendship table schema (friend requests + accepted friends)
|
|
export const friendship = sqliteTable('friendship', {
|
|
id: text('id')
|
|
.primaryKey()
|
|
.$defaultFn(() => crypto.randomUUID()),
|
|
requesterId: text('requester_id')
|
|
.notNull()
|
|
.references(() => user.id, { onDelete: 'cascade' }),
|
|
addresseeId: text('addressee_id')
|
|
.notNull()
|
|
.references(() => user.id, { onDelete: 'cascade' }),
|
|
status: text('status').$type<FriendshipStatus>().notNull().default('pending'),
|
|
createdAt: integer('created_at').notNull().$default(() => Date.now()),
|
|
updatedAt: integer('updated_at').notNull().$default(() => Date.now()),
|
|
}, (table) => [
|
|
unique().on(table.requesterId, table.addresseeId)
|
|
]);
|
|
|
|
export type Friendship = InferSelectModel<typeof friendship>;
|
|
|
|
export * from './auth.schema';
|