Skip to content

Commit 343dc5a

Browse files
authored
Persist Roles and Permissions between test runs (#854)
1 parent ec0c3c4 commit 343dc5a

File tree

4 files changed

+105
-60
lines changed

4 files changed

+105
-60
lines changed

prisma/migrations/20230914194400_init/migration.sql

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,53 @@ CREATE INDEX "_RoleToUser_B_index" ON "_RoleToUser"("B");
173173
-- Hey there, Kent here! This is how you can reliably seed your database with
174174
-- some data. You edit the migration.sql file and that will handle it for you.
175175

176+
-- The user Roles and Permissions are seeded here.
177+
-- If you'd like to customise roles and permissions, you can edit and add the code below to your `prisma/seed.ts` file.
178+
-- Seed your development database with `npx prisma db seed`
179+
-- Create a sql dump of your database with `sqlite3 prisma/data.db .dump > seed.sql`
180+
-- Replace the SQL below with your new Roles & Permissions related SQL from `seed.sql`
181+
182+
-- console.time('🔑 Created permissions...')
183+
-- const entities = ['user', 'note']
184+
-- const actions = ['create', 'read', 'update', 'delete']
185+
-- const accesses = ['own', 'any'] as const
186+
187+
-- let permissionsToCreate = []
188+
-- for (const entity of entities) {
189+
-- for (const action of actions) {
190+
-- for (const access of accesses) {
191+
-- permissionsToCreate.push({ entity, action, access })
192+
-- }
193+
-- }
194+
-- }
195+
-- await prisma.permission.createMany({ data: permissionsToCreate })
196+
-- console.timeEnd('🔑 Created permissions...')
197+
198+
-- console.time('👑 Created roles...')
199+
-- await prisma.role.create({
200+
-- data: {
201+
-- name: 'admin',
202+
-- permissions: {
203+
-- connect: await prisma.permission.findMany({
204+
-- select: { id: true },
205+
-- where: { access: 'any' },
206+
-- }),
207+
-- },
208+
-- },
209+
-- })
210+
-- await prisma.role.create({
211+
-- data: {
212+
-- name: 'user',
213+
-- permissions: {
214+
-- connect: await prisma.permission.findMany({
215+
-- select: { id: true },
216+
-- where: { access: 'own' },
217+
-- }),
218+
-- },
219+
-- },
220+
-- })
221+
-- console.timeEnd('👑 Created roles...')
222+
176223
INSERT INTO Permission VALUES('clnf2zvli0000pcou3zzzzome','create','user','own','',1696625465526,1696625465526);
177224
INSERT INTO Permission VALUES('clnf2zvll0001pcouly1310ku','create','user','any','',1696625465529,1696625465529);
178225
INSERT INTO Permission VALUES('clnf2zvll0002pcouka7348re','read','user','own','',1696625465530,1696625465530);
@@ -208,4 +255,4 @@ INSERT INTO _PermissionToRole VALUES('clnf2zvlo0006pcouyoptc5jp','clnf2zvlx000hp
208255
INSERT INTO _PermissionToRole VALUES('clnf2zvlp0008pcou9r0fhbm8','clnf2zvlx000hpcou5dfrbegs');
209256
INSERT INTO _PermissionToRole VALUES('clnf2zvlq000apcouxnspejs9','clnf2zvlx000hpcou5dfrbegs');
210257
INSERT INTO _PermissionToRole VALUES('clnf2zvlr000cpcouy1vp6oeg','clnf2zvlx000hpcou5dfrbegs');
211-
INSERT INTO _PermissionToRole VALUES('clnf2zvls000epcou4ts5ui8f','clnf2zvlx000hpcou5dfrbegs');
258+
INSERT INTO _PermissionToRole VALUES('clnf2zvls000epcou4ts5ui8f','clnf2zvlx000hpcou5dfrbegs');

prisma/seed.ts

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,9 @@ async function seed() {
1717
console.time(`🌱 Database has been seeded`)
1818

1919
console.time('🧹 Cleaned up the database...')
20-
await cleanupDb(prisma)
20+
await cleanupDb()
2121
console.timeEnd('🧹 Cleaned up the database...')
2222

23-
console.time('🔑 Created permissions...')
24-
const entities = ['user', 'note']
25-
const actions = ['create', 'read', 'update', 'delete']
26-
const accesses = ['own', 'any'] as const
27-
28-
let permissionsToCreate = []
29-
for (const entity of entities) {
30-
for (const action of actions) {
31-
for (const access of accesses) {
32-
permissionsToCreate.push({ entity, action, access })
33-
}
34-
}
35-
}
36-
await prisma.permission.createMany({ data: permissionsToCreate })
37-
console.timeEnd('🔑 Created permissions...')
38-
39-
console.time('👑 Created roles...')
40-
await prisma.role.create({
41-
data: {
42-
name: 'admin',
43-
permissions: {
44-
connect: await prisma.permission.findMany({
45-
select: { id: true },
46-
where: { access: 'any' },
47-
}),
48-
},
49-
},
50-
})
51-
await prisma.role.create({
52-
data: {
53-
name: 'user',
54-
permissions: {
55-
connect: await prisma.permission.findMany({
56-
select: { id: true },
57-
where: { access: 'own' },
58-
}),
59-
},
60-
},
61-
})
62-
console.timeEnd('👑 Created roles...')
63-
6423
const totalUsers = 5
6524
console.time(`👤 Created ${totalUsers} users...`)
6625
const noteImages = await getNoteImages()

tests/db-utils.ts

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'node:fs'
22
import { faker } from '@faker-js/faker'
3-
import { type PrismaClient } from '@prisma/client'
43
import bcrypt from 'bcryptjs'
4+
import Database from 'better-sqlite3'
55
import { UniqueEnforcer } from 'enforce-unique'
66

77
const uniqueUsernameEnforcer = new UniqueEnforcer()
@@ -115,23 +115,63 @@ export async function img({
115115
}
116116
}
117117

118-
export async function cleanupDb(prisma: PrismaClient) {
119-
const tables = await prisma.$queryRaw<
120-
{ name: string }[]
121-
>`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_prisma_migrations';`
118+
let _migrationSqls: Array<Array<string>> | undefined
119+
async function getMigrationSqls() {
120+
if (_migrationSqls) return _migrationSqls
121+
122+
const migrationSqls: Array<Array<string>> = []
123+
const migrationPaths = (await fs.promises.readdir('prisma/migrations'))
124+
.filter((dir) => dir !== 'migration_lock.toml')
125+
.map((dir) => `prisma/migrations/${dir}/migration.sql`)
126+
127+
for (const path of migrationPaths) {
128+
const sql = await fs.promises.readFile(path, 'utf8')
129+
const statements = sql
130+
.split(';')
131+
.map((statement) => statement.trim())
132+
.filter(Boolean)
133+
migrationSqls.push(statements)
134+
}
135+
136+
_migrationSqls = migrationSqls
137+
138+
return migrationSqls
139+
}
140+
141+
export async function cleanupDb() {
142+
const db = new Database(process.env.DATABASE_URL!.replace('file:', ''))
122143

123144
try {
124145
// Disable FK constraints to avoid relation conflicts during deletion
125-
await prisma.$executeRawUnsafe(`PRAGMA foreign_keys = OFF`)
126-
await prisma.$transaction([
127-
// Delete all rows from each table, preserving table structures
128-
...tables.map(({ name }) =>
129-
prisma.$executeRawUnsafe(`DELETE from "${name}"`),
130-
),
131-
])
132-
} catch (error) {
133-
console.error('Error cleaning up database:', error)
146+
db.exec('PRAGMA foreign_keys = OFF')
147+
148+
// Get all table names
149+
const tables = db
150+
.prepare(
151+
`
152+
SELECT name FROM sqlite_master
153+
WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_prisma_migrations'
154+
`,
155+
)
156+
.all() as { name: string }[]
157+
158+
// Delete tables except the ones that are excluded above
159+
for (const { name } of tables) {
160+
db.exec(`DROP TABLE IF EXISTS "${name}"`)
161+
}
162+
163+
// Get migration SQLs and run each migration
164+
const migrationSqls = await getMigrationSqls()
165+
for (const statements of migrationSqls) {
166+
// Run each sql statement in the migration
167+
db.transaction(() => {
168+
for (const statement of statements) {
169+
db.exec(statement)
170+
}
171+
})()
172+
}
134173
} finally {
135-
await prisma.$executeRawUnsafe(`PRAGMA foreign_keys = ON`)
174+
db.exec('PRAGMA foreign_keys = ON')
175+
db.close()
136176
}
137177
}

tests/setup/db-setup.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ beforeAll(async () => {
1515
// we *must* use dynamic imports here so the process.env.DATABASE_URL is set
1616
// before prisma is imported and initialized
1717
afterEach(async () => {
18-
const { prisma } = await import('#app/utils/db.server.ts')
19-
await cleanupDb(prisma)
18+
await cleanupDb()
2019
})
2120

2221
afterAll(async () => {

0 commit comments

Comments
 (0)