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)
99 lines
4.0 KiB
TypeScript
99 lines
4.0 KiB
TypeScript
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;
|