Skip to content

Commit db04b38

Browse files
committed
add drizzle-seed
1 parent 274ca47 commit db04b38

File tree

18 files changed

+283
-251
lines changed

18 files changed

+283
-251
lines changed

apps/drizzle-run/.eslintrc.cjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@ module.exports = {
55
parserOptions: {
66
project: true,
77
},
8-
ignorePatterns: ["app/registry/*/presets", "**/*/_blank"],
8+
ignorePatterns: [
9+
"app/registry/dialects/*/presets",
10+
"app/registry/dialects/*/core",
11+
"**/*/_blank",
12+
],
913
};

apps/drizzle-run/app/modules/playground/machine.client.ts

+1
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ async function fetchNodeModules(
688688

689689
const imports = new Map<string, Promise<Record<string, unknown>>>([
690690
["drizzle-orm", import("drizzle-orm")],
691+
["drizzle-seed", import("drizzle-seed")],
691692
["@drizzle-lab/api/pg", import("@drizzle-lab/api/pg")],
692693
["@drizzle-lab/api/sqlite", import("@drizzle-lab/api/sqlite")],
693694
]);

apps/drizzle-run/app/registry/build.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const typesToBundle = [
1717
"valibot",
1818
"@electric-sql/pglite",
1919
"@libsql",
20+
"drizzle-seed",
2021
] as const;
2122

2223
console.log("Building registry");

apps/drizzle-run/app/registry/dialects/postgresql/core/seed.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,10 @@
44
* 💡Tip: you can use the `$` global variable to access goodies
55
*/
66

7+
import { seed } from "drizzle-seed";
8+
79
import { db } from "./db";
8-
import {} from "./schema";
10+
import * as schema from "./schema";
11+
12+
// doc: https://orm.drizzle.team/docs/seed-overview
13+
await seed(db, schema);

apps/drizzle-run/app/registry/dialects/postgresql/presets/rls/index.ts

+46-7
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,54 @@
33
* 💡Tip: you can use the `$` global variable to access goodies
44
*/
55

6-
import { db } from "./db";
7-
import {} from "./schema";
6+
import { eq } from "drizzle-orm";
7+
import { drizzle } from "drizzle-orm/pglite";
88

9-
// 💡 This playground run a seed code in the Seed tab
9+
import { db as admin } from "./db";
10+
import * as schema from "./schema";
11+
import { createDrizzle } from "./utils";
1012

11-
const result = await db.query.users.findMany({
12-
with: {
13-
posts: true,
13+
const userId1 = $.random.uuid();
14+
const userId2 = $.random.uuid();
15+
16+
const client = drizzle({
17+
client: admin.$client,
18+
schema,
19+
casing: "snake_case",
20+
});
21+
22+
const db = createDrizzle({ role: "authenticated", sub: userId1 }, { admin, client });
23+
24+
await db.admin.insert(schema.authUsers).values([
25+
{
26+
id: userId1,
27+
},
28+
{
29+
id: userId2,
1430
},
31+
]);
32+
33+
await db.admin.insert(schema.profiles).values({
34+
id: userId1,
35+
1536
});
1637

17-
console.log(result);
38+
console.log(
39+
"insert allowed",
40+
await db.rls(async (tx) => tx.insert(schema.rooms).values({ topic: "user room" }).returning()),
41+
);
42+
43+
console.log(
44+
"user can not edit other profile. Before",
45+
await db.admin.query.profiles.findMany(),
46+
await db.rls(async (tx) => {
47+
await tx.update(schema.profiles).set({ email: "nope" }).where(eq(schema.profiles.id, userId2));
48+
}),
49+
"after",
50+
await db.admin.query.profiles.findMany(),
51+
);
52+
53+
const dbAnonymous = createDrizzle({ role: "anon" }, { admin, client });
54+
55+
console.log("anonymous can not read");
56+
console.log(await dbAnonymous.rls(async (tx) => tx.select().from(schema.rooms)));
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"$schema": "../../../manifest.schema.json",
3-
"name": "Starter 01",
4-
"description": "A starter demo"
3+
"name": "(Experimental) Row Level Security (RLS)",
4+
"description": "A demo of RLS with a Supabase emulator"
55
}
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,123 @@
1-
/**
2-
* This is the schema for the database.
3-
* 💡Tip: you can use the `$` global variable to access goodies
4-
* Do not forget to `export` your tables 😅
5-
*/
1+
import { sql, eq, getTableColumns } from "drizzle-orm";
2+
import {
3+
bigint,
4+
foreignKey,
5+
pgTable,
6+
text,
7+
timestamp,
8+
unique,
9+
uuid,
10+
pgPolicy,
11+
pgView,
12+
pgSchema,
13+
pgRole,
14+
} from "drizzle-orm/pg-core";
615

7-
import { relations } from "drizzle-orm";
8-
import { integer, text, pgTable, timestamp } from "drizzle-orm/pg-core";
16+
/* ------------------------------ Supabase emulation ------------------------------ */
917

10-
export const users = pgTable("users", {
11-
id: integer("id").primaryKey().generatedByDefaultAsIdentity(),
12-
name: text("name").notNull(),
13-
createdAt: timestamp("created_at", { precision: 3 }).notNull().defaultNow(),
18+
export const anonRole = pgRole("anon");
19+
export const authenticatedRole = pgRole("authenticated");
20+
export const serviceRole = pgRole("service_role");
21+
export const supabaseAuthAdminRole = pgRole("supabase_auth_admin");
22+
export const auth = pgSchema("auth");
23+
export const authUsers = auth.table("users", {
24+
id: uuid().primaryKey().notNull(),
1425
});
26+
const authUid = sql`(select auth.uid())`;
1527

16-
export const usersRelations = relations(users, ({ many }) => ({
17-
posts: many(posts),
18-
}));
28+
/* ------------------------------ public schema; ------------------------------ */
1929

20-
export const posts = pgTable("posts", {
21-
id: integer("id").primaryKey().generatedByDefaultAsIdentity(),
22-
content: text("content").notNull(),
23-
authorId: integer("author_id")
24-
.notNull()
25-
.references(() => users.id),
26-
createdAt: timestamp("created_at", { precision: 3 }).notNull().defaultNow(),
27-
});
30+
export const rooms = pgTable(
31+
"rooms",
32+
{
33+
id: bigint({ mode: "number" }).primaryKey().generatedByDefaultAsIdentity(),
34+
topic: text().notNull(),
35+
},
36+
(table) => [
37+
unique("rooms_topic_key").on(table.topic),
38+
pgPolicy("authenticated can read rooms", {
39+
for: "select",
40+
to: authenticatedRole,
41+
using: sql`true`,
42+
}),
43+
pgPolicy("authenticated can add rooms", {
44+
for: "insert",
45+
to: authenticatedRole,
46+
withCheck: sql`true`,
47+
}),
48+
],
49+
);
50+
51+
export const profiles = pgTable(
52+
"profiles",
53+
{
54+
id: uuid()
55+
.primaryKey()
56+
.notNull()
57+
.references(() => authUsers.id, { onDelete: "cascade" }),
58+
email: text().notNull(),
59+
},
60+
(table) => [
61+
pgPolicy("authenticated can view all profiles", {
62+
for: "select",
63+
to: authenticatedRole,
64+
using: sql`true`,
65+
}),
66+
pgPolicy("owner can update profile", {
67+
for: "update",
68+
to: authenticatedRole,
69+
using: eq(table.id, authUid),
70+
withCheck: eq(table.id, authUid),
71+
}),
72+
],
73+
);
74+
75+
export const roomsUsers = pgTable(
76+
"rooms_users",
77+
{
78+
userId: uuid().notNull(),
79+
roomTopic: text().notNull(),
80+
joinedAt: timestamp({
81+
mode: "string",
82+
precision: 3,
83+
})
84+
.notNull()
85+
.defaultNow(),
86+
},
87+
(table) => [
88+
foreignKey({
89+
columns: [table.userId],
90+
foreignColumns: [authUsers.id],
91+
name: "rooms_users_user_id_fk",
92+
}),
93+
foreignKey({
94+
columns: [table.roomTopic],
95+
foreignColumns: [rooms.topic],
96+
name: "rooms_users_room_topic_fk",
97+
}),
98+
pgPolicy("authenticated can read rooms_users", {
99+
for: "select",
100+
to: authenticatedRole,
101+
using: sql`true`,
102+
}),
103+
pgPolicy("authenticated can add rooms_users", {
104+
for: "insert",
105+
to: authenticatedRole,
106+
withCheck: sql`true`,
107+
}),
108+
],
109+
);
28110

29-
export const postsRelations = relations(posts, ({ one }) => ({
30-
author: one(users, { fields: [posts.authorId], references: [users.id] }),
31-
}));
111+
export const roomsUsersProfiles = pgView("rooms_users_profiles")
112+
.with({
113+
securityInvoker: true,
114+
})
115+
.as((qb) =>
116+
qb
117+
.select({
118+
...getTableColumns(roomsUsers),
119+
email: profiles.email,
120+
})
121+
.from(roomsUsers)
122+
.innerJoin(profiles, eq(roomsUsers.userId, profiles.id)),
123+
);

apps/drizzle-run/app/registry/dialects/postgresql/presets/rls/seed.ts

+10-15
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,16 @@
44
* 💡Tip: you can use the `$` global variable to access goodies
55
*/
66

7-
import { db } from "./db";
8-
import { posts, users } from "./schema";
9-
10-
/* ------------------------------- Create user ------------------------------ */
7+
import { sql } from "drizzle-orm";
118

12-
const [{ userId }] = await db
13-
.insert(users)
14-
.values({
15-
name: $.random.fullName(),
16-
})
17-
.returning({ userId: users.id });
9+
import { db } from "./db";
1810

19-
/* ------------------------------- Create post ------------------------------ */
11+
await db.execute(sql`
12+
create or replace function auth.uid() returns uuid as $$
13+
select nullif(current_setting('request.jwt.claim.sub', true), '')::uuid;
14+
$$ language sql stable;
15+
`);
2016

21-
await db.insert(posts).values({
22-
authorId: userId,
23-
content: $.random.lorem(),
24-
});
17+
await db.execute(sql`
18+
GRANT postgres TO authenticated;
19+
`);

apps/drizzle-run/app/registry/dialects/postgresql/presets/starter-01/index.ts

+7-46
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,15 @@
33
* 💡Tip: you can use the `$` global variable to access goodies
44
*/
55

6-
import { eq } from "drizzle-orm";
7-
import { drizzle } from "drizzle-orm/pglite";
6+
import { db } from "./db";
7+
import {} from "./schema";
88

9-
import { db as admin } from "./db";
10-
import * as schema from "./schema";
11-
import { createDrizzle } from "./utils";
9+
// 💡 This playground run a seed code in the Seed tab
1210

13-
const userId1 = $.random.uuid();
14-
const userId2 = $.random.uuid();
15-
16-
const client = drizzle({
17-
client: admin.$client,
18-
schema,
19-
casing: "snake_case",
20-
});
21-
22-
const db = createDrizzle({ role: "authenticated", sub: userId1 }, { admin, client });
23-
24-
await db.admin.insert(schema.authUsers).values([
25-
{
26-
id: userId1,
27-
},
28-
{
29-
id: userId2,
11+
const result = await db.query.users.findMany({
12+
with: {
13+
posts: true,
3014
},
31-
]);
32-
33-
await db.admin.insert(schema.profiles).values({
34-
id: userId1,
35-
3615
});
3716

38-
console.log(
39-
"insert allowed",
40-
await db.rls(async (tx) => tx.insert(schema.rooms).values({ topic: "user room" }).returning()),
41-
);
42-
43-
console.log(
44-
"user can not edit other profile. Before",
45-
await db.admin.query.profiles.findMany(),
46-
await db.rls(async (tx) => {
47-
await tx.update(schema.profiles).set({ email: "nope" }).where(eq(schema.profiles.id, userId2));
48-
}),
49-
"after",
50-
await db.admin.query.profiles.findMany(),
51-
);
52-
53-
const dbAnonymous = createDrizzle({ role: "anon" }, { admin, client });
54-
55-
console.log("anonymous can not read");
56-
console.log(await dbAnonymous.rls(async (tx) => tx.select().from(schema.rooms)));
17+
console.log(result);
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"$schema": "../../../manifest.schema.json",
3-
"name": "(Experimental) Row Level Security (RLS)",
4-
"description": "A demo of RLS with a Supabase emulator"
3+
"name": "Simple example",
4+
"description": "A simple example to start with"
55
}

0 commit comments

Comments
 (0)