@opensaas/stack-cli 0.1.0 → 0.1.2

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.
Files changed (49) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +21 -0
  3. package/CLAUDE.md +249 -0
  4. package/LICENSE +21 -0
  5. package/README.md +65 -5
  6. package/dist/commands/generate.d.ts.map +1 -1
  7. package/dist/commands/generate.js +6 -1
  8. package/dist/commands/generate.js.map +1 -1
  9. package/dist/commands/init.d.ts +9 -1
  10. package/dist/commands/init.d.ts.map +1 -1
  11. package/dist/commands/init.js +27 -338
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/generator/context.d.ts.map +1 -1
  14. package/dist/generator/context.js +78 -3
  15. package/dist/generator/context.js.map +1 -1
  16. package/dist/generator/index.d.ts +1 -0
  17. package/dist/generator/index.d.ts.map +1 -1
  18. package/dist/generator/index.js +1 -0
  19. package/dist/generator/index.js.map +1 -1
  20. package/dist/generator/mcp.d.ts +14 -0
  21. package/dist/generator/mcp.d.ts.map +1 -0
  22. package/dist/generator/mcp.js +193 -0
  23. package/dist/generator/mcp.js.map +1 -0
  24. package/dist/generator/types.d.ts.map +1 -1
  25. package/dist/generator/types.js +11 -33
  26. package/dist/generator/types.js.map +1 -1
  27. package/dist/index.js +10 -4
  28. package/dist/index.js.map +1 -1
  29. package/package.json +9 -3
  30. package/src/commands/__snapshots__/generate.test.ts.snap +265 -0
  31. package/src/commands/dev.test.ts +216 -0
  32. package/src/commands/generate.test.ts +272 -0
  33. package/src/commands/generate.ts +7 -0
  34. package/src/commands/init.ts +28 -361
  35. package/src/generator/__snapshots__/context.test.ts.snap +137 -0
  36. package/src/generator/__snapshots__/prisma.test.ts.snap +182 -0
  37. package/src/generator/__snapshots__/types.test.ts.snap +512 -0
  38. package/src/generator/context.test.ts +145 -0
  39. package/src/generator/context.ts +80 -3
  40. package/src/generator/index.ts +1 -0
  41. package/src/generator/mcp.test.ts +393 -0
  42. package/src/generator/mcp.ts +221 -0
  43. package/src/generator/prisma.test.ts +221 -0
  44. package/src/generator/types.test.ts +280 -0
  45. package/src/generator/types.ts +14 -36
  46. package/src/index.ts +8 -4
  47. package/tsconfig.json +1 -1
  48. package/tsconfig.tsbuildinfo +1 -1
  49. package/vitest.config.ts +26 -0
@@ -1,367 +1,34 @@
1
- import * as path from 'path'
2
- import * as fs from 'fs'
1
+ import { spawn } from 'child_process'
3
2
  import chalk from 'chalk'
