Skip to content

Commit c7cb660

Browse files
committed
feat(nuxt-drizzle): drizzle hooks
1 parent 2e70a6e commit c7cb660

File tree

10 files changed

+334
-28
lines changed

10 files changed

+334
-28
lines changed

packages/nuxt-drizzle/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@rstore/shared": "workspace:^",
4444
"@rstore/vue": "workspace:^",
4545
"h3": "^1.15.1",
46+
"hookable": "^5.5.3",
4647
"jiti": "^2.4.2",
4748
"pathe": "^2.0.3"
4849
},

packages/nuxt-drizzle/src/module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { getTableConfig as pgGetTableConfig } from 'drizzle-orm/pg-core'
55
import type { getTableConfig as singleStoreGetTableConfig } from 'drizzle-orm/singlestore-core'
66
import type { getTableConfig as sqliteGetTableConfig } from 'drizzle-orm/sqlite-core'
77
import fs from 'node:fs'
8-
import { addImportsDir, addServerHandler, addServerTemplate, addTemplate, addTypeTemplate, createResolver, defineNuxtModule, hasNuxtModule, installModule, updateTemplates, useLogger } from '@nuxt/kit'
8+
import { addImportsDir, addServerHandler, addServerImports, addServerTemplate, addTemplate, addTypeTemplate, createResolver, defineNuxtModule, hasNuxtModule, installModule, updateTemplates, useLogger } from '@nuxt/kit'
99
import { createTableRelationsHelpers, getTableName, is, isTable, Many, One, Relations, type Table, type TableConfig } from 'drizzle-orm'
1010
import { createJiti } from 'jiti'
1111
import path from 'pathe'
@@ -93,6 +93,9 @@ export default defineNuxtModule<ModuleOptions>({
9393
method: 'delete',
9494
})
9595
addImportsDir(resolve('./runtime/utils'))
96+
addServerImports([
97+
'rstoreDrizzleHooks',
98+
].map(name => ({ from: resolve('./runtime/server/utils/hooks'), name })))
9699

