Openstatus
www.openstatus.dev
1import { relations, sql } from "drizzle-orm";
2import {
3 integer,
4 primaryKey,
5 sqliteTable,
6 text,
7} from "drizzle-orm/sqlite-core";
8import type { AdapterAccount } from "next-auth/adapters";
9
10import { workspace, workspaceRole } from "../workspaces";
11
12export const user = sqliteTable("user", {
13 id: integer("id").primaryKey(),
14
15 // clerk fields
16 tenantId: text("tenant_id", { length: 256 }).unique(), // the clerk User Id
17 firstName: text("first_name").default(""),
18 lastName: text("last_name").default(""),
19 photoUrl: text("photo_url").default(""),
20
21 // next-auth fields
22 name: text("name"),
23 email: text("email").default(""),
24 emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
25
26 createdAt: integer("created_at", { mode: "timestamp" }).default(
27 sql`(strftime('%s', 'now'))`,
28 ),
29 updatedAt: integer("updated_at", { mode: "timestamp" }).default(
30 sql`(strftime('%s', 'now'))`,
31 ),
32});
33
34export const userRelations = relations(user, ({ many }) => ({
35 usersToWorkspaces: many(usersToWorkspaces),
36}));
37
38export const usersToWorkspaces = sqliteTable(
39 "users_to_workspaces",
40 {
41 userId: integer("user_id")
42 .notNull()
43 .references(() => user.id),
44 workspaceId: integer("workspace_id")
45 .notNull()
46 .references(() => workspace.id),
47 role: text("role", { enum: workspaceRole }).notNull().default("member"),
48 createdAt: integer("created_at", { mode: "timestamp" }).default(
49 sql`(strftime('%s', 'now'))`,
50 ),
51 },
52 (t) => ({
53 pk: primaryKey({ columns: [t.userId, t.workspaceId] }),
54 }),
55);
56
57export const usersToWorkspaceRelations = relations(
58 usersToWorkspaces,
59 ({ one }) => ({
60 workspace: one(workspace, {
61 fields: [usersToWorkspaces.workspaceId],
62 references: [workspace.id],
63 }),
64 user: one(user, {
65 fields: [usersToWorkspaces.userId],
66 references: [user.id],
67 }),
68 }),
69);
70
71// NEXT AUTH TABLES
72
73export const account = sqliteTable(
74 "account",
75 {
76 userId: integer("user_id")
77 .notNull()
78 .references(() => user.id, { onDelete: "cascade" }),
79 type: text("type").$type<AdapterAccount["type"]>().notNull(),
80 provider: text("provider").notNull(),
81 providerAccountId: text("provider_account_id").notNull(),
82 refresh_token: text("refresh_token"),
83 access_token: text("access_token"),
84 expires_at: integer("expires_at"),
85 token_type: text("token_type"),
86 scope: text("scope"),
87 id_token: text("id_token"),
88 session_state: text("session_state"),
89 },
90 (account) => ({
91 compoundKey: primaryKey({
92 columns: [account.provider, account.providerAccountId],
93 }),
94 }),
95);
96
97export const session = sqliteTable("session", {
98 sessionToken: text("session_token").primaryKey(),
99 userId: integer("user_id")
100 .notNull()
101 .references(() => user.id, { onDelete: "cascade" }),
102 expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
103});
104
105export const verificationToken = sqliteTable(
106 "verification_token",
107 {
108 identifier: text("identifier").notNull(),
109 token: text("token").notNull(),
110 expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
111 },
112 (vt) => ({
113 compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }),
114 }),
115);