4
- import ora from 'ora'
5
- import prompts from 'prompts'
6
-
7
- export async function initCommand(projectName: string | undefined) {
8
- console.log(chalk.bold.cyan('\nšŸš€ Create OpenSaas Project\n'))
9
-
10
- // Prompt for project name if not provided
11
- if (!projectName) {
12
- const response = await prompts({
13
- type: 'text',
14
- name: 'name',
15
- message: 'Project name:',
16
- initial: 'my-opensaas-app',
17
- validate: (value) => {
18
- if (!value) return 'Project name is required'
19
- if (!/^[a-z0-9-]+$/.test(value)) {
20
- return 'Project name must contain only lowercase letters, numbers, and hyphens'
21
- }
22
- return true
23
- },
24
- })
25
-
26
- if (!response.name) {
27
- console.log(chalk.yellow('\nāŒ Cancelled'))
28
- process.exit(0)
29
- }
30
-
31
- projectName = response.name
32
- }
33
-
34
- // Type guard to ensure projectName is defined
35
- if (!projectName) {
36
- console.error(chalk.red('\nāŒ Project name is required'))
37
- process.exit(1)
38
- }
39
-
40
- const projectPath = path.join(process.cwd(), projectName)
41
-
42
- // Check if directory already exists
43
- if (fs.existsSync(projectPath)) {
44
- console.error(chalk.red(`\nāŒ Directory "${projectName}" already exists`))
45
- process.exit(1)
46
- }
47
-
48
- const spinner = ora('Creating project structure...').start()
49
-
50
- try {
51
- // Create project directory
52
- fs.mkdirSync(projectPath, { recursive: true })
53
-
54
- // Create basic structure
55
- fs.mkdirSync(path.join(projectPath, 'app'), { recursive: true })
56
- fs.mkdirSync(path.join(projectPath, 'lib'), { recursive: true })
57
- fs.mkdirSync(path.join(projectPath, 'prisma'), { recursive: true })
58
-
59
- spinner.text = 'Writing configuration files...'
60
-
61
- // Create package.json
62
- const packageJson = {
63
- name: projectName,
64
- version: '0.1.0',
65
- private: true,
66
- scripts: {
67
- dev: 'next dev',
68
- build: 'next build',
69
- start: 'next start',
70
- generate: 'opensaas generate',
71
- 'db:push': 'prisma db push',
72
- 'db:studio': 'prisma studio',
73
- },
74
- dependencies: {
75
- '@opensaas/stack-core': '^0.1.0',
76
- '@prisma/client': '^5.7.1',
77
- next: '^14.0.4',
78
- react: '^18.2.0',
79
- 'react-dom': '^18.2.0',
80
- },
81
- devDependencies: {
82
- '@opensaas/stack-cli': '^0.1.0',
83
- '@types/node': '^20.10.0',
84
- '@types/react': '^18.2.45',
85
- '@types/react-dom': '^18.2.18',
86
- prisma: '^5.7.1',
87
- tsx: '^4.7.0',
88
- typescript: '^5.3.3',
89
- },
90
- }
91
-
92
- fs.writeFileSync(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2))
93
-
94
- // Create tsconfig.json
95
- const tsConfig = {
96
- compilerOptions: {
97
- target: 'ES2022',
98
- lib: ['dom', 'dom.iterable', 'esnext'],
99
- allowJs: true,
100
- skipLibCheck: true,
101
- strict: true,
102
- noEmit: true,
103
- esModuleInterop: true,
104
- module: 'esnext',
105
- moduleResolution: 'bundler',
106
- resolveJsonModule: true,
107
- isolatedModules: true,
108
- jsx: 'preserve',
109
- incremental: true,
110
- plugins: [{ name: 'next' }],
111
- paths: {
112
- '@/*': ['./*'],
113
- },
114
- },
115
- include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
116
- exclude: ['node_modules'],
117
- }
118
-
119
- fs.writeFileSync(path.join(projectPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2))
120
-
121
- // Create next.config.js
122
- const nextConfig = `/** @type {import('next').NextConfig} */
123
- const nextConfig = {
124
- experimental: {
125
- serverComponentsExternalPackages: ['@prisma/client', '@opensaas/stack-core'],
126
- },
127
- }
128
-
129
- module.exports = nextConfig
130
- `
131
- fs.writeFileSync(path.join(projectPath, 'next.config.js'), nextConfig)
132
-
133
- // Create .env
134
- const env = `DATABASE_URL="file:./dev.db"
135
- `
136
- fs.writeFileSync(path.join(projectPath, '.env'), env)
137
-
138
- // Create .gitignore
139
- const gitignore = `# Dependencies
140
- node_modules
141
- .pnp
142
- .pnp.js
143
-
144
- # Testing
145
- coverage
146
-
147
- # Next.js
148
- .next
149
- out
150
-
151
- # Production
152
- build
153
- dist
154
-
155
- # Misc
156
- .DS_Store
157
- *.pem
158
-
159
- # Debug
160
- npm-debug.log*
161
- yarn-debug.log*
162
- yarn-error.log*
163
-
164
- # Local env files
165
- .env
166
- .env.local
167
- .env.development.local
168
- .env.test.local
169
- .env.production.local
170
-
171
- # Vercel
172
- .vercel
173
-
174
- # TypeScript
175
- *.tsbuildinfo
176
-
177
- # OpenSaas generated
178
- .opensaas
179
-
180
- # Prisma
181
- prisma/dev.db
182
- prisma/dev.db-journal
183
- `
184
- fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore)
185
-
186
- // Create opensaas.config.ts
187
- const config = `import { config, list } from '@opensaas/stack-core'
188
- import { text, relationship, password } from '@opensaas/stack-core/fields'
189
- import type { AccessControl } from '@opensaas/stack-core'
190
-
191
- // Access control helpers
192
- const isSignedIn: AccessControl = ({ session }) => {
193
- return !!session
194
- }
195
-
196
- export default config({
197
- db: {
198
- provider: 'sqlite',
199
- url: process.env.DATABASE_URL || 'file:./dev.db',
200
- },
201
-
202
- lists: {
203
- User: list({
204
- fields: {
205
- name: text({ validation: { isRequired: true } }),
206
- email: text({
207
- validation: { isRequired: true },
208
- isIndexed: 'unique',
209
- }),
210
- password: password({ validation: { isRequired: true } }),
211
- },
212
- }),
213
- },
214
-
215
- session: {
216
- getSession: async () => {
217
- // TODO: Integrate with your auth system
218
- return null
219
- }
220
- },
221
-
222
- ui: {
223
- basePath: '/admin',
224
- }
225
- })
226
- `
227
- fs.writeFileSync(path.join(projectPath, 'opensaas.config.ts'), config)
228
-
229
- // Create lib/context.ts
230
- const contextFile = `import { PrismaClient } from '@prisma/client'
231
- import { getContext as createContext } from '@opensaas/stack-core'
232
- import config from '../opensaas.config'
233
- import type { Context } from '../.opensaas/types'
234
-
235
- // Singleton Prisma client
236
- const globalForPrisma = globalThis as unknown as {
237
- prisma: PrismaClient | undefined
238
- }
239
-
240
- export const prisma = globalForPrisma.prisma ?? new PrismaClient()
241
-
242
- if (process.env.NODE_ENV !== 'production') {
243
- globalForPrisma.prisma = prisma
244
- }
245
3
 
246
4
  /**
247
- * Get an access-controlled context for the current session
5
+ * Initialize a new OpenSaas Stack project.
6
+ *
7
+ * This command delegates to create-opensaas-app for the actual scaffolding.
8
+ * It's kept here for backwards compatibility with `opensaas init`.
9
+ *
10
+ * @param args - Command line arguments (project name and flags)
248
11
  */
249
- export async function getContext(): Promise<Context> {
250
- const session = config.session ? await config.session.getSession() : null
251
- const context = await createContext<PrismaClient>(config, prisma, session)
252
- return context as Context
253
- }
254
- `
255
- fs.writeFileSync(path.join(projectPath, 'lib', 'context.ts'), contextFile)
256
-
257
- // Create app/page.tsx
258
- const page = `export default function Home() {
259
- return (
260
- <main className="flex min-h-screen flex-col items-center justify-center p-24">
261
- <h1 className="text-4xl font-bold mb-4">Welcome to OpenSaas</h1>
262
- <p className="text-gray-600">Your project is ready to go!</p>
263
-
264
- <div className="mt-8 space-y-2">
265
- <p className="text-sm">Next steps:</p>
266
- <ol className="text-sm text-gray-600 list-decimal list-inside space-y-1">
267
- <li>Run <code className="bg-gray-100 px-2 py-1 rounded">npm run generate</code></li>
268
- <li>Run <code className="bg-gray-100 px-2 py-1 rounded">npm run db:push</code></li>
269
- <li>Edit <code className="bg-gray-100 px-2 py-1 rounded">opensaas.config.ts</code> to define your schema</li>
270
- </ol>
271
- </div>
272
- </main>
273
- )
274
- }
275
- `
276
- fs.writeFileSync(path.join(projectPath, 'app', 'page.tsx'), page)
277
-
278
- // Create app/layout.tsx
279
- const layout = `export const metadata = {
280
- title: '${projectName}',
281
- description: 'Built with OpenSaas',
282
- }
283
-
284
- export default function RootLayout({
285
- children,
286
- }: {
287
- children: React.ReactNode
288
- }) {
289
- return (
290
- <html lang="en">
291
- <body>{children}</body>
292
- </html>
293
- )
294
- }
295
- `
296
- fs.writeFileSync(path.join(projectPath, 'app', 'layout.tsx'), layout)
297
-
298
- // Create README.md
299
- const readme = `# ${projectName}
300
-
301
- Built with [OpenSaas Stack](https://github.com/your-org/opensaas-stack)
302
-
303
- ## Getting Started
304
-
305
- 1. Install dependencies:
306
- \`\`\`bash
307
- npm install
308
- # or
309
- pnpm install
310
- \`\`\`
311
-
312
- 2. Generate Prisma schema and types:
313
- \`\`\`bash
314
- npm run generate
315
- \`\`\`
316
-
317
- 3. Push schema to database:
318
- \`\`\`bash
319
- npm run db:push
320
- \`\`\`
321
-
322
- 4. Run the development server:
323
- \`\`\`bash
324
- npm run dev
325
- \`\`\`
326
-
327
- Open [http://localhost:3000](http://localhost:3000) to see your app.
328
-
329
- ## Project Structure
330
-
331
- - \`opensaas.config.ts\` - Your schema definition with access control
332
- - \`lib/context.ts\` - Database context with access control
333
- - \`app/\` - Next.js app router pages
334
- - \`prisma/\` - Generated Prisma schema
335
- - \`.opensaas/\` - Generated TypeScript types
336
-
337
- ## Learn More
338
-
339
- - [OpenSaas Documentation](https://github.com/your-org/opensaas-stack)
340
- - [Next.js Documentation](https://nextjs.org/docs)
341
- - [Prisma Documentation](https://www.prisma.io/docs)
342
- `
343
- fs.writeFileSync(path.join(projectPath, 'README.md'), readme)
344
-
345
- spinner.succeed(chalk.green('Project created successfully!'))
346
-
347
- console.log(chalk.bold.green(`\n✨ Created ${projectName}\n`))
348
- console.log(chalk.gray('Next steps:\n'))
349
- console.log(chalk.cyan(` cd ${projectName}`))
350
- console.log(chalk.cyan(' npm install'))
351
- console.log(chalk.cyan(' npm run generate'))
352
- console.log(chalk.cyan(' npm run db:push'))
353
- console.log(chalk.cyan(' npm run dev'))
354
- console.log()
355
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
356
- } catch (error: any) {
357
- spinner.fail(chalk.red('Failed to create project'))
358
- console.error(chalk.red('\nāŒ Error:'), error.message)
359
-
360
- // Cleanup on failure
361
- if (fs.existsSync(projectPath)) {
362
- fs.rmSync(projectPath, { recursive: true, force: true })
363
- }
12
+ export async function initCommand(args: string[]) {
13
+ console.log(chalk.dim('Delegating to create-opensaas-app...\n'))
14
+
15
+ // Forward all arguments to create-opensaas-app
16
+ const child = spawn('npx', ['create-opensaas-app@latest', ...args], {
17
+ stdio: 'inherit',
18
+ shell: true,
19
+ })
20
+
21
+ return new Promise<void>((resolve, reject) => {
22
+ child.on('close', (code) => {
23
+ if (code !== 0) {
24
+ reject(new Error(`create-opensaas-app exited with code ${code}`))
25
+ } else {
26
+ resolve()
27
+ }
28
+ })
364
29
 
365
- process.exit(1)
366
- }
30
+ child.on('error', (err) => {
31
+ reject(err)
32
+ })
33
+ })
367
34
  }