97100
const jiti = createJiti(import.meta.url, {
98101
moduleCache: false,
Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,52 @@
1+
import { and } from 'drizzle-orm'
12
import { defineEventHandler, getRouterParams } from 'h3'
23
import { getDrizzleKeyWhere, getDrizzleTableFromModel, rstoreUseDrizzle } from '../../utils'
4+
import { rstoreDrizzleHooks, type RstoreDrizzleMeta, type RstoreDrizzleTransformQuery } from '../../utils/hooks'
35

46
export default defineEventHandler(async (event) => {
5-
const { model: modelName, key } = getRouterParams(event) as { model: string, key: string }
7+
const meta: RstoreDrizzleMeta = {}
8+
const transforms: Array<RstoreDrizzleTransformQuery> = []
9+
10+
const params = getRouterParams(event) as { model: string, key: string }
11+
const { model: modelName, key } = params
12+
const query = getQuery(event)
13+
14+
await rstoreDrizzleHooks.callHook('item.delete.before', {
15+
event,
16+
model: modelName,
17+
meta,
18+
params,
19+
query,
20+
transformQuery: (transform) => { transforms.push(transform) },
21+
})
22+
623
const { table, primaryKeys } = getDrizzleTableFromModel(modelName)
724

8-
await rstoreUseDrizzle().delete(table as any).where(getDrizzleKeyWhere(key, primaryKeys, table))
25+
const where: any[] = [
26+
getDrizzleKeyWhere(key, primaryKeys, table),
27+
]
28+
29+
for (const transform of transforms) {
30+
transform({
31+
where: (condition) => { where.push(condition) },
32+
})
33+
}
34+
35+
await rstoreUseDrizzle().delete(table as any).where(and(
36+
...where,
37+
))
38+
39+
let result: any = null
40+
41+
await rstoreDrizzleHooks.callHook('item.delete.after', {
42+
event,
43+
model: modelName,
44+
meta,
45+
params,
46+
query,
47+
result,
48+
setResult: (r) => { result = r },
49+
})
50+
51+
return result
952
})
Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,56 @@
11
import type { RelationalQueryBuilder } from 'drizzle-orm/pg-core/query-builders/query'
2+
import { and } from 'drizzle-orm'
23
import { defineEventHandler, getQuery, getRouterParams } from 'h3'
34
import { getDrizzleKeyWhere, getDrizzleTableFromModel, type RstoreDrizzleQueryParamsOne, rstoreUseDrizzle } from '../../utils'
5+
import { rstoreDrizzleHooks, type RstoreDrizzleMeta, type RstoreDrizzleTransformQuery } from '../../utils/hooks'
46

57
export default defineEventHandler(async (event) => {
6-
const { model: modelName, key } = getRouterParams(event) as { model: string, key: string }
8+
const meta: RstoreDrizzleMeta = {}
9+
const transforms: Array<RstoreDrizzleTransformQuery> = []
10+
11+
const params = getRouterParams(event) as { model: string, key: string }
12+
const { model: modelName, key } = params
713
const query = getQuery(event) as RstoreDrizzleQueryParamsOne
14+
15+
await rstoreDrizzleHooks.callHook('item.get.before', {
16+
event,
17+
model: modelName,
18+
meta,
19+
params,
20+
query: query as Record<string, string | string[]>,
21+
transformQuery: (transform) => { transforms.push(transform) },
22+
})
23+
824
const { table, primaryKeys } = getDrizzleTableFromModel(modelName)
925

26+
const where: any[] = []
27+
for (const transform of transforms) {
28+
transform({
29+
where: (condition) => { where.push(condition) },
30+
})
31+
}
32+
1033
const dbQuery = rstoreUseDrizzle().query as unknown as Record<string, RelationalQueryBuilder<any, any>>
11-
const result = await dbQuery[modelName].findFirst({
12-
where: getDrizzleKeyWhere(key, primaryKeys, table),
34+
let result: any = await dbQuery[modelName].findFirst({
35+
where: and(
36+
getDrizzleKeyWhere(key, primaryKeys, table),
37+
...where,
38+
),
1339
with: query.with ? JSON.parse(query.with) : undefined,
1440
columns: query.columns ? JSON.parse(query.columns) : undefined,
1541
})
16-
return result ?? null
42+
43+
result ??= null
44+
45+
await rstoreDrizzleHooks.callHook('item.get.after', {
46+
event,
47+
model: modelName,
48+
meta,
49+
params,
50+
query: query as Record<string, string | string[]>,
51+
result,
52+
setResult: (r) => { result = r },
53+
})
54+
55+
return result
1756
})
Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,68 @@
1+
import { and } from 'drizzle-orm'
12
import { defineEventHandler, getRouterParams, readBody } from 'h3'
23
import { getDrizzleDialect, getDrizzleKeyWhere, getDrizzleTableFromModel, rstoreUseDrizzle } from '../../utils'
4+
import { rstoreDrizzleHooks, type RstoreDrizzleMeta, type RstoreDrizzleTransformQuery } from '../../utils/hooks'
35

46
export default defineEventHandler(async (event) => {
5-
const { model: modelName, key } = getRouterParams(event) as { model: string, key: string }
6-
const { table, primaryKeys } = getDrizzleTableFromModel(modelName)
7+
const meta: RstoreDrizzleMeta = {}
8+
const transforms: Array<RstoreDrizzleTransformQuery> = []
9+
10+
const params = getRouterParams(event) as { model: string, key: string }
11+
const { model: modelName, key } = params
12+
const query = getQuery(event)
713
const body = await readBody(event)
814

9-
const where = getDrizzleKeyWhere(key, primaryKeys, table)
10-
const q = rstoreUseDrizzle().update(table as any).set(body).where(where)
15+
await rstoreDrizzleHooks.callHook('item.patch.before', {
16+
event,
17+
model: modelName,
18+
meta,
19+
params,
20+
query,
21+
body,
22+
transformQuery: (transform) => { transforms.push(transform) },
23+
})
24+
25+
const { table, primaryKeys } = getDrizzleTableFromModel(modelName)
26+
27+
const where: any[] = [
28+
getDrizzleKeyWhere(key, primaryKeys, table),
29+
]
30+
31+
for (const transform of transforms) {
32+
transform({
33+
where: (condition) => { where.push(condition) },
34+
})
35+
}
36+
37+
const q = rstoreUseDrizzle().update(table as any).set(body).where(and(
38+
...where,
39+
))
40+
41+
let result: any
1142

1243
const dialect = getDrizzleDialect()
1344
if (dialect === 'pg' || dialect === 'sqlite') {
14-
const result = await q.returning()
15-
return result[0]
45+
const _result = await q.returning()
46+
result = _result[0]
1647
}
1748
else {
1849
await q
19-
const select = await rstoreUseDrizzle().select().from(table as any).where(where).limit(1)
20-
return select[0]
50+
const select = await rstoreUseDrizzle().select().from(table as any).where(and(
51+
...where,
52+
)).limit(1)
53+
result = select[0]
2154
}
55+
56+
await rstoreDrizzleHooks.callHook('item.patch.after', {
57+
event,
58+
model: modelName,
59+
meta,
60+
params,
61+
query,
62+
body,
63+
result,
64+
setResult: (r) => { result = r },
65+
})
66+
67+
return result
2268
})

packages/nuxt-drizzle/src/runtime/server/api/index.get.ts

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,45 @@
11
import type { RelationalQueryBuilder } from 'drizzle-orm/pg-core/query-builders/query'
2-
import { asc, desc } from 'drizzle-orm'
2+
import { and, asc, desc } from 'drizzle-orm'
33
import { createError, eventHandler, getQuery, getRouterParams } from 'h3'
44
import { getDrizzleCondition, getDrizzleTableFromModel, type RstoreDrizzleQueryParams, rstoreUseDrizzle } from '../utils'
5+
import { rstoreDrizzleHooks, type RstoreDrizzleMeta, type RstoreDrizzleTransformQuery } from '../utils/hooks'
56

67
const orderByOperators = {
78
asc,
89
desc,
910
}
1011

1112
export default eventHandler(async (event) => {
12-
const { model: modelName } = getRouterParams(event) as { model: string }
13-
const { table } = getDrizzleTableFromModel(modelName)
13+
const meta: RstoreDrizzleMeta = {}
14+
const transforms: Array<RstoreDrizzleTransformQuery> = []
1415

16+
const params = getRouterParams(event) as { model: string }
17+
const { model: modelName } = params
1518
const query = getQuery(event) as RstoreDrizzleQueryParams
1619

20+
await rstoreDrizzleHooks.callHook('index.get.before', {
21+
event,
22+
model: modelName,
23+
meta,
24+
params,
25+
query: query as Record<string, string | string[]>,
26+
transformQuery: (transform) => { transforms.push(transform) },
27+
})
28+
29+
const { table } = getDrizzleTableFromModel(modelName)
30+
1731
const dbQuery = rstoreUseDrizzle().query as unknown as Record<string, RelationalQueryBuilder<any, any>>
1832

1933
const q = {} as NonNullable<Parameters<typeof dbQuery[typeof modelName]['findMany']>[0]>
2034

35+
const where: any[] = []
36+
2137
if (query.where) {
2238
try {
2339
const where = JSON.parse(query.where as string) as any
2440
if (where) {
2541
const condition = getDrizzleCondition(table, where)
26-
q.where = condition
42+
where.push(condition)
2743
}
2844
}
2945
catch (e) {
@@ -35,6 +51,14 @@ export default eventHandler(async (event) => {
3551
}
3652
}
3753

54+
for (const transform of transforms) {
55+
transform({
56+
where: (condition) => { where.push(condition) },
57+
})
58+
}
59+
60+
q.where = where.length ? and(...where) : undefined
61+
3862
if (query.limit != null) {
3963
q.limit = Number.parseInt(query.limit)
4064
}
@@ -69,6 +93,18 @@ export default eventHandler(async (event) => {
6993
q.orderBy = orderBy
7094
}
7195

72-
const result = await dbQuery[modelName].findMany(q)
73-
return result ?? []
96+
let result = await dbQuery[modelName].findMany(q)
97+
result ??= []
98+
99+
await rstoreDrizzleHooks.callHook('index.get.after', {
100+
event,
101+
model: modelName,
102+
meta,
103+
params,
104+
query: query as Record<string, string | string[]>,
105+
result,
106+
setResult: (r) => { result = r },
107+
})
108+
109+
return result
74110
})
Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
11
import { and, eq, type Table } from 'drizzle-orm'
22
import { defineEventHandler, getRouterParams, readBody } from 'h3'
33
import { getDrizzleDialect, getDrizzleTableFromModel, rstoreUseDrizzle } from '../utils'
4+
import { rstoreDrizzleHooks, type RstoreDrizzleMeta, type RstoreDrizzleTransformQuery } from '../utils/hooks'
45

56
export default defineEventHandler(async (event) => {
6-
const { model: modelName } = getRouterParams(event) as { model: string }
7-
const { table } = getDrizzleTableFromModel(modelName)
7+
const meta: RstoreDrizzleMeta = {}
8+
const transforms: Array<RstoreDrizzleTransformQuery> = []
9+
10+
const params = getRouterParams(event) as { model: string }
11+
const { model: modelName } = params
812
const body = await readBody(event)
13+
const query = getQuery(event)
14+
15+
await rstoreDrizzleHooks.callHook('index.post.before', {
16+
event,
17+
model: modelName,
18+
meta,
19+
params,
20+
query,
21+
body,
22+
transformQuery: (transform) => { transforms.push(transform) },
23+
})
24+
25+
const { table } = getDrizzleTableFromModel(modelName)
926

1027
const q = rstoreUseDrizzle().insert(table as any).values(body)
1128

29+
let result: any
30+
1231
const dialect = getDrizzleDialect()
1332
if (dialect === 'pg' || dialect === 'sqlite') {
14-
const result = await q.returning()
15-
return result[0]
33+
const _result = await q.returning()
34+
result = _result[0]
1635
}
1736
else if (dialect === 'mysql' || dialect === 'singlestore') {
1837
// @ts-expect-error specific to mysql
19-
const result = await q.$returningId()
20-
const primaryKey = result[0]
38+
const _result = await q.$returningId()
39+
const primaryKey = _result[0]
2140
const select = await rstoreUseDrizzle().select().from(table as any).where(and(
2241
...Object.entries(primaryKey).map(([key, value]) => {
2342
return eq(table[key as keyof typeof table] as Table, value)
2443
}),
2544
)).limit(1)
26-
return select[0]
45+
result = select[0]
2746
}
47+
48+
await rstoreDrizzleHooks.callHook('index.post.after', {
49+
event,
50+
model: modelName,
51+
meta,
52+
params,
53+
query,
54+
body,
55+
result,
56+
setResult: (r) => { result = r },
57+
})
58+
59+
return result
2860
})

0 commit comments

Comments
 (0)