Initial commit: itinova-podcasts v1
Stack: Node.js/Express + React/Vite + tRPC + MySQL (Drizzle ORM) Features: Gestion de podcasts, établissements, mots-clés, upload audio S3 Migrations: 0000-0002 (users, etablissements, mots_cles, podcasts, podcast_mots_cles)
This commit is contained in:
98
drizzle/schema.ts
Normal file
98
drizzle/schema.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import {
|
||||
int,
|
||||
mysqlEnum,
|
||||
mysqlTable,
|
||||
text,
|
||||
timestamp,
|
||||
varchar,
|
||||
primaryKey,
|
||||
boolean,
|
||||
} from "drizzle-orm/mysql-core";
|
||||
|
||||
export const users = mysqlTable("users", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
openId: varchar("openId", { length: 64 }).notNull().unique(),
|
||||
name: text("name"),
|
||||
email: varchar("email", { length: 320 }),
|
||||
loginMethod: varchar("loginMethod", { length: 64 }),
|
||||
role: mysqlEnum("role", ["user", "admin"]).default("user").notNull(),
|
||||
/** Identifiant de connexion locale (ex: adminServPodcast) */
|
||||
username: varchar("username", { length: 64 }).unique(),
|
||||
/** Hash bcrypt du mot de passe local */
|
||||
passwordHash: varchar("passwordHash", { length: 255 }),
|
||||
/** Empêche la modification ou suppression de ce compte */
|
||||
immutable: boolean("immutable").default(false).notNull(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
lastSignedIn: timestamp("lastSignedIn").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export type User = typeof users.$inferSelect;
|
||||
export type InsertUser = typeof users.$inferInsert;
|
||||
|
||||
// ─── Établissements ────────────────────────────────────────────────────────────
|
||||
|
||||
export const etablissements = mysqlTable("etablissements", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
nom: varchar("nom", { length: 255 }).notNull(),
|
||||
description: text("description"),
|
||||
logoUrl: text("logoUrl"),
|
||||
actif: boolean("actif").default(true).notNull(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type Etablissement = typeof etablissements.$inferSelect;
|
||||
export type InsertEtablissement = typeof etablissements.$inferInsert;
|
||||
|
||||
// ─── Mots-clés ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export const motsCles = mysqlTable("mots_cles", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
label: varchar("label", { length: 100 }).notNull().unique(),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export type MotCle = typeof motsCles.$inferSelect;
|
||||
export type InsertMotCle = typeof motsCles.$inferInsert;
|
||||
|
||||
// ─── Podcasts ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export const podcasts = mysqlTable("podcasts", {
|
||||
id: int("id").autoincrement().primaryKey(),
|
||||
titre: varchar("titre", { length: 255 }).notNull(),
|
||||
resume: text("resume").notNull(),
|
||||
etablissementId: int("etablissementId")
|
||||
.notNull()
|
||||
.references(() => etablissements.id),
|
||||
audioUrl: text("audioUrl"),
|
||||
audioKey: text("audioKey"),
|
||||
dureeSecondes: int("dureeSecondes"),
|
||||
statut: mysqlEnum("statut", ["brouillon", "publie"]).default("brouillon").notNull(),
|
||||
auteurId: int("auteurId").references(() => users.id),
|
||||
imageUrl: text("imageUrl"),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
|
||||
});
|
||||
|
||||
export type Podcast = typeof podcasts.$inferSelect;
|
||||
export type InsertPodcast = typeof podcasts.$inferInsert;
|
||||
|
||||
// ─── Relation Podcast ↔ Mots-clés ─────────────────────────────────────────────
|
||||
|
||||
export const podcastMotsCles = mysqlTable(
|
||||
"podcast_mots_cles",
|
||||
{
|
||||
podcastId: int("podcastId")
|
||||
.notNull()
|
||||
.references(() => podcasts.id, { onDelete: "cascade" }),
|
||||
motCleId: int("motCleId")
|
||||
.notNull()
|
||||
.references(() => motsCles.id, { onDelete: "cascade" }),
|
||||
},
|
||||
(table) => ({
|
||||
pk: primaryKey({ columns: [table.podcastId, table.motCleId] }),
|
||||
})
|
||||
);
|
||||
|
||||
export type PodcastMotCle = typeof podcastMotsCles.$inferSelect;
|
||||
Reference in New Issue
Block a user