@@ -0,0 +1,137 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Context Generator > generateContext > should generate context factory with custom Prisma client constructor 1`] = `
4
+ "/**
5
+ * Auto-generated context factory
6
+ *
7
+ * This module provides a simple API for creating OpenSaas contexts.
8
+ * It abstracts away Prisma client management and configuration.
9
+ *
10
+ * DO NOT EDIT - This file is automatically generated by 'pnpm generate'
11
+ */
12
+
13
+ import { getContext as getOpensaasContext } from '@opensaas/stack-core'
14
+ import type { Session as OpensaasSession } from '@opensaas/stack-core'
15
+ import { PrismaClient } from './prisma-client'
16
+ import type { Context } from './types'
17
+ import config from '../opensaas.config'
18
+
19
+ // Internal Prisma singleton - managed automatically
20
+ const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }
21
+ const prisma = globalForPrisma.prisma ?? config.db.prismaClientConstructor!(PrismaClient)
22
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
23
+
24
+ /**
25
+ * Storage utilities (not configured)
26
+ */
27
+ const storage = {
28
+ uploadFile: async () => {
29
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
30
+ },
31
+ uploadImage: async () => {
32
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
33
+ },
34
+ deleteFile: async () => {
35
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
36
+ },
37
+ deleteImage: async () => {
38
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
39
+ },
40
+ }
41
+
42
+ /**
43
+ * Get OpenSaas context with optional session
44
+ *
45
+ * @param session - Optional session object (structure defined by your application)
46
+ *
47
+ * @example
48
+ * \`\`\`typescript
49
+ * // Anonymous access
50
+ * const context = getContext()
51
+ * const posts = await context.db.post.findMany()
52
+ *
53
+ * // Authenticated access
54
+ * const context = getContext({ userId: 'user-123' })
55
+ * const myPosts = await context.db.post.findMany()
56
+ *
57
+ * // With custom session type
58
+ * type CustomSession = { userId: string; email: string; role: string } | null
59
+ * const context = getContext<CustomSession>({ userId: '123', email: 'user@example.com', role: 'admin' })
60
+ * // context.session is now typed as CustomSession
61
+ * \`\`\`
62
+ */
63
+ export function getContext<TSession extends OpensaasSession = OpensaasSession>(session?: TSession): Context<TSession> {
64
+ return getOpensaasContext(config, prisma, session ?? null, storage) as Context<TSession>
65
+ }
66
+
67
+ export const rawOpensaasContext = getContext()
68
+ "
69
+ `;
70
+
71
+ exports[`Context Generator > generateContext > should generate context factory with default Prisma client 1`] = `
72
+ "/**
73
+ * Auto-generated context factory
74
+ *
75
+ * This module provides a simple API for creating OpenSaas contexts.
76
+ * It abstracts away Prisma client management and configuration.
77
+ *
78
+ * DO NOT EDIT - This file is automatically generated by 'pnpm generate'
79
+ */
80
+
81
+ import { getContext as getOpensaasContext } from '@opensaas/stack-core'
82
+ import type { Session as OpensaasSession } from '@opensaas/stack-core'
83
+ import { PrismaClient } from './prisma-client'
84
+ import type { Context } from './types'
85
+ import config from '../opensaas.config'
86
+
87
+ // Internal Prisma singleton - managed automatically
88
+ const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }
89
+ const prisma = globalForPrisma.prisma ?? new PrismaClient()
90
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
91
+
92
+ /**
93
+ * Storage utilities (not configured)
94
+ */
95
+ const storage = {
96
+ uploadFile: async () => {
97
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
98
+ },
99
+ uploadImage: async () => {
100
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
101
+ },
102
+ deleteFile: async () => {
103
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
104
+ },
105
+ deleteImage: async () => {
106
+ throw new Error('Storage is not configured. Add storage providers to your opensaas.config.ts')
107
+ },
108
+ }
109
+
110
+ /**
111
+ * Get OpenSaas context with optional session
112
+ *
113
+ * @param session - Optional session object (structure defined by your application)
114
+ *
115
+ * @example
116
+ * \`\`\`typescript
117
+ * // Anonymous access
118
+ * const context = getContext()
119
+ * const posts = await context.db.post.findMany()
120
+ *
121
+ * // Authenticated access
122
+ * const context = getContext({ userId: 'user-123' })
123
+ * const myPosts = await context.db.post.findMany()
124
+ *
125
+ * // With custom session type
126
+ * type CustomSession = { userId: string; email: string; role: string } | null
127
+ * const context = getContext<CustomSession>({ userId: '123', email: 'user@example.com', role: 'admin' })
128
+ * // context.session is now typed as CustomSession
129
+ * \`\`\`
130
+ */
131
+ export function getContext<TSession extends OpensaasSession = OpensaasSession>(session?: TSession): Context<TSession> {
132
+ return getOpensaasContext(config, prisma, session ?? null, storage) as Context<TSession>
133
+ }
134
+
135
+ export const rawOpensaasContext = getContext()
136
+ "
137
+ `;
@@ -0,0 +1,182 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate basic schema with datasource and generator 1`] = `
4
+ "generator client {
5
+ provider = "prisma-client-js"
6
+ output = "../.opensaas/prisma-client"
7
+ }
8
+
9
+ datasource db {
10
+ provider = "sqlite"
11
+ url = env("DATABASE_URL")
12
+ }
13
+ "
14
+ `;
15
+
16
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate many-to-one relationship 1`] = `
17
+ "generator client {
18
+ provider = "prisma-client-js"
19
+ output = "../.opensaas/prisma-client"
20
+ }
21
+
22
+ datasource db {
23
+ provider = "sqlite"
24
+ url = env("DATABASE_URL")
25
+ }
26
+
27
+ model User {
28
+ id String @id @default(cuid())
29
+ name String?
30
+ createdAt DateTime @default(now())
31
+ updatedAt DateTime @updatedAt
32
+ }
33
+
34
+ model Post {
35
+ id String @id @default(cuid())
36
+ title String?
37
+ authorId String?
38
+ author User? @relation(fields: [authorId], references: [id])
39
+ createdAt DateTime @default(now())
40
+ updatedAt DateTime @updatedAt
41
+ }
42
+ "
43
+ `;
44
+
45
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with basic fields 1`] = `
46
+ "generator client {
47
+ provider = "prisma-client-js"
48
+ output = "../.opensaas/prisma-client"
49
+ }
50
+
51
+ datasource db {
52
+ provider = "sqlite"
53
+ url = env("DATABASE_URL")
54
+ }
55
+
56
+ model User {
57
+ id String @id @default(cuid())
58
+ name String
59
+ email String
60
+ age Int?
61
+ createdAt DateTime @default(now())
62
+ updatedAt DateTime @updatedAt
63
+ }
64
+ "
65
+ `;
66
+
67
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with checkbox field 1`] = `
68
+ "generator client {
69
+ provider = "prisma-client-js"
70
+ output = "../.opensaas/prisma-client"
71
+ }
72
+
73
+ datasource db {
74
+ provider = "sqlite"
75
+ url = env("DATABASE_URL")
76
+ }
77
+
78
+ model Post {
79
+ id String @id @default(cuid())
80
+ title String?
81
+ isPublished Boolean @default(false)
82
+ createdAt DateTime @default(now())
83
+ updatedAt DateTime @updatedAt
84
+ }
85
+ "
86
+ `;
87
+
88
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate model with timestamp field 1`] = `
89
+ "generator client {
90
+ provider = "prisma-client-js"
91
+ output = "../.opensaas/prisma-client"
92
+ }
93
+
94
+ datasource db {
95
+ provider = "sqlite"
96
+ url = env("DATABASE_URL")
97
+ }
98
+
99
+ model Post {
100
+ id String @id @default(cuid())
101
+ title String?
102
+ publishedAt DateTime?
103
+ createdAt DateTime @default(now())
104
+ updatedAt DateTime @updatedAt
105
+ }
106
+ "
107
+ `;
108
+
109
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate multiple models 1`] = `
110
+ "generator client {
111
+ provider = "prisma-client-js"
112
+ output = "../.opensaas/prisma-client"
113
+ }
114
+
115
+ datasource db {
116
+ provider = "postgresql"
117
+ url = env("DATABASE_URL")
118
+ }
119
+
120
+ model User {
121
+ id String @id @default(cuid())
122
+ name String?
123
+ createdAt DateTime @default(now())
124
+ updatedAt DateTime @updatedAt
125
+ }
126
+
127
+ model Post {
128
+ id String @id @default(cuid())
129
+ title String?
130
+ createdAt DateTime @default(now())
131
+ updatedAt DateTime @updatedAt
132
+ }
133
+
134
+ model Comment {
135
+ id String @id @default(cuid())
136
+ content String?
137
+ createdAt DateTime @default(now())
138
+ updatedAt DateTime @updatedAt
139
+ }
140
+ "
141
+ `;
142
+
143
+ exports[`Prisma Schema Generator > generatePrismaSchema > should generate one-to-many relationship 1`] = `
144
+ "generator client {
145
+ provider = "prisma-client-js"
146
+ output = "../.opensaas/prisma-client"
147
+ }
148
+
149
+ datasource db {
150
+ provider = "sqlite"
151
+ url = env("DATABASE_URL")
152
+ }
153
+
154
+ model User {
155
+ id String @id @default(cuid())
156
+ name String?
157
+ posts Post[]
158
+ createdAt DateTime @default(now())
159
+ updatedAt DateTime @updatedAt
160
+ }
161
+
162
+ model Post {
163
+ id String @id @default(cuid())
164
+ title String?
165
+ createdAt DateTime @default(now())
166
+ updatedAt DateTime @updatedAt
167
+ }
168
+ "
169
+ `;
170
+
171
+ exports[`Prisma Schema Generator > generatePrismaSchema > should use custom opensaasPath for generator output 1`] = `
172
+ "generator client {
173
+ provider = "prisma-client-js"
174
+ output = "../.custom-path/prisma-client"
175
+ }
176
+
177
+ datasource db {
178
+ provider = "sqlite"
179
+ url = env("DATABASE_URL")
180
+ }
181
+ "
182
+ `;