@effectify/prisma 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/cli.js +9 -9
- package/dist/src/commands/init.d.ts +1 -1
- package/dist/src/commands/init.js +0 -2
- package/dist/src/commands/prisma.d.ts +5 -0
- package/dist/src/commands/prisma.js +35 -0
- package/dist/src/generators/sql-schema-generator.d.ts +9 -0
- package/dist/src/generators/sql-schema-generator.js +50 -58
- package/dist/src/services/generator-context.d.ts +6 -0
- package/dist/src/services/generator-context.js +3 -0
- package/dist/src/services/generator-service.d.ts +14 -0
- package/dist/src/services/generator-service.js +121 -0
- package/dist/src/services/render-service.d.ts +10 -0
- package/dist/src/services/render-service.js +23 -0
- package/dist/src/templates/model.eta +8 -0
- package/package.json +15 -11
- package/dist/src/commands/generate-effect.d.ts +0 -2
- package/dist/src/commands/generate-effect.js +0 -73
- package/dist/src/commands/generate-sql-schema.d.ts +0 -2
- package/dist/src/commands/generate-sql-schema.js +0 -72
- package/dist/src/effect-prisma.d.ts +0 -2
- package/dist/src/effect-prisma.js +0 -1771
- package/dist/src/generators/prisma-effect-generator.d.ts +0 -1
- package/dist/src/generators/prisma-effect-generator.js +0 -446
- package/prisma/dev.db +0 -0
- package/prisma/generated/client.d.ts +0 -1
- package/prisma/generated/client.js +0 -5
- package/prisma/generated/default.d.ts +0 -1
- package/prisma/generated/default.js +0 -5
- package/prisma/generated/edge.d.ts +0 -1
- package/prisma/generated/edge.js +0 -141
- package/prisma/generated/effect/index.ts +0 -392
- package/prisma/generated/effect/models/Todo.ts +0 -6
- package/prisma/generated/effect/prisma-repository.ts +0 -954
- package/prisma/generated/effect/prisma-schema.ts +0 -94
- package/prisma/generated/effect/schemas/enums.ts +0 -6
- package/prisma/generated/effect/schemas/index.ts +0 -2
- package/prisma/generated/effect/schemas/types.ts +0 -40
- package/prisma/generated/index-browser.js +0 -172
- package/prisma/generated/index.d.ts +0 -2376
- package/prisma/generated/index.js +0 -141
- package/prisma/generated/package.json +0 -144
- package/prisma/generated/query_compiler_bg.js +0 -2
- package/prisma/generated/query_compiler_bg.wasm +0 -0
- package/prisma/generated/query_compiler_bg.wasm-base64.js +0 -2
- package/prisma/generated/runtime/client.d.ts +0 -3180
- package/prisma/generated/runtime/client.js +0 -86
- package/prisma/generated/runtime/index-browser.d.ts +0 -87
- package/prisma/generated/runtime/index-browser.js +0 -6
- package/prisma/generated/runtime/wasm-compiler-edge.js +0 -76
- package/prisma/generated/schema.prisma +0 -31
- package/prisma/generated/wasm-edge-light-loader.mjs +0 -5
- package/prisma/generated/wasm-worker-loader.mjs +0 -5
- package/prisma/migrations/20250721164420_init/migration.sql +0 -9
- package/prisma/migrations/20250721191716_dumb/migration.sql +0 -49
- package/prisma/migrations/migration_lock.toml +0 -3
- package/prisma/schema.prisma +0 -31
- package/prisma.config.ts +0 -8
- package/project.json +0 -48
- package/scripts/cleanup-tests.ts +0 -26
- package/scripts/generate-test-files.ts +0 -93
- package/setup-tests.ts +0 -10
- package/src/cli.ts +0 -22
- package/src/commands/init.ts +0 -153
- package/src/commands/prisma.ts +0 -50
- package/src/generators/sql-schema-generator.ts +0 -66
- package/src/services/generator-context.ts +0 -4
- package/src/services/generator-service.ts +0 -178
- package/src/services/render-service.ts +0 -32
- package/src/templates/model.eta +0 -6
- package/test/prisma-model.test.ts +0 -340
- package/test/utils.ts +0 -10
- package/tsconfig.json +0 -20
- package/tsconfig.lib.json +0 -24
- package/tsconfig.spec.json +0 -15
- package/vitest.config.ts +0 -24
- /package/{src → dist/src}/templates/index-custom-error.eta +0 -0
- /package/{src → dist/src}/templates/index-default.eta +0 -0
- /package/{src → dist/src}/templates/prisma-raw-sql.eta +0 -0
- /package/{src → dist/src}/templates/prisma-repository.eta +0 -0
- /package/{src → dist/src}/templates/prisma-schema.eta +0 -0
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import * as FileSystem from '@effect/platform/FileSystem'
|
|
2
|
-
import * as Path from '@effect/platform/Path'
|
|
3
|
-
import type { DMMF, GeneratorOptions } from '@prisma/generator-helper'
|
|
4
|
-
import * as Context from 'effect/Context'
|
|
5
|
-
import * as Effect from 'effect/Effect'
|
|
6
|
-
import * as Layer from 'effect/Layer'
|
|
7
|
-
import { GeneratorContext } from './generator-context.js'
|
|
8
|
-
import { RenderService } from './render-service.js'
|
|
9
|
-
|
|
10
|
-
export class GeneratorService extends Context.Tag('GeneratorService')<
|
|
11
|
-
GeneratorService,
|
|
12
|
-
{
|
|
13
|
-
readonly generate: Effect.Effect<void, Error, GeneratorContext>
|
|
14
|
-
}
|
|
15
|
-
>() {
|
|
16
|
-
static Live = Layer.effect(
|
|
17
|
-
GeneratorService,
|
|
18
|
-
Effect.gen(function* () {
|
|
19
|
-
const fs = yield* FileSystem.FileSystem
|
|
20
|
-
const path = yield* Path.Path
|
|
21
|
-
const { render } = yield* RenderService
|
|
22
|
-
|
|
23
|
-
const parseErrorImportPath = (
|
|
24
|
-
errorImportPath: string | undefined,
|
|
25
|
-
): { path: string; className: string } | null => {
|
|
26
|
-
if (!errorImportPath) {
|
|
27
|
-
return null
|
|
28
|
-
}
|
|
29
|
-
const [modulePath, className] = errorImportPath.split('#')
|
|
30
|
-
if (!(modulePath && className)) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`Invalid errorImportPath format: "${errorImportPath}". Expected "path/to/module#ErrorClassName"`,
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
return { path: modulePath, className }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const addExtension = (filePath: string, extension: string): string => {
|
|
39
|
-
if (!extension) {
|
|
40
|
-
return filePath
|
|
41
|
-
}
|
|
42
|
-
const ext = path.extname(filePath)
|
|
43
|
-
if (ext) {
|
|
44
|
-
return filePath
|
|
45
|
-
}
|
|
46
|
-
return `${filePath}.${extension}`
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const fixSchemaImports = (outputDir: string) =>
|
|
50
|
-
Effect.gen(function* () {
|
|
51
|
-
const schemasDir = path.join(outputDir, 'schemas')
|
|
52
|
-
const indexFile = path.join(schemasDir, 'index.ts')
|
|
53
|
-
|
|
54
|
-
const exists = yield* fs.exists(indexFile)
|
|
55
|
-
if (!exists) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const content = yield* fs.readFileString(indexFile)
|
|
60
|
-
const fixedContent = content
|
|
61
|
-
.replace(/export \* from '\.\/enums'/g, "export * from './enums.js'")
|
|
62
|
-
.replace(/export \* from '\.\/types'/g, "export * from './types.js'")
|
|
63
|
-
|
|
64
|
-
if (content !== fixedContent) {
|
|
65
|
-
yield* fs.writeFileString(indexFile, fixedContent)
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const getClientImportPath = (config: GeneratorOptions['generator']['config']) =>
|
|
70
|
-
Array.isArray(config.clientImportPath)
|
|
71
|
-
? config.clientImportPath[0]
|
|
72
|
-
: (config.clientImportPath ?? '@prisma/client')
|
|
73
|
-
|
|
74
|
-
const getErrorImportPath = (config: GeneratorOptions['generator']['config']) =>
|
|
75
|
-
Array.isArray(config.errorImportPath) ? config.errorImportPath[0] : config.errorImportPath
|
|
76
|
-
|
|
77
|
-
const getImportFileExtension = (config: GeneratorOptions['generator']['config']) =>
|
|
78
|
-
Array.isArray(config.importFileExtension) ? config.importFileExtension[0] : (config.importFileExtension ?? '')
|
|
79
|
-
|
|
80
|
-
const getCustomError = (
|
|
81
|
-
config: GeneratorOptions['generator']['config'],
|
|
82
|
-
options: GeneratorOptions,
|
|
83
|
-
schemaDir: string,
|
|
84
|
-
) => {
|
|
85
|
-
const errorImportPathRaw = getErrorImportPath(config)
|
|
86
|
-
const importFileExtension = getImportFileExtension(config)
|
|
87
|
-
|
|
88
|
-
let customError = parseErrorImportPath(errorImportPathRaw)
|
|
89
|
-
|
|
90
|
-
if (customError?.path.startsWith('.')) {
|
|
91
|
-
const outputDir = options.generator.output?.value
|
|
92
|
-
if (outputDir) {
|
|
93
|
-
const absoluteErrorPath = path.resolve(schemaDir, customError.path)
|
|
94
|
-
const relativeToOutput = path.relative(outputDir, absoluteErrorPath)
|
|
95
|
-
const normalizedPath = relativeToOutput.startsWith('.') ? relativeToOutput : `./${relativeToOutput}`
|
|
96
|
-
const pathWithExtension = addExtension(normalizedPath, importFileExtension)
|
|
97
|
-
customError = { ...customError, path: pathWithExtension }
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return customError
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const getGeneratorConfig = (options: GeneratorOptions, schemaDir: string) => {
|
|
104
|
-
const { config } = options.generator
|
|
105
|
-
const clientImportPath = getClientImportPath(config)
|
|
106
|
-
const customError = getCustomError(config, options, schemaDir)
|
|
107
|
-
|
|
108
|
-
return { clientImportPath, customError }
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const generatePrismaSchema = (outputDir: string) =>
|
|
112
|
-
Effect.gen(function* () {
|
|
113
|
-
const content = yield* render('prisma-schema', {})
|
|
114
|
-
yield* fs.writeFileString(path.join(outputDir, 'prisma-schema.ts'), content)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const generatePrismaRepository = (outputDir: string, clientImportPath: string) =>
|
|
118
|
-
Effect.gen(function* () {
|
|
119
|
-
const content = yield* render('prisma-repository', { clientImportPath })
|
|
120
|
-
yield* fs.writeFileString(path.join(outputDir, 'prisma-repository.ts'), content)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
const generateModels = (outputDir: string, models: readonly DMMF.Model[]) =>
|
|
124
|
-
Effect.gen(function* () {
|
|
125
|
-
yield* fs.makeDirectory(path.join(outputDir, 'models'), { recursive: true })
|
|
126
|
-
for (const model of models) {
|
|
127
|
-
const content = yield* render('model', { model })
|
|
128
|
-
yield* fs.writeFileString(path.join(outputDir, 'models', `${model.name}.ts`), content)
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
const generateIndex = (
|
|
133
|
-
outputDir: string,
|
|
134
|
-
models: readonly DMMF.Model[],
|
|
135
|
-
clientImportPath: string,
|
|
136
|
-
customError: { path: string; className: string } | null,
|
|
137
|
-
) =>
|
|
138
|
-
Effect.gen(function* () {
|
|
139
|
-
const errorType = customError ? customError.className : 'PrismaError'
|
|
140
|
-
const rawSqlOperations = yield* render('prisma-raw-sql', { errorType })
|
|
141
|
-
const modelExports = models.map((m) => `export * from "./models/${m.name}.js"`).join('\n')
|
|
142
|
-
|
|
143
|
-
const templateName = customError ? 'index-custom-error' : 'index-default'
|
|
144
|
-
const content = yield* render(templateName, {
|
|
145
|
-
clientImportPath,
|
|
146
|
-
customError,
|
|
147
|
-
rawSqlOperations,
|
|
148
|
-
modelExports,
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
yield* fs.writeFileString(path.join(outputDir, 'index.ts'), content)
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
const generate = Effect.gen(function* () {
|
|
155
|
-
const options = yield* GeneratorContext
|
|
156
|
-
const models = options.dmmf.datamodel.models
|
|
157
|
-
const outputDir = options.generator.output?.value
|
|
158
|
-
const schemaDir = path.dirname(options.schemaPath)
|
|
159
|
-
|
|
160
|
-
if (!outputDir) {
|
|
161
|
-
return yield* Effect.fail(new Error('No output directory specified'))
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const { clientImportPath, customError } = getGeneratorConfig(options, schemaDir)
|
|
165
|
-
|
|
166
|
-
yield* fs.makeDirectory(outputDir, { recursive: true })
|
|
167
|
-
|
|
168
|
-
yield* generatePrismaSchema(outputDir)
|
|
169
|
-
yield* generatePrismaRepository(outputDir, clientImportPath)
|
|
170
|
-
yield* generateModels(outputDir, models)
|
|
171
|
-
yield* generateIndex(outputDir, models, clientImportPath, customError)
|
|
172
|
-
yield* fixSchemaImports(outputDir)
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
return { generate }
|
|
176
|
-
}),
|
|
177
|
-
)
|
|
178
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import * as path from 'node:path'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
|
-
import * as Context from 'effect/Context'
|
|
4
|
-
import * as Effect from 'effect/Effect'
|
|
5
|
-
import * as Layer from 'effect/Layer'
|
|
6
|
-
import { Eta } from 'eta'
|
|
7
|
-
|
|
8
|
-
export class RenderService extends Context.Tag('RenderService')<
|
|
9
|
-
RenderService,
|
|
10
|
-
{
|
|
11
|
-
readonly render: (templateName: string, data: Record<string, unknown>) => Effect.Effect<string, Error>
|
|
12
|
-
}
|
|
13
|
-
>() {
|
|
14
|
-
static Live = Layer.sync(RenderService, () => {
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
16
|
-
const __dirname = path.dirname(__filename)
|
|
17
|
-
const templatesDir = path.resolve(__dirname, '../templates')
|
|
18
|
-
|
|
19
|
-
const eta = new Eta({
|
|
20
|
-
views: templatesDir,
|
|
21
|
-
autoEscape: false,
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
render: (templateName: string, data: Record<string, unknown>) =>
|
|
26
|
-
Effect.try({
|
|
27
|
-
try: () => eta.render(templateName, data),
|
|
28
|
-
catch: (error) => new Error(`Failed to render template ${templateName}: ${error}`),
|
|
29
|
-
}),
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
}
|
package/src/templates/model.eta
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import { layer } from '@effect/vitest'
|
|
2
|
-
import { Prisma, PrismaClient, TodoModel } from '@prisma/effect'
|
|
3
|
-
import * as PrismaRepository from '@prisma/effect/prisma-repository.js'
|
|
4
|
-
import { Effect, Layer, Option } from 'effect'
|
|
5
|
-
import { beforeEach, expect } from 'vitest'
|
|
6
|
-
import { prisma as db } from './utils.js'
|
|
7
|
-
|
|
8
|
-
// Create the Prisma layer manually to use the existing client instance
|
|
9
|
-
const ClientLayer = Layer.succeed(PrismaClient, { tx: db, client: db })
|
|
10
|
-
const PrismaLayer = Layer.merge(ClientLayer, Prisma.Default.pipe(Layer.provide(ClientLayer)))
|
|
11
|
-
|
|
12
|
-
layer(PrismaLayer)('Prisma Model Repository', (it) => {
|
|
13
|
-
beforeEach(async () => {
|
|
14
|
-
await db.todo.deleteMany({})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it.effect('create', () =>
|
|
18
|
-
Effect.gen(function* () {
|
|
19
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
20
|
-
|
|
21
|
-
const created = yield* todoRepo.create({
|
|
22
|
-
data: {
|
|
23
|
-
id: 1,
|
|
24
|
-
title: 'Create Test',
|
|
25
|
-
content: 'Content',
|
|
26
|
-
published: false,
|
|
27
|
-
authorId: 1,
|
|
28
|
-
},
|
|
29
|
-
})
|
|
30
|
-
expect(created.id).toBe(1)
|
|
31
|
-
expect(created.title).toBe('Create Test')
|
|
32
|
-
}),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
it.effect('createMany', () =>
|
|
36
|
-
Effect.gen(function* () {
|
|
37
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
38
|
-
|
|
39
|
-
const result = yield* todoRepo.createMany({
|
|
40
|
-
data: [
|
|
41
|
-
{ id: 1, title: 'Todo 1', content: 'C1', published: false, authorId: 1 },
|
|
42
|
-
{ id: 2, title: 'Todo 2', content: 'C2', published: true, authorId: 1 },
|
|
43
|
-
],
|
|
44
|
-
})
|
|
45
|
-
expect(result.count).toBe(2)
|
|
46
|
-
}),
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
it.effect('createManyAndReturn', () =>
|
|
50
|
-
Effect.gen(function* () {
|
|
51
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
52
|
-
|
|
53
|
-
const result = yield* todoRepo.createManyAndReturn({
|
|
54
|
-
data: [
|
|
55
|
-
{ id: 1, title: 'Todo 1', content: 'C1', published: false, authorId: 1 },
|
|
56
|
-
{ id: 2, title: 'Todo 2', content: 'C2', published: true, authorId: 1 },
|
|
57
|
-
],
|
|
58
|
-
})
|
|
59
|
-
expect(result).toHaveLength(2)
|
|
60
|
-
expect(result[0].title).toBe('Todo 1')
|
|
61
|
-
expect(result[1].title).toBe('Todo 2')
|
|
62
|
-
}),
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
it.effect('findUnique', () =>
|
|
66
|
-
Effect.gen(function* () {
|
|
67
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
68
|
-
|
|
69
|
-
yield* todoRepo.create({
|
|
70
|
-
data: { id: 1, title: 'Find Unique', content: 'Content', published: false, authorId: 1 },
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
const found = yield* todoRepo.findUnique({
|
|
74
|
-
where: { id: 1 },
|
|
75
|
-
})
|
|
76
|
-
expect(Option.isSome(found)).toBe(true)
|
|
77
|
-
if (Option.isSome(found)) {
|
|
78
|
-
expect(found.value.title).toBe('Find Unique')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const notFound = yield* todoRepo.findUnique({
|
|
82
|
-
where: { id: 999 },
|
|
83
|
-
})
|
|
84
|
-
expect(Option.isNone(notFound)).toBe(true)
|
|
85
|
-
}),
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
it.effect('findUniqueOrThrow', () =>
|
|
89
|
-
Effect.gen(function* () {
|
|
90
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
91
|
-
|
|
92
|
-
yield* todoRepo.create({
|
|
93
|
-
data: { id: 1, title: 'Find Unique Or Throw', content: 'Content', published: false, authorId: 1 },
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
const found = yield* todoRepo.findUniqueOrThrow({
|
|
97
|
-
where: { id: 1 },
|
|
98
|
-
})
|
|
99
|
-
expect(found.title).toBe('Find Unique Or Throw')
|
|
100
|
-
|
|
101
|
-
const error = yield* todoRepo
|
|
102
|
-
.findUniqueOrThrow({
|
|
103
|
-
where: { id: 999 },
|
|
104
|
-
})
|
|
105
|
-
.pipe(Effect.flip)
|
|
106
|
-
|
|
107
|
-
expect(error._tag).toBe('PrismaRecordNotFoundError')
|
|
108
|
-
}),
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
it.effect('findFirst', () =>
|
|
112
|
-
Effect.gen(function* () {
|
|
113
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
114
|
-
|
|
115
|
-
yield* todoRepo.create({
|
|
116
|
-
data: { id: 1, title: 'Find First', content: 'Content', published: false, authorId: 1 },
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
const found = yield* todoRepo.findFirst({
|
|
120
|
-
where: { title: 'Find First' },
|
|
121
|
-
})
|
|
122
|
-
expect(Option.isSome(found)).toBe(true)
|
|
123
|
-
}),
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
it.effect('findFirstOrThrow', () =>
|
|
127
|
-
Effect.gen(function* () {
|
|
128
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
129
|
-
|
|
130
|
-
yield* todoRepo.create({
|
|
131
|
-
data: { id: 1, title: 'Find First Or Throw', content: 'Content', published: false, authorId: 1 },
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
const found = yield* todoRepo.findFirstOrThrow({
|
|
135
|
-
where: { title: 'Find First Or Throw' },
|
|
136
|
-
})
|
|
137
|
-
expect(found.title).toBe('Find First Or Throw')
|
|
138
|
-
|
|
139
|
-
const error = yield* todoRepo
|
|
140
|
-
.findFirstOrThrow({
|
|
141
|
-
where: { title: 'Non Existent' },
|
|
142
|
-
})
|
|
143
|
-
.pipe(Effect.flip)
|
|
144
|
-
|
|
145
|
-
expect(error._tag).toBe('PrismaRecordNotFoundError')
|
|
146
|
-
}),
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
it.effect('findMany', () =>
|
|
150
|
-
Effect.gen(function* () {
|
|
151
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
152
|
-
|
|
153
|
-
yield* todoRepo.createMany({
|
|
154
|
-
data: [
|
|
155
|
-
{ id: 1, title: 'T1', content: 'C', published: true, authorId: 1 },
|
|
156
|
-
{ id: 2, title: 'T2', content: 'C', published: true, authorId: 1 },
|
|
157
|
-
{ id: 3, title: 'T3', content: 'C', published: false, authorId: 1 },
|
|
158
|
-
],
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
const found = yield* todoRepo.findMany({
|
|
162
|
-
where: { published: true },
|
|
163
|
-
})
|
|
164
|
-
expect(found).toHaveLength(2)
|
|
165
|
-
}),
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
it.effect('update', () =>
|
|
169
|
-
Effect.gen(function* () {
|
|
170
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
171
|
-
|
|
172
|
-
yield* todoRepo.create({
|
|
173
|
-
data: { id: 1, title: 'Original', content: 'Content', published: false, authorId: 1 },
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
const updated = yield* todoRepo.update({
|
|
177
|
-
where: { id: 1 },
|
|
178
|
-
data: { title: 'Updated' },
|
|
179
|
-
})
|
|
180
|
-
expect(updated.title).toBe('Updated')
|
|
181
|
-
}),
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
it.effect('updateMany', () =>
|
|
185
|
-
Effect.gen(function* () {
|
|
186
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
187
|
-
|
|
188
|
-
yield* todoRepo.createMany({
|
|
189
|
-
data: [
|
|
190
|
-
{ id: 1, title: 'T1', content: 'C', published: false, authorId: 1 },
|
|
191
|
-
{ id: 2, title: 'T2', content: 'C', published: false, authorId: 1 },
|
|
192
|
-
],
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
const result = yield* todoRepo.updateMany({
|
|
196
|
-
where: { published: false },
|
|
197
|
-
data: { published: true },
|
|
198
|
-
})
|
|
199
|
-
expect(result.count).toBe(2)
|
|
200
|
-
}),
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
it.effect('upsert', () =>
|
|
204
|
-
Effect.gen(function* () {
|
|
205
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
206
|
-
|
|
207
|
-
// Create new
|
|
208
|
-
const created = yield* todoRepo.upsert({
|
|
209
|
-
where: { id: 1 },
|
|
210
|
-
create: { id: 1, title: 'Upsert Created', content: 'Content', published: false, authorId: 1 },
|
|
211
|
-
update: { title: 'Upsert Updated' },
|
|
212
|
-
})
|
|
213
|
-
expect(created.title).toBe('Upsert Created')
|
|
214
|
-
|
|
215
|
-
// Update existing
|
|
216
|
-
const updated = yield* todoRepo.upsert({
|
|
217
|
-
where: { id: 1 },
|
|
218
|
-
create: { id: 1, title: 'Upsert Created', content: 'Content', published: false, authorId: 1 },
|
|
219
|
-
update: { title: 'Upsert Updated' },
|
|
220
|
-
})
|
|
221
|
-
expect(updated.title).toBe('Upsert Updated')
|
|
222
|
-
}),
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
it.effect('delete', () =>
|
|
226
|
-
Effect.gen(function* () {
|
|
227
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
228
|
-
|
|
229
|
-
yield* todoRepo.create({
|
|
230
|
-
data: { id: 1, title: 'To Delete', content: 'Content', published: false, authorId: 1 },
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
const deleted = yield* todoRepo.delete({
|
|
234
|
-
where: { id: 1 },
|
|
235
|
-
})
|
|
236
|
-
expect(deleted.title).toBe('To Delete')
|
|
237
|
-
|
|
238
|
-
const found = yield* todoRepo.findUnique({
|
|
239
|
-
where: { id: 1 },
|
|
240
|
-
})
|
|
241
|
-
expect(Option.isNone(found)).toBe(true)
|
|
242
|
-
}),
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
it.effect('deleteMany', () =>
|
|
246
|
-
Effect.gen(function* () {
|
|
247
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
248
|
-
|
|
249
|
-
yield* todoRepo.createMany({
|
|
250
|
-
data: [
|
|
251
|
-
{ id: 1, title: 'T1', content: 'C', published: false, authorId: 1 },
|
|
252
|
-
{ id: 2, title: 'T2', content: 'C', published: false, authorId: 1 },
|
|
253
|
-
],
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
const result = yield* todoRepo.deleteMany({
|
|
257
|
-
where: { published: false },
|
|
258
|
-
})
|
|
259
|
-
expect(result.count).toBe(2)
|
|
260
|
-
}),
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
it.effect('count', () =>
|
|
264
|
-
Effect.gen(function* () {
|
|
265
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
266
|
-
|
|
267
|
-
yield* todoRepo.createMany({
|
|
268
|
-
data: [
|
|
269
|
-
{ id: 1, title: 'T1', content: 'C', published: false, authorId: 1 },
|
|
270
|
-
{ id: 2, title: 'T2', content: 'C', published: false, authorId: 1 },
|
|
271
|
-
],
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
const count = yield* todoRepo.count()
|
|
275
|
-
expect(count).toBe(2)
|
|
276
|
-
|
|
277
|
-
const filteredCount = yield* todoRepo.count({
|
|
278
|
-
where: { id: 1 },
|
|
279
|
-
})
|
|
280
|
-
expect(filteredCount).toBe(1)
|
|
281
|
-
}),
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
it.effect('aggregate', () =>
|
|
285
|
-
Effect.gen(function* () {
|
|
286
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
287
|
-
|
|
288
|
-
yield* todoRepo.createMany({
|
|
289
|
-
data: [
|
|
290
|
-
{ id: 1, title: 'T1', content: 'C', published: false, authorId: 1 },
|
|
291
|
-
{ id: 2, title: 'T2', content: 'C', published: false, authorId: 1 },
|
|
292
|
-
],
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
const result: any = yield* todoRepo.aggregate({
|
|
296
|
-
_count: true,
|
|
297
|
-
_min: { id: true },
|
|
298
|
-
_max: { id: true },
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
expect(result._count).toBe(2)
|
|
302
|
-
expect(result._min.id).toBe(1)
|
|
303
|
-
expect(result._max.id).toBe(2)
|
|
304
|
-
}),
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
it.effect('groupBy', () =>
|
|
308
|
-
Effect.gen(function* () {
|
|
309
|
-
const todoRepo = yield* PrismaRepository.make(TodoModel, { modelName: 'todo', spanPrefix: 'todo' })
|
|
310
|
-
|
|
311
|
-
yield* todoRepo.createMany({
|
|
312
|
-
data: [
|
|
313
|
-
{ id: 1, title: 'T1', content: 'C', published: true, authorId: 1 },
|
|
314
|
-
{ id: 2, title: 'T2', content: 'C', published: true, authorId: 1 },
|
|
315
|
-
{ id: 3, title: 'T3', content: 'C', published: false, authorId: 2 },
|
|
316
|
-
],
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
const result: any = yield* todoRepo.groupBy({
|
|
320
|
-
by: ['published', 'authorId'],
|
|
321
|
-
_count: {
|
|
322
|
-
id: true,
|
|
323
|
-
},
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
expect(Array.isArray(result)).toBe(true)
|
|
327
|
-
expect(result.length).toBeGreaterThan(0)
|
|
328
|
-
|
|
329
|
-
// Check for the group with published: true, authorId: 1
|
|
330
|
-
const group1 = result.find((g: any) => g.published === true && g.authorId === 1)
|
|
331
|
-
expect(group1).toBeDefined()
|
|
332
|
-
expect(group1._count.id).toBe(2)
|
|
333
|
-
|
|
334
|
-
// Check for the group with published: false, authorId: 2
|
|
335
|
-
const group2 = result.find((g: any) => g.published === false && g.authorId === 2)
|
|
336
|
-
expect(group2).toBeDefined()
|
|
337
|
-
expect(group2._count.id).toBe(1)
|
|
338
|
-
}),
|
|
339
|
-
)
|
|
340
|
-
})
|
package/test/utils.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
|
|
3
|
-
import { PrismaClient } from '@prisma/client'
|
|
4
|
-
|
|
5
|
-
const dbPath = path.join(__dirname, '../prisma/dev.db')
|
|
6
|
-
const adapter = new PrismaBetterSqlite3({
|
|
7
|
-
url: `file:${dbPath}`,
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
export const prisma = new PrismaClient({ adapter })
|
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"files": [],
|
|
4
|
-
"include": [],
|
|
5
|
-
"references": [
|
|
6
|
-
{
|
|
7
|
-
"path": "./tsconfig.lib.json"
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"path": "./tsconfig.spec.json"
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
"compilerOptions": {
|
|
14
|
-
"baseUrl": ".",
|
|
15
|
-
"paths": {
|
|
16
|
-
"@prisma/client": ["node_modules/@prisma/client"],
|
|
17
|
-
"@prisma/*": ["./prisma/generated/*"]
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
package/tsconfig.lib.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"composite": true,
|
|
5
|
-
"baseUrl": ".",
|
|
6
|
-
"rootDir": "src",
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"target": "es2022",
|
|
9
|
-
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
10
|
-
"emitDeclarationOnly": false,
|
|
11
|
-
"moduleResolution": "nodenext",
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"types": ["node"],
|
|
14
|
-
"paths": {
|
|
15
|
-
"@/*": ["./src/*"],
|
|
16
|
-
"@prisma/client": ["node_modules/@prisma/client"],
|
|
17
|
-
"@prisma/effect": ["./prisma/generated/effect/index.ts"],
|
|
18
|
-
"@prisma/effect/*": ["./prisma/generated/effect/*"],
|
|
19
|
-
"@prisma/*": ["./prisma/generated/*"]
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
23
|
-
"references": []
|
|
24
|
-
}
|
package/tsconfig.spec.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "./dist/out-tsc",
|
|
5
|
-
"types": ["vitest/globals", "node"],
|
|
6
|
-
"baseUrl": ".",
|
|
7
|
-
"paths": {
|
|
8
|
-
"@prisma/client": ["node_modules/@prisma/client"],
|
|
9
|
-
"@prisma/effect": ["./prisma/generated/effect/index.ts"],
|
|
10
|
-
"@prisma/effect/*": ["./prisma/generated/effect/*"],
|
|
11
|
-
"@prisma/*": ["./prisma/generated/*"]
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"include": ["test/**/*.ts", "src/**/*.ts", "prisma/generated/**/*.ts"]
|
|
15
|
-
}
|
package/vitest.config.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
3
|
-
import { defineConfig } from 'vitest/config'
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [tsconfigPaths()],
|
|
7
|
-
test: {
|
|
8
|
-
setupFiles: [path.join(__dirname, 'setup-tests.ts')],
|
|
9
|
-
include: ['**/*.test.ts'],
|
|
10
|
-
exclude: ['**/node_modules/**', '**/dist/**', 'inspiration/**'],
|
|
11
|
-
globals: true,
|
|
12
|
-
},
|
|
13
|
-
resolve: {
|
|
14
|
-
alias: {
|
|
15
|
-
'@template/basic/test': path.join(__dirname, 'test'),
|
|
16
|
-
'@template/basic': path.join(__dirname, 'src'),
|
|
17
|
-
'@prisma/effect': path.join(__dirname, 'prisma/generated/effect'),
|
|
18
|
-
},
|
|
19
|
-
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
|
|
20
|
-
},
|
|
21
|
-
esbuild: {
|
|
22
|
-
target: 'node22',
|
|
23
|
-
},
|
|
24
|
-
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|