@zenstackhq/testtools 3.3.0-beta.4 → 3.3.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/index.cjs CHANGED
@@ -168,13 +168,26 @@ function replacePlaceholders(schemaText, provider, dbUrl) {
168
168
  return schemaText.replace(/\$DB_URL/g, url).replace(/\$PROVIDER/g, provider);
169
169
  }
170
170
  __name(replacePlaceholders, "replacePlaceholders");
171
- async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema) {
171
+ async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema, extraZModelFiles) {
172
172
  const workDir = createTestProject();
173
173
  const zmodelPath = import_node_path2.default.join(workDir, "schema.zmodel");
174
174
  const noPrelude = schemaText.includes("datasource ");
175
175
  import_node_fs2.default.writeFileSync(zmodelPath, `${noPrelude ? "" : makePrelude(provider, dbUrl)}
176
176
 
177
177
  ${replacePlaceholders(schemaText, provider, dbUrl)}`);
178
+ if (extraZModelFiles) {
179
+ for (const [fileName, content] of Object.entries(extraZModelFiles)) {
180
+ let name = fileName;
181
+ if (!name.endsWith(".zmodel")) {
182
+ name += ".zmodel";
183
+ }
184
+ const filePath = import_node_path2.default.join(workDir, name);
185
+ import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(filePath), {
186
+ recursive: true
187
+ });
188
+ import_node_fs2.default.writeFileSync(filePath, content);
189
+ }
190
+ }
178
191
  const result = await loadDocumentWithPlugins(zmodelPath);
179
192
  if (!result.success) {
180
193
  throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);
@@ -315,7 +328,7 @@ async function createTestClient(schema, options) {
315
328
  const dbUrl = (0, import_ts_pattern2.match)(provider).with("sqlite", () => `file:${dbName}`).with("mysql", () => `${TEST_MYSQL_URL}/${dbName}`).with("postgresql", () => `${TEST_PG_URL}/${dbName}`).exhaustive();
316
329
  let model;
317
330
  if (typeof schema === "string") {
318
- const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0);
331
+ const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0, options?.extraZModelFiles);
319
332
  workDir = generated.workDir;
320
333
  model = generated.model;
321
334
  _schema = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["export * from './client';\nexport * from './project';\nexport * from './schema';\nexport * from './vitest-ext';\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/orm';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/orm/schema';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { glob } from 'glob';\nimport { MysqlDialect, PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { createPool as createMysqlPool } from 'mysql2';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql', 'mysql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql' | 'mysql';\n}\n\nexport const TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;\n\nexport const TEST_MYSQL_CONFIG = {\n host: process.env['TEST_MYSQL_HOST'] ?? 'localhost',\n port: process.env['TEST_MYSQL_PORT'] ? parseInt(process.env['TEST_MYSQL_PORT']) : 3306,\n user: process.env['TEST_MYSQL_USER'] ?? 'root',\n password: process.env['TEST_MYSQL_PASSWORD'] ?? 'mysql',\n timezone: 'Z',\n};\n\nexport const TEST_MYSQL_URL = `mysql://${TEST_MYSQL_CONFIG.user}:${TEST_MYSQL_CONFIG.password}@${TEST_MYSQL_CONFIG.host}:${TEST_MYSQL_CONFIG.port}`;\n\ntype ExtraTestClientOptions = {\n /**\n * Database provider\n */\n provider?: 'sqlite' | 'postgresql' | 'mysql';\n\n /**\n * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.\n */\n schemaFile?: string;\n\n /**\n * Database name. If not provided, a name will be generated based on the test name.\n */\n dbName?: string;\n\n /**\n * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.\n */\n usePrismaPush?: boolean;\n\n /**\n * Extra source files to create and compile.\n */\n extraSourceFiles?: Record<string, string>;\n\n /**\n * Working directory for the test client. If not provided, a temporary directory will be created.\n */\n workDir?: string;\n\n /**\n * Debug mode.\n */\n debug?: boolean;\n\n /**\n * A sqlite database file to be used for the test. Only supported for sqlite provider.\n */\n dbFile?: string;\n\n /**\n * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.\n */\n dataSourceExtensions?: string[];\n\n /**\n * Additional files to be copied to the working directory. The glob pattern is relative to the test file.\n */\n copyFiles?: {\n globPattern: string;\n destination: string;\n }[];\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> &\n ExtraTestClientOptions;\n\nexport async function createTestClient<\n Schema extends SchemaDef,\n Options extends ClientOptions<Schema>,\n CreateOptions = Omit<Options, 'dialect'>,\n>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;\nexport async function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;\nexport async function createTestClient(\n schema: SchemaDef | string,\n options?: CreateTestClientOptions<SchemaDef>,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: SchemaDef;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n const dbName = options?.dbName ?? getTestDbName(provider);\n const dbUrl = match(provider)\n .with('sqlite', () => `file:${dbName}`)\n .with('mysql', () => `${TEST_MYSQL_URL}/${dbName}`)\n .with('postgresql', () => `${TEST_PG_URL}/${dbName}`)\n .exhaustive();\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, undefined);\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n ...generated.schema.provider,\n type: provider,\n },\n } as SchemaDef;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (options?.schemaFile) {\n let schemaContent = fs.readFileSync(options.schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(', ')}]` : ''}\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir!, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n\n const { plugins, ...rest } = options ?? {};\n const _options = {\n ...rest,\n } as ClientOptions<SchemaDef>;\n\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n console.log(`Database name: ${dbName}`);\n _options.log ??= testLogger;\n }\n\n // copy db file to workDir if specified\n if (options?.dbFile) {\n if (provider !== 'sqlite') {\n throw new Error('dbFile option is only supported for sqlite provider');\n }\n fs.copyFileSync(options.dbFile, path.join(workDir, dbName));\n }\n\n // copy additional files if specified\n if (options?.copyFiles) {\n const state = expect.getState();\n const currentTestPath = state.testPath;\n if (!currentTestPath) {\n throw new Error('Unable to determine current test file path');\n }\n for (const { globPattern, destination } of options.copyFiles) {\n const files = glob.sync(globPattern, { cwd: path.dirname(currentTestPath) });\n for (const file of files) {\n const src = path.resolve(path.dirname(currentTestPath), file);\n const dest = path.resolve(workDir, destination, path.basename(file));\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n }\n }\n\n if (!options?.dbFile) {\n if (options?.usePrismaPush) {\n invariant(\n typeof schema === 'string' || options?.schemaFile,\n 'a schema file must be provided when using prisma db push',\n );\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: options.debug ? 'inherit' : 'ignore',\n });\n } else {\n await prepareDatabase(provider, dbName);\n }\n }\n\n // create Kysely dialect\n _options.dialect = createDialect(provider, dbName, workDir);\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush && !options?.dbFile) {\n await client.$pushSchema();\n }\n\n // install plugins\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nfunction createDialect(provider: DataSourceProviderType, dbName: string, workDir: string) {\n return match(provider)\n .with(\n 'postgresql',\n () =>\n new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'mysql',\n () =>\n new MysqlDialect({\n pool: createMysqlPool({\n ...TEST_MYSQL_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'sqlite',\n () =>\n new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n }),\n )\n .exhaustive();\n}\n\nasync function prepareDatabase(provider: string, dbName: string) {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n } else if (provider === 'mysql') {\n invariant(dbName, 'dbName is required');\n const mysqlPool = createMysqlPool(TEST_MYSQL_CONFIG);\n await mysqlPool.promise().query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n await mysqlPool.promise().query(`CREATE DATABASE \\`${dbName}\\``);\n await mysqlPool.promise().end();\n }\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName ?? 'unnamed';\n const testPath = expect.getState().testPath ?? '';\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'orm', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/schema';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: DataSourceProviderType, dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .with('mysql', () => {\n return `\ndatasource db {\n provider = 'mysql'\n url = '${dbUrl ?? 'mysql://root:mysql@localhost:3306/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nfunction replacePlaceholders(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' | 'mysql',\n dbUrl: string | undefined,\n) {\n const url =\n dbUrl ??\n (provider === 'sqlite'\n ? 'file:./test.db'\n : provider === 'mysql'\n ? 'mysql://root:mysql@localhost:3306/db'\n : 'postgres://postgres:postgres@localhost:5432/db');\n return schemaText.replace(/\\$DB_URL/g, url).replace(/\\$PROVIDER/g, provider);\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: DataSourceProviderType = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n withLiteSchema?: boolean,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(\n zmodelPath,\n `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${replacePlaceholders(schemaText, provider, dbUrl)}`,\n );\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir, lite: withLiteSchema });\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n\n let moduleLite: any;\n try {\n moduleLite = await import(path.join(workDir, 'schema-lite.js'));\n } catch {\n // ignore\n }\n return { workDir, schema: module.schema as SchemaDef, schemaLite: moduleLite?.schema as SchemaDef | undefined };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir });\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [require.resolve('@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { ORMError, ORMErrorReason } from '@zenstackhq/orm';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectErrorReason(err: any, errorReason: ORMErrorReason) {\n if (err instanceof ORMError && err.reason === errorReason) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ORMError of reason ${errorReason}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.toLowerCase().includes(m.toLowerCase())) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectErrorReason(err, ORMErrorReason.NOT_FOUND);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["import_common_helpers","import_sdk","import_node_child_process","import_node_crypto","import_node_fs","import_node_path","import_ts_pattern","import_vitest","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","import_node_fs","import_node_path","loadDocumentWithPlugins","filePath","pluginModelFiles","require","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","replacePlaceholders","schemaText","url","replace","generateTsSchema","extraSourceFiles","withLiteSchema","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","outDir","lite","fileName","content","Object","entries","filePath","resolve","endsWith","mkdirSync","dirname","recursive","compileAndLoad","execSync","cwd","stdio","module","moduleLite","schema","schemaLite","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","name","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","TEST_PG_URL","TEST_MYSQL_CONFIG","timezone","TEST_MYSQL_URL","createTestClient","schema","options","workDir","_schema","provider","dbName","getTestDbName","dbUrl","match","with","exhaustive","model","generated","generateTsSchema","extraSourceFiles","undefined","type","createTestProject","schemaFile","schemaContent","fs","readFileSync","replace","dataSourceExtensions","join","writeFileSync","path","invariant","plugins","rest","_options","debug","console","log","testLogger","dbFile","copyFileSync","copyFiles","state","expect","getState","currentTestPath","testPath","globPattern","destination","files","glob","sync","cwd","dirname","file","src","resolve","dest","basename","mkdirSync","recursive","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","execSync","stdio","prepareDatabase","dialect","createDialect","client","ZenStackClient","$pushSchema","plugin","$use","PostgresDialect","pool","Pool","database","MysqlDialect","createMysqlPool","SqliteDialect","SQLite","pgClient","PGClient","connect","query","end","mysqlPool","promise","createPolicyTestClient","PolicyPlugin","e","sql","parameters","testName","currentTestName","digest","createHash","update","toLowerCase","substring","slice","import_orm","import_vitest","isPromise","value","then","catch","expectErrorReason","err","errorReason","ORMError","reason","message","pass","expectErrorMessages","expectedMessages","m","toLowerCase","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","ORMErrorReason","NOT_FOUND","toBeRejectedByPolicy","REJECTED_BY_POLICY","toBeRejectedByValidation","INVALID_INPUT"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["export * from './client';\nexport * from './project';\nexport * from './schema';\nexport * from './vitest-ext';\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/orm';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/orm/schema';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { glob } from 'glob';\nimport { MysqlDialect, PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { createPool as createMysqlPool } from 'mysql2';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql', 'mysql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql' | 'mysql';\n}\n\nexport const TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;\n\nexport const TEST_MYSQL_CONFIG = {\n host: process.env['TEST_MYSQL_HOST'] ?? 'localhost',\n port: process.env['TEST_MYSQL_PORT'] ? parseInt(process.env['TEST_MYSQL_PORT']) : 3306,\n user: process.env['TEST_MYSQL_USER'] ?? 'root',\n password: process.env['TEST_MYSQL_PASSWORD'] ?? 'mysql',\n timezone: 'Z',\n};\n\nexport const TEST_MYSQL_URL = `mysql://${TEST_MYSQL_CONFIG.user}:${TEST_MYSQL_CONFIG.password}@${TEST_MYSQL_CONFIG.host}:${TEST_MYSQL_CONFIG.port}`;\n\ntype ExtraTestClientOptions = {\n /**\n * Database provider\n */\n provider?: 'sqlite' | 'postgresql' | 'mysql';\n\n /**\n * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.\n */\n schemaFile?: string;\n\n /**\n * Database name. If not provided, a name will be generated based on the test name.\n */\n dbName?: string;\n\n /**\n * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.\n */\n usePrismaPush?: boolean;\n\n /**\n * Extra ZModel files to be created in the working directory.\n */\n extraZModelFiles?: Record<string, string>;\n\n /**\n * Extra TypeScript source files to create and compile.\n */\n extraSourceFiles?: Record<string, string>;\n\n /**\n * Working directory for the test client. If not provided, a temporary directory will be created.\n */\n workDir?: string;\n\n /**\n * Debug mode.\n */\n debug?: boolean;\n\n /**\n * A sqlite database file to be used for the test. Only supported for sqlite provider.\n */\n dbFile?: string;\n\n /**\n * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.\n */\n dataSourceExtensions?: string[];\n\n /**\n * Additional files to be copied to the working directory. The glob pattern is relative to the test file.\n */\n copyFiles?: {\n globPattern: string;\n destination: string;\n }[];\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> &\n ExtraTestClientOptions;\n\nexport async function createTestClient<\n Schema extends SchemaDef,\n Options extends ClientOptions<Schema>,\n CreateOptions = Omit<Options, 'dialect'>,\n>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;\nexport async function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;\nexport async function createTestClient(\n schema: SchemaDef | string,\n options?: CreateTestClientOptions<SchemaDef>,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: SchemaDef;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n const dbName = options?.dbName ?? getTestDbName(provider);\n const dbUrl = match(provider)\n .with('sqlite', () => `file:${dbName}`)\n .with('mysql', () => `${TEST_MYSQL_URL}/${dbName}`)\n .with('postgresql', () => `${TEST_PG_URL}/${dbName}`)\n .exhaustive();\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(\n schema,\n provider,\n dbUrl,\n options?.extraSourceFiles,\n undefined,\n options?.extraZModelFiles,\n );\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n ...generated.schema.provider,\n type: provider,\n },\n } as SchemaDef;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (options?.schemaFile) {\n let schemaContent = fs.readFileSync(options.schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(', ')}]` : ''}\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir!, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n\n const { plugins, ...rest } = options ?? {};\n const _options = {\n ...rest,\n } as ClientOptions<SchemaDef>;\n\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n console.log(`Database name: ${dbName}`);\n _options.log ??= testLogger;\n }\n\n // copy db file to workDir if specified\n if (options?.dbFile) {\n if (provider !== 'sqlite') {\n throw new Error('dbFile option is only supported for sqlite provider');\n }\n fs.copyFileSync(options.dbFile, path.join(workDir, dbName));\n }\n\n // copy additional files if specified\n if (options?.copyFiles) {\n const state = expect.getState();\n const currentTestPath = state.testPath;\n if (!currentTestPath) {\n throw new Error('Unable to determine current test file path');\n }\n for (const { globPattern, destination } of options.copyFiles) {\n const files = glob.sync(globPattern, { cwd: path.dirname(currentTestPath) });\n for (const file of files) {\n const src = path.resolve(path.dirname(currentTestPath), file);\n const dest = path.resolve(workDir, destination, path.basename(file));\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n }\n }\n\n if (!options?.dbFile) {\n if (options?.usePrismaPush) {\n invariant(\n typeof schema === 'string' || options?.schemaFile,\n 'a schema file must be provided when using prisma db push',\n );\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: options.debug ? 'inherit' : 'ignore',\n });\n } else {\n await prepareDatabase(provider, dbName);\n }\n }\n\n // create Kysely dialect\n _options.dialect = createDialect(provider, dbName, workDir);\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush && !options?.dbFile) {\n await client.$pushSchema();\n }\n\n // install plugins\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nfunction createDialect(provider: DataSourceProviderType, dbName: string, workDir: string) {\n return match(provider)\n .with(\n 'postgresql',\n () =>\n new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'mysql',\n () =>\n new MysqlDialect({\n pool: createMysqlPool({\n ...TEST_MYSQL_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'sqlite',\n () =>\n new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n }),\n )\n .exhaustive();\n}\n\nasync function prepareDatabase(provider: string, dbName: string) {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n } else if (provider === 'mysql') {\n invariant(dbName, 'dbName is required');\n const mysqlPool = createMysqlPool(TEST_MYSQL_CONFIG);\n await mysqlPool.promise().query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n await mysqlPool.promise().query(`CREATE DATABASE \\`${dbName}\\``);\n await mysqlPool.promise().end();\n }\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName ?? 'unnamed';\n const testPath = expect.getState().testPath ?? '';\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'orm', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/schema';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: DataSourceProviderType, dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .with('mysql', () => {\n return `\ndatasource db {\n provider = 'mysql'\n url = '${dbUrl ?? 'mysql://root:mysql@localhost:3306/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nfunction replacePlaceholders(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' | 'mysql',\n dbUrl: string | undefined,\n) {\n const url =\n dbUrl ??\n (provider === 'sqlite'\n ? 'file:./test.db'\n : provider === 'mysql'\n ? 'mysql://root:mysql@localhost:3306/db'\n : 'postgres://postgres:postgres@localhost:5432/db');\n return schemaText.replace(/\\$DB_URL/g, url).replace(/\\$PROVIDER/g, provider);\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: DataSourceProviderType = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n withLiteSchema?: boolean,\n extraZModelFiles?: Record<string, string>,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(\n zmodelPath,\n `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${replacePlaceholders(schemaText, provider, dbUrl)}`,\n );\n\n // write extra ZModel files before loading the schema\n if (extraZModelFiles) {\n for (const [fileName, content] of Object.entries(extraZModelFiles)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(workDir, name);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir, lite: withLiteSchema });\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n\n let moduleLite: any;\n try {\n moduleLite = await import(path.join(workDir, 'schema-lite.js'));\n } catch {\n // ignore\n }\n return { workDir, schema: module.schema as SchemaDef, schemaLite: moduleLite?.schema as SchemaDef | undefined };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir });\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [require.resolve('@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { ORMError, ORMErrorReason } from '@zenstackhq/orm';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectErrorReason(err: any, errorReason: ORMErrorReason) {\n if (err instanceof ORMError && err.reason === errorReason) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ORMError of reason ${errorReason}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.toLowerCase().includes(m.toLowerCase())) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectErrorReason(err, ORMErrorReason.NOT_FOUND);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["import_common_helpers","import_sdk","import_node_child_process","import_node_crypto","import_node_fs","import_node_path","import_ts_pattern","import_vitest","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","import_node_fs","import_node_path","loadDocumentWithPlugins","filePath","pluginModelFiles","require","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","replacePlaceholders","schemaText","url","replace","generateTsSchema","extraSourceFiles","withLiteSchema","extraZModelFiles","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","fileName","content","Object","entries","name","endsWith","filePath","mkdirSync","dirname","recursive","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","outDir","lite","resolve","compileAndLoad","execSync","cwd","stdio","module","moduleLite","schema","schemaLite","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","TEST_PG_URL","TEST_MYSQL_CONFIG","timezone","TEST_MYSQL_URL","createTestClient","schema","options","workDir","_schema","provider","dbName","getTestDbName","dbUrl","match","with","exhaustive","model","generated","generateTsSchema","extraSourceFiles","undefined","extraZModelFiles","type","createTestProject","schemaFile","schemaContent","fs","readFileSync","replace","dataSourceExtensions","join","writeFileSync","path","invariant","plugins","rest","_options","debug","console","log","testLogger","dbFile","copyFileSync","copyFiles","state","expect","getState","currentTestPath","testPath","globPattern","destination","files","glob","sync","cwd","dirname","file","src","resolve","dest","basename","mkdirSync","recursive","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","execSync","stdio","prepareDatabase","dialect","createDialect","client","ZenStackClient","$pushSchema","plugin","$use","PostgresDialect","pool","Pool","database","MysqlDialect","createMysqlPool","SqliteDialect","SQLite","pgClient","PGClient","connect","query","end","mysqlPool","promise","createPolicyTestClient","PolicyPlugin","e","sql","parameters","testName","currentTestName","digest","createHash","update","toLowerCase","substring","slice","import_orm","import_vitest","isPromise","value","then","catch","expectErrorReason","err","errorReason","ORMError","reason","message","pass","expectErrorMessages","expectedMessages","m","toLowerCase","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","ORMErrorReason","NOT_FOUND","toBeRejectedByPolicy","REJECTED_BY_POLICY","toBeRejectedByValidation","INVALID_INPUT"]}
package/dist/index.d.cts CHANGED
@@ -38,7 +38,11 @@ type ExtraTestClientOptions = {
38
38
  */
39
39
  usePrismaPush?: boolean;
40
40
  /**
41
- * Extra source files to create and compile.
41
+ * Extra ZModel files to be created in the working directory.
42
+ */
43
+ extraZModelFiles?: Record<string, string>;
44
+ /**
45
+ * Extra TypeScript source files to create and compile.
42
46
  */
43
47
  extraSourceFiles?: Record<string, string>;
44
48
  /**
@@ -74,7 +78,7 @@ declare function testLogger(e: LogEvent): void;
74
78
 
75
79
  declare function createTestProject(zmodelContent?: string): string;
76
80
 
77
- declare function generateTsSchema(schemaText: string, provider?: DataSourceProviderType, dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean): Promise<{
81
+ declare function generateTsSchema(schemaText: string, provider?: DataSourceProviderType, dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean, extraZModelFiles?: Record<string, string>): Promise<{
78
82
  model: _zenstackhq_language_ast.Model;
79
83
  workDir: string;
80
84
  schema: SchemaDef$1;
package/dist/index.d.ts CHANGED
@@ -38,7 +38,11 @@ type ExtraTestClientOptions = {
38
38
  */
39
39
  usePrismaPush?: boolean;
40
40
  /**
41
- * Extra source files to create and compile.
41
+ * Extra ZModel files to be created in the working directory.
42
+ */
43
+ extraZModelFiles?: Record<string, string>;
44
+ /**
45
+ * Extra TypeScript source files to create and compile.
42
46
  */
43
47
  extraSourceFiles?: Record<string, string>;
44
48
  /**
@@ -74,7 +78,7 @@ declare function testLogger(e: LogEvent): void;
74
78
 
75
79
  declare function createTestProject(zmodelContent?: string): string;
76
80
 
77
- declare function generateTsSchema(schemaText: string, provider?: DataSourceProviderType, dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean): Promise<{
81
+ declare function generateTsSchema(schemaText: string, provider?: DataSourceProviderType, dbUrl?: string, extraSourceFiles?: Record<string, string>, withLiteSchema?: boolean, extraZModelFiles?: Record<string, string>): Promise<{
78
82
  model: _zenstackhq_language_ast.Model;
79
83
  workDir: string;
80
84
  schema: SchemaDef$1;
package/dist/index.js CHANGED
@@ -127,13 +127,26 @@ function replacePlaceholders(schemaText, provider, dbUrl) {
127
127
  return schemaText.replace(/\$DB_URL/g, url).replace(/\$PROVIDER/g, provider);
128
128
  }
129
129
  __name(replacePlaceholders, "replacePlaceholders");
130
- async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema) {
130
+ async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema, extraZModelFiles) {
131
131
  const workDir = createTestProject();
132
132
  const zmodelPath = path2.join(workDir, "schema.zmodel");
133
133
  const noPrelude = schemaText.includes("datasource ");
134
134
  fs2.writeFileSync(zmodelPath, `${noPrelude ? "" : makePrelude(provider, dbUrl)}
135
135
 
136
136
  ${replacePlaceholders(schemaText, provider, dbUrl)}`);
137
+ if (extraZModelFiles) {
138
+ for (const [fileName, content] of Object.entries(extraZModelFiles)) {
139
+ let name = fileName;
140
+ if (!name.endsWith(".zmodel")) {
141
+ name += ".zmodel";
142
+ }
143
+ const filePath = path2.join(workDir, name);
144
+ fs2.mkdirSync(path2.dirname(filePath), {
145
+ recursive: true
146
+ });
147
+ fs2.writeFileSync(filePath, content);
148
+ }
149
+ }
137
150
  const result = await loadDocumentWithPlugins(zmodelPath);
138
151
  if (!result.success) {
139
152
  throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);
@@ -274,7 +287,7 @@ async function createTestClient(schema, options) {
274
287
  const dbUrl = match2(provider).with("sqlite", () => `file:${dbName}`).with("mysql", () => `${TEST_MYSQL_URL}/${dbName}`).with("postgresql", () => `${TEST_PG_URL}/${dbName}`).exhaustive();
275
288
  let model;
276
289
  if (typeof schema === "string") {
277
- const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0);
290
+ const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0, options?.extraZModelFiles);
278
291
  workDir = generated.workDir;
279
292
  model = generated.model;
280
293
  _schema = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/orm';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/orm/schema';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { glob } from 'glob';\nimport { MysqlDialect, PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { createPool as createMysqlPool } from 'mysql2';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql', 'mysql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql' | 'mysql';\n}\n\nexport const TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;\n\nexport const TEST_MYSQL_CONFIG = {\n host: process.env['TEST_MYSQL_HOST'] ?? 'localhost',\n port: process.env['TEST_MYSQL_PORT'] ? parseInt(process.env['TEST_MYSQL_PORT']) : 3306,\n user: process.env['TEST_MYSQL_USER'] ?? 'root',\n password: process.env['TEST_MYSQL_PASSWORD'] ?? 'mysql',\n timezone: 'Z',\n};\n\nexport const TEST_MYSQL_URL = `mysql://${TEST_MYSQL_CONFIG.user}:${TEST_MYSQL_CONFIG.password}@${TEST_MYSQL_CONFIG.host}:${TEST_MYSQL_CONFIG.port}`;\n\ntype ExtraTestClientOptions = {\n /**\n * Database provider\n */\n provider?: 'sqlite' | 'postgresql' | 'mysql';\n\n /**\n * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.\n */\n schemaFile?: string;\n\n /**\n * Database name. If not provided, a name will be generated based on the test name.\n */\n dbName?: string;\n\n /**\n * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.\n */\n usePrismaPush?: boolean;\n\n /**\n * Extra source files to create and compile.\n */\n extraSourceFiles?: Record<string, string>;\n\n /**\n * Working directory for the test client. If not provided, a temporary directory will be created.\n */\n workDir?: string;\n\n /**\n * Debug mode.\n */\n debug?: boolean;\n\n /**\n * A sqlite database file to be used for the test. Only supported for sqlite provider.\n */\n dbFile?: string;\n\n /**\n * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.\n */\n dataSourceExtensions?: string[];\n\n /**\n * Additional files to be copied to the working directory. The glob pattern is relative to the test file.\n */\n copyFiles?: {\n globPattern: string;\n destination: string;\n }[];\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> &\n ExtraTestClientOptions;\n\nexport async function createTestClient<\n Schema extends SchemaDef,\n Options extends ClientOptions<Schema>,\n CreateOptions = Omit<Options, 'dialect'>,\n>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;\nexport async function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;\nexport async function createTestClient(\n schema: SchemaDef | string,\n options?: CreateTestClientOptions<SchemaDef>,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: SchemaDef;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n const dbName = options?.dbName ?? getTestDbName(provider);\n const dbUrl = match(provider)\n .with('sqlite', () => `file:${dbName}`)\n .with('mysql', () => `${TEST_MYSQL_URL}/${dbName}`)\n .with('postgresql', () => `${TEST_PG_URL}/${dbName}`)\n .exhaustive();\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, undefined);\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n ...generated.schema.provider,\n type: provider,\n },\n } as SchemaDef;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (options?.schemaFile) {\n let schemaContent = fs.readFileSync(options.schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(', ')}]` : ''}\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir!, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n\n const { plugins, ...rest } = options ?? {};\n const _options = {\n ...rest,\n } as ClientOptions<SchemaDef>;\n\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n console.log(`Database name: ${dbName}`);\n _options.log ??= testLogger;\n }\n\n // copy db file to workDir if specified\n if (options?.dbFile) {\n if (provider !== 'sqlite') {\n throw new Error('dbFile option is only supported for sqlite provider');\n }\n fs.copyFileSync(options.dbFile, path.join(workDir, dbName));\n }\n\n // copy additional files if specified\n if (options?.copyFiles) {\n const state = expect.getState();\n const currentTestPath = state.testPath;\n if (!currentTestPath) {\n throw new Error('Unable to determine current test file path');\n }\n for (const { globPattern, destination } of options.copyFiles) {\n const files = glob.sync(globPattern, { cwd: path.dirname(currentTestPath) });\n for (const file of files) {\n const src = path.resolve(path.dirname(currentTestPath), file);\n const dest = path.resolve(workDir, destination, path.basename(file));\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n }\n }\n\n if (!options?.dbFile) {\n if (options?.usePrismaPush) {\n invariant(\n typeof schema === 'string' || options?.schemaFile,\n 'a schema file must be provided when using prisma db push',\n );\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: options.debug ? 'inherit' : 'ignore',\n });\n } else {\n await prepareDatabase(provider, dbName);\n }\n }\n\n // create Kysely dialect\n _options.dialect = createDialect(provider, dbName, workDir);\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush && !options?.dbFile) {\n await client.$pushSchema();\n }\n\n // install plugins\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nfunction createDialect(provider: DataSourceProviderType, dbName: string, workDir: string) {\n return match(provider)\n .with(\n 'postgresql',\n () =>\n new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'mysql',\n () =>\n new MysqlDialect({\n pool: createMysqlPool({\n ...TEST_MYSQL_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'sqlite',\n () =>\n new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n }),\n )\n .exhaustive();\n}\n\nasync function prepareDatabase(provider: string, dbName: string) {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n } else if (provider === 'mysql') {\n invariant(dbName, 'dbName is required');\n const mysqlPool = createMysqlPool(TEST_MYSQL_CONFIG);\n await mysqlPool.promise().query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n await mysqlPool.promise().query(`CREATE DATABASE \\`${dbName}\\``);\n await mysqlPool.promise().end();\n }\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName ?? 'unnamed';\n const testPath = expect.getState().testPath ?? '';\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'orm', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/schema';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: DataSourceProviderType, dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .with('mysql', () => {\n return `\ndatasource db {\n provider = 'mysql'\n url = '${dbUrl ?? 'mysql://root:mysql@localhost:3306/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nfunction replacePlaceholders(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' | 'mysql',\n dbUrl: string | undefined,\n) {\n const url =\n dbUrl ??\n (provider === 'sqlite'\n ? 'file:./test.db'\n : provider === 'mysql'\n ? 'mysql://root:mysql@localhost:3306/db'\n : 'postgres://postgres:postgres@localhost:5432/db');\n return schemaText.replace(/\\$DB_URL/g, url).replace(/\\$PROVIDER/g, provider);\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: DataSourceProviderType = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n withLiteSchema?: boolean,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(\n zmodelPath,\n `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${replacePlaceholders(schemaText, provider, dbUrl)}`,\n );\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir, lite: withLiteSchema });\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n\n let moduleLite: any;\n try {\n moduleLite = await import(path.join(workDir, 'schema-lite.js'));\n } catch {\n // ignore\n }\n return { workDir, schema: module.schema as SchemaDef, schemaLite: moduleLite?.schema as SchemaDef | undefined };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir });\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [require.resolve('@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { ORMError, ORMErrorReason } from '@zenstackhq/orm';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectErrorReason(err: any, errorReason: ORMErrorReason) {\n if (err instanceof ORMError && err.reason === errorReason) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ORMError of reason ${errorReason}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.toLowerCase().includes(m.toLowerCase())) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectErrorReason(err, ORMErrorReason.NOT_FOUND);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["invariant","ZenStackClient","PolicyPlugin","PrismaSchemaGenerator","SQLite","glob","MysqlDialect","PostgresDialect","SqliteDialect","createPool","createMysqlPool","execSync","createHash","fs","path","Client","PGClient","Pool","match","expect","fs","path","tmp","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","invariant","TsSchemaGenerator","execSync","crypto","fs","os","path","match","expect","loadDocument","loadDocumentWithPlugins","filePath","pluginModelFiles","require","resolve","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","replacePlaceholders","schemaText","url","replace","generateTsSchema","extraSourceFiles","withLiteSchema","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","outDir","lite","fileName","content","Object","entries","filePath","resolve","endsWith","mkdirSync","dirname","recursive","compileAndLoad","execSync","cwd","stdio","module","moduleLite","schema","schemaLite","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","name","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","TEST_PG_URL","TEST_MYSQL_CONFIG","timezone","TEST_MYSQL_URL","createTestClient","schema","options","workDir","_schema","provider","dbName","getTestDbName","dbUrl","match","with","exhaustive","model","generated","generateTsSchema","extraSourceFiles","undefined","type","createTestProject","schemaFile","schemaContent","fs","readFileSync","replace","dataSourceExtensions","join","writeFileSync","path","invariant","plugins","rest","_options","debug","console","log","testLogger","dbFile","copyFileSync","copyFiles","state","expect","getState","currentTestPath","testPath","globPattern","destination","files","glob","sync","cwd","dirname","file","src","resolve","dest","basename","mkdirSync","recursive","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","execSync","stdio","prepareDatabase","dialect","createDialect","client","ZenStackClient","$pushSchema","plugin","$use","PostgresDialect","pool","Pool","database","MysqlDialect","createMysqlPool","SqliteDialect","SQLite","pgClient","PGClient","connect","query","end","mysqlPool","promise","createPolicyTestClient","PolicyPlugin","e","sql","parameters","testName","currentTestName","digest","createHash","update","toLowerCase","substring","slice","ORMError","ORMErrorReason","expect","isPromise","value","then","catch","expectErrorReason","err","errorReason","ORMError","reason","message","pass","expectErrorMessages","expectedMessages","m","toLowerCase","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","ORMErrorReason","NOT_FOUND","toBeRejectedByPolicy","REJECTED_BY_POLICY","toBeRejectedByValidation","INVALID_INPUT"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/orm';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/orm/schema';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { glob } from 'glob';\nimport { MysqlDialect, PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { createPool as createMysqlPool } from 'mysql2';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql', 'mysql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql' | 'mysql';\n}\n\nexport const TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;\n\nexport const TEST_MYSQL_CONFIG = {\n host: process.env['TEST_MYSQL_HOST'] ?? 'localhost',\n port: process.env['TEST_MYSQL_PORT'] ? parseInt(process.env['TEST_MYSQL_PORT']) : 3306,\n user: process.env['TEST_MYSQL_USER'] ?? 'root',\n password: process.env['TEST_MYSQL_PASSWORD'] ?? 'mysql',\n timezone: 'Z',\n};\n\nexport const TEST_MYSQL_URL = `mysql://${TEST_MYSQL_CONFIG.user}:${TEST_MYSQL_CONFIG.password}@${TEST_MYSQL_CONFIG.host}:${TEST_MYSQL_CONFIG.port}`;\n\ntype ExtraTestClientOptions = {\n /**\n * Database provider\n */\n provider?: 'sqlite' | 'postgresql' | 'mysql';\n\n /**\n * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.\n */\n schemaFile?: string;\n\n /**\n * Database name. If not provided, a name will be generated based on the test name.\n */\n dbName?: string;\n\n /**\n * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.\n */\n usePrismaPush?: boolean;\n\n /**\n * Extra ZModel files to be created in the working directory.\n */\n extraZModelFiles?: Record<string, string>;\n\n /**\n * Extra TypeScript source files to create and compile.\n */\n extraSourceFiles?: Record<string, string>;\n\n /**\n * Working directory for the test client. If not provided, a temporary directory will be created.\n */\n workDir?: string;\n\n /**\n * Debug mode.\n */\n debug?: boolean;\n\n /**\n * A sqlite database file to be used for the test. Only supported for sqlite provider.\n */\n dbFile?: string;\n\n /**\n * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.\n */\n dataSourceExtensions?: string[];\n\n /**\n * Additional files to be copied to the working directory. The glob pattern is relative to the test file.\n */\n copyFiles?: {\n globPattern: string;\n destination: string;\n }[];\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> &\n ExtraTestClientOptions;\n\nexport async function createTestClient<\n Schema extends SchemaDef,\n Options extends ClientOptions<Schema>,\n CreateOptions = Omit<Options, 'dialect'>,\n>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;\nexport async function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;\nexport async function createTestClient(\n schema: SchemaDef | string,\n options?: CreateTestClientOptions<SchemaDef>,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: SchemaDef;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n const dbName = options?.dbName ?? getTestDbName(provider);\n const dbUrl = match(provider)\n .with('sqlite', () => `file:${dbName}`)\n .with('mysql', () => `${TEST_MYSQL_URL}/${dbName}`)\n .with('postgresql', () => `${TEST_PG_URL}/${dbName}`)\n .exhaustive();\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(\n schema,\n provider,\n dbUrl,\n options?.extraSourceFiles,\n undefined,\n options?.extraZModelFiles,\n );\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n ...generated.schema.provider,\n type: provider,\n },\n } as SchemaDef;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (options?.schemaFile) {\n let schemaContent = fs.readFileSync(options.schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(', ')}]` : ''}\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir!, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n\n const { plugins, ...rest } = options ?? {};\n const _options = {\n ...rest,\n } as ClientOptions<SchemaDef>;\n\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n console.log(`Database name: ${dbName}`);\n _options.log ??= testLogger;\n }\n\n // copy db file to workDir if specified\n if (options?.dbFile) {\n if (provider !== 'sqlite') {\n throw new Error('dbFile option is only supported for sqlite provider');\n }\n fs.copyFileSync(options.dbFile, path.join(workDir, dbName));\n }\n\n // copy additional files if specified\n if (options?.copyFiles) {\n const state = expect.getState();\n const currentTestPath = state.testPath;\n if (!currentTestPath) {\n throw new Error('Unable to determine current test file path');\n }\n for (const { globPattern, destination } of options.copyFiles) {\n const files = glob.sync(globPattern, { cwd: path.dirname(currentTestPath) });\n for (const file of files) {\n const src = path.resolve(path.dirname(currentTestPath), file);\n const dest = path.resolve(workDir, destination, path.basename(file));\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n }\n }\n\n if (!options?.dbFile) {\n if (options?.usePrismaPush) {\n invariant(\n typeof schema === 'string' || options?.schemaFile,\n 'a schema file must be provided when using prisma db push',\n );\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: options.debug ? 'inherit' : 'ignore',\n });\n } else {\n await prepareDatabase(provider, dbName);\n }\n }\n\n // create Kysely dialect\n _options.dialect = createDialect(provider, dbName, workDir);\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush && !options?.dbFile) {\n await client.$pushSchema();\n }\n\n // install plugins\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nfunction createDialect(provider: DataSourceProviderType, dbName: string, workDir: string) {\n return match(provider)\n .with(\n 'postgresql',\n () =>\n new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'mysql',\n () =>\n new MysqlDialect({\n pool: createMysqlPool({\n ...TEST_MYSQL_CONFIG,\n database: dbName,\n }),\n }),\n )\n .with(\n 'sqlite',\n () =>\n new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n }),\n )\n .exhaustive();\n}\n\nasync function prepareDatabase(provider: string, dbName: string) {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n } else if (provider === 'mysql') {\n invariant(dbName, 'dbName is required');\n const mysqlPool = createMysqlPool(TEST_MYSQL_CONFIG);\n await mysqlPool.promise().query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n await mysqlPool.promise().query(`CREATE DATABASE \\`${dbName}\\``);\n await mysqlPool.promise().end();\n }\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName ?? 'unnamed';\n const testPath = expect.getState().testPath ?? '';\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'orm', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { DataSourceProviderType, SchemaDef } from '@zenstackhq/schema';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: DataSourceProviderType, dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .with('mysql', () => {\n return `\ndatasource db {\n provider = 'mysql'\n url = '${dbUrl ?? 'mysql://root:mysql@localhost:3306/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nfunction replacePlaceholders(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' | 'mysql',\n dbUrl: string | undefined,\n) {\n const url =\n dbUrl ??\n (provider === 'sqlite'\n ? 'file:./test.db'\n : provider === 'mysql'\n ? 'mysql://root:mysql@localhost:3306/db'\n : 'postgres://postgres:postgres@localhost:5432/db');\n return schemaText.replace(/\\$DB_URL/g, url).replace(/\\$PROVIDER/g, provider);\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: DataSourceProviderType = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n withLiteSchema?: boolean,\n extraZModelFiles?: Record<string, string>,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(\n zmodelPath,\n `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${replacePlaceholders(schemaText, provider, dbUrl)}`,\n );\n\n // write extra ZModel files before loading the schema\n if (extraZModelFiles) {\n for (const [fileName, content] of Object.entries(extraZModelFiles)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(workDir, name);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir, lite: withLiteSchema });\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n\n let moduleLite: any;\n try {\n moduleLite = await import(path.join(workDir, 'schema-lite.js'));\n } catch {\n // ignore\n }\n return { workDir, schema: module.schema as SchemaDef, schemaLite: moduleLite?.schema as SchemaDef | undefined };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir });\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [require.resolve('@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { ORMError, ORMErrorReason } from '@zenstackhq/orm';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectErrorReason(err: any, errorReason: ORMErrorReason) {\n if (err instanceof ORMError && err.reason === errorReason) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ORMError of reason ${errorReason}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.toLowerCase().includes(m.toLowerCase())) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectErrorReason(err, ORMErrorReason.NOT_FOUND);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["invariant","ZenStackClient","PolicyPlugin","PrismaSchemaGenerator","SQLite","glob","MysqlDialect","PostgresDialect","SqliteDialect","createPool","createMysqlPool","execSync","createHash","fs","path","Client","PGClient","Pool","match","expect","fs","path","tmp","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","invariant","TsSchemaGenerator","execSync","crypto","fs","os","path","match","expect","loadDocument","loadDocumentWithPlugins","filePath","pluginModelFiles","require","resolve","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","replacePlaceholders","schemaText","url","replace","generateTsSchema","extraSourceFiles","withLiteSchema","extraZModelFiles","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","fileName","content","Object","entries","name","endsWith","filePath","mkdirSync","dirname","recursive","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","outDir","lite","resolve","compileAndLoad","execSync","cwd","stdio","module","moduleLite","schema","schemaLite","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","TEST_PG_URL","TEST_MYSQL_CONFIG","timezone","TEST_MYSQL_URL","createTestClient","schema","options","workDir","_schema","provider","dbName","getTestDbName","dbUrl","match","with","exhaustive","model","generated","generateTsSchema","extraSourceFiles","undefined","extraZModelFiles","type","createTestProject","schemaFile","schemaContent","fs","readFileSync","replace","dataSourceExtensions","join","writeFileSync","path","invariant","plugins","rest","_options","debug","console","log","testLogger","dbFile","copyFileSync","copyFiles","state","expect","getState","currentTestPath","testPath","globPattern","destination","files","glob","sync","cwd","dirname","file","src","resolve","dest","basename","mkdirSync","recursive","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","execSync","stdio","prepareDatabase","dialect","createDialect","client","ZenStackClient","$pushSchema","plugin","$use","PostgresDialect","pool","Pool","database","MysqlDialect","createMysqlPool","SqliteDialect","SQLite","pgClient","PGClient","connect","query","end","mysqlPool","promise","createPolicyTestClient","PolicyPlugin","e","sql","parameters","testName","currentTestName","digest","createHash","update","toLowerCase","substring","slice","ORMError","ORMErrorReason","expect","isPromise","value","then","catch","expectErrorReason","err","errorReason","ORMError","reason","message","pass","expectErrorMessages","expectedMessages","m","toLowerCase","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","ORMErrorReason","NOT_FOUND","toBeRejectedByPolicy","REJECTED_BY_POLICY","toBeRejectedByValidation","INVALID_INPUT"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenstackhq/testtools",
3
- "version": "3.3.0-beta.4",
3
+ "version": "3.3.0",
4
4
  "description": "ZenStack Test Tools",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -31,12 +31,12 @@
31
31
  "prisma": "^6.19.0",
32
32
  "tmp": "^0.2.3",
33
33
  "ts-pattern": "^5.7.1",
34
- "@zenstackhq/common-helpers": "3.3.0-beta.4",
35
- "@zenstackhq/sdk": "3.3.0-beta.4",
36
- "@zenstackhq/orm": "3.3.0-beta.4",
37
- "@zenstackhq/schema": "3.3.0-beta.4",
38
- "@zenstackhq/language": "3.3.0-beta.4",
39
- "@zenstackhq/plugin-policy": "3.3.0-beta.4"
34
+ "@zenstackhq/common-helpers": "3.3.0",
35
+ "@zenstackhq/language": "3.3.0",
36
+ "@zenstackhq/sdk": "3.3.0",
37
+ "@zenstackhq/schema": "3.3.0",
38
+ "@zenstackhq/plugin-policy": "3.3.0",
39
+ "@zenstackhq/orm": "3.3.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "better-sqlite3": "^12.5.0",
@@ -48,8 +48,8 @@
48
48
  "@types/tmp": "^0.2.6",
49
49
  "@types/pg": "^8.11.11",
50
50
  "typescript": "^5.9.3",
51
- "@zenstackhq/typescript-config": "3.3.0-beta.4",
52
- "@zenstackhq/eslint-config": "3.3.0-beta.4"
51
+ "@zenstackhq/eslint-config": "3.3.0",
52
+ "@zenstackhq/typescript-config": "3.3.0"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsc --noEmit && tsup-node",
package/dist/index.mjs DELETED
@@ -1,504 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
-
4
- // src/client.ts
5
- import { invariant as invariant2 } from "@zenstackhq/common-helpers";
6
- import { PolicyPlugin } from "@zenstackhq/plugin-policy";
7
- import { ZenStackClient } from "@zenstackhq/runtime";
8
- import { PrismaSchemaGenerator } from "@zenstackhq/sdk";
9
- import SQLite from "better-sqlite3";
10
- import { PostgresDialect, SqliteDialect } from "kysely";
11
- import { execSync as execSync2 } from "child_process";
12
- import { createHash } from "crypto";
13
- import fs3 from "fs";
14
- import path4 from "path";
15
- import { Client as PGClient, Pool } from "pg";
16
- import { expect as expect2 } from "vitest";
17
-
18
- // src/project.ts
19
- import fs from "fs";
20
- import path from "path";
21
- import tmp from "tmp";
22
- function createTestProject(zmodelContent) {
23
- const { name: workDir } = tmp.dirSync({
24
- unsafeCleanup: true
25
- });
26
- fs.mkdirSync(path.join(workDir, "node_modules"));
27
- const nodeModules = fs.readdirSync(path.join(__dirname, "../node_modules"));
28
- for (const entry of nodeModules) {
29
- if (entry.startsWith("@zenstackhq")) {
30
- continue;
31
- }
32
- fs.symlinkSync(path.join(__dirname, "../node_modules", entry), path.join(workDir, "node_modules", entry), "dir");
33
- }
34
- const zenstackPackages = [
35
- "language",
36
- "sdk",
37
- "runtime",
38
- "cli"
39
- ];
40
- fs.mkdirSync(path.join(workDir, "node_modules/@zenstackhq"));
41
- for (const pkg of zenstackPackages) {
42
- fs.symlinkSync(path.join(__dirname, `../../${pkg}`), path.join(workDir, `node_modules/@zenstackhq/${pkg}`), "dir");
43
- }
44
- fs.writeFileSync(path.join(workDir, "package.json"), JSON.stringify({
45
- name: "test",
46
- version: "1.0.0",
47
- type: "module"
48
- }, null, 4));
49
- fs.writeFileSync(path.join(workDir, "tsconfig.json"), JSON.stringify({
50
- compilerOptions: {
51
- module: "ESNext",
52
- target: "ESNext",
53
- moduleResolution: "Bundler",
54
- esModuleInterop: true,
55
- skipLibCheck: true,
56
- strict: true
57
- },
58
- include: [
59
- "**/*.ts"
60
- ]
61
- }, null, 4));
62
- if (zmodelContent) {
63
- fs.writeFileSync(path.join(workDir, "schema.zmodel"), zmodelContent);
64
- }
65
- return workDir;
66
- }
67
- __name(createTestProject, "createTestProject");
68
-
69
- // src/schema.ts
70
- import { invariant } from "@zenstackhq/common-helpers";
71
- import { TsSchemaGenerator } from "@zenstackhq/sdk";
72
- import { execSync } from "child_process";
73
- import crypto from "crypto";
74
- import fs2 from "fs";
75
- import os from "os";
76
- import path3 from "path";
77
- import { match } from "ts-pattern";
78
- import { expect } from "vitest";
79
-
80
- // src/utils.ts
81
- import { loadDocument } from "@zenstackhq/language";
82
- import path2 from "path";
83
- function loadDocumentWithPlugins(filePath) {
84
- const pluginModelFiles = [
85
- path2.resolve(__dirname, "../node_modules/@zenstackhq/plugin-policy/plugin.zmodel")
86
- ];
87
- return loadDocument(filePath, pluginModelFiles);
88
- }
89
- __name(loadDocumentWithPlugins, "loadDocumentWithPlugins");
90
-
91
- // src/schema.ts
92
- function makePrelude(provider, dbUrl) {
93
- return match(provider).with("sqlite", () => {
94
- return `
95
- datasource db {
96
- provider = 'sqlite'
97
- url = '${dbUrl ?? "file:./test.db"}'
98
- }
99
- `;
100
- }).with("postgresql", () => {
101
- return `
102
- datasource db {
103
- provider = 'postgresql'
104
- url = '${dbUrl ?? "postgres://postgres:postgres@localhost:5432/db"}'
105
- }
106
- `;
107
- }).exhaustive();
108
- }
109
- __name(makePrelude, "makePrelude");
110
- async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles) {
111
- const workDir = createTestProject();
112
- const zmodelPath = path3.join(workDir, "schema.zmodel");
113
- const noPrelude = schemaText.includes("datasource ");
114
- fs2.writeFileSync(zmodelPath, `${noPrelude ? "" : makePrelude(provider, dbUrl)}
115
-
116
- ${schemaText}`);
117
- const result = await loadDocumentWithPlugins(zmodelPath);
118
- if (!result.success) {
119
- throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);
120
- }
121
- const generator = new TsSchemaGenerator();
122
- await generator.generate(result.model, workDir);
123
- if (extraSourceFiles) {
124
- for (const [fileName, content] of Object.entries(extraSourceFiles)) {
125
- const filePath = path3.resolve(workDir, !fileName.endsWith(".ts") ? `${fileName}.ts` : fileName);
126
- fs2.mkdirSync(path3.dirname(filePath), {
127
- recursive: true
128
- });
129
- fs2.writeFileSync(filePath, content);
130
- }
131
- }
132
- return {
133
- ...await compileAndLoad(workDir),
134
- model: result.model
135
- };
136
- }
137
- __name(generateTsSchema, "generateTsSchema");
138
- async function compileAndLoad(workDir) {
139
- execSync("npx tsc", {
140
- cwd: workDir,
141
- stdio: "inherit"
142
- });
143
- const module = await import(path3.join(workDir, "schema.js"));
144
- return {
145
- workDir,
146
- schema: module.schema
147
- };
148
- }
149
- __name(compileAndLoad, "compileAndLoad");
150
- function generateTsSchemaFromFile(filePath) {
151
- const schemaText = fs2.readFileSync(filePath, "utf8");
152
- return generateTsSchema(schemaText);
153
- }
154
- __name(generateTsSchemaFromFile, "generateTsSchemaFromFile");
155
- async function generateTsSchemaInPlace(schemaPath) {
156
- const workDir = path3.dirname(schemaPath);
157
- const result = await loadDocumentWithPlugins(schemaPath);
158
- if (!result.success) {
159
- throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);
160
- }
161
- const generator = new TsSchemaGenerator();
162
- await generator.generate(result.model, workDir);
163
- return compileAndLoad(workDir);
164
- }
165
- __name(generateTsSchemaInPlace, "generateTsSchemaInPlace");
166
- async function loadSchema(schema, additionalSchemas) {
167
- if (!schema.includes("datasource ")) {
168
- schema = `${makePrelude("sqlite")}
169
-
170
- ${schema}`;
171
- }
172
- const tempDir = fs2.mkdtempSync(path3.join(os.tmpdir(), "zenstack-schema"));
173
- const tempFile = path3.join(tempDir, `schema.zmodel`);
174
- fs2.writeFileSync(tempFile, schema);
175
- if (additionalSchemas) {
176
- for (const [fileName, content] of Object.entries(additionalSchemas)) {
177
- let name = fileName;
178
- if (!name.endsWith(".zmodel")) {
179
- name += ".zmodel";
180
- }
181
- const filePath = path3.join(tempDir, name);
182
- fs2.writeFileSync(filePath, content);
183
- }
184
- }
185
- const r = await loadDocumentWithPlugins(tempFile);
186
- expect(r).toSatisfy((r2) => r2.success, `Failed to load schema: ${r.errors?.map((e) => e.toString()).join(", ")}`);
187
- invariant(r.success);
188
- return r.model;
189
- }
190
- __name(loadSchema, "loadSchema");
191
- async function loadSchemaWithError(schema, error) {
192
- if (!schema.includes("datasource ")) {
193
- schema = `${makePrelude("sqlite")}
194
-
195
- ${schema}`;
196
- }
197
- const tempFile = path3.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);
198
- fs2.writeFileSync(tempFile, schema);
199
- const r = await loadDocumentWithPlugins(tempFile);
200
- expect(r.success).toBe(false);
201
- invariant(!r.success);
202
- if (typeof error === "string") {
203
- expect(r).toSatisfy((r2) => r2.errors.some((e) => e.toString().toLowerCase().includes(error.toLowerCase())), `Expected error message to include "${error}" but got: ${r.errors.map((e) => e.toString()).join(", ")}`);
204
- } else {
205
- expect(r).toSatisfy((r2) => r2.errors.some((e) => error.test(e)), `Expected error message to match "${error}" but got: ${r.errors.map((e) => e.toString()).join(", ")}`);
206
- }
207
- }
208
- __name(loadSchemaWithError, "loadSchemaWithError");
209
-
210
- // src/client.ts
211
- function getTestDbProvider() {
212
- const val = process.env["TEST_DB_PROVIDER"] ?? "sqlite";
213
- if (![
214
- "sqlite",
215
- "postgresql"
216
- ].includes(val)) {
217
- throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);
218
- }
219
- return val;
220
- }
221
- __name(getTestDbProvider, "getTestDbProvider");
222
- var TEST_PG_CONFIG = {
223
- host: process.env["TEST_PG_HOST"] ?? "localhost",
224
- port: process.env["TEST_PG_PORT"] ? parseInt(process.env["TEST_PG_PORT"]) : 5432,
225
- user: process.env["TEST_PG_USER"] ?? "postgres",
226
- password: process.env["TEST_PG_PASSWORD"] ?? "postgres"
227
- };
228
- async function createTestClient(schema, options, schemaFile) {
229
- let workDir = options?.workDir;
230
- let _schema;
231
- const provider = options?.provider ?? getTestDbProvider() ?? "sqlite";
232
- const dbName = options?.dbName ?? getTestDbName(provider);
233
- const dbUrl = provider === "sqlite" ? `file:${dbName}` : `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}/${dbName}`;
234
- let model;
235
- if (typeof schema === "string") {
236
- const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles);
237
- workDir = generated.workDir;
238
- model = generated.model;
239
- _schema = {
240
- ...generated.schema,
241
- provider: {
242
- type: provider
243
- }
244
- };
245
- } else {
246
- _schema = {
247
- ...schema,
248
- provider: {
249
- type: provider
250
- }
251
- };
252
- workDir ??= createTestProject();
253
- if (schemaFile) {
254
- let schemaContent = fs3.readFileSync(schemaFile, "utf-8");
255
- if (dbUrl) {
256
- schemaContent = schemaContent.replace(/datasource\s+db\s*{[^}]*}/m, `datasource db {
257
- provider = '${provider}'
258
- url = '${dbUrl}'
259
- }`);
260
- }
261
- fs3.writeFileSync(path4.join(workDir, "schema.zmodel"), schemaContent);
262
- }
263
- }
264
- invariant2(workDir);
265
- if (options?.debug) {
266
- console.log(`Work directory: ${workDir}`);
267
- }
268
- const { plugins, ...rest } = options ?? {};
269
- const _options = {
270
- ...rest
271
- };
272
- if (options?.usePrismaPush) {
273
- invariant2(typeof schema === "string" || schemaFile, "a schema file must be provided when using prisma db push");
274
- if (!model) {
275
- const r = await loadDocumentWithPlugins(path4.join(workDir, "schema.zmodel"));
276
- if (!r.success) {
277
- throw new Error(r.errors.join("\n"));
278
- }
279
- model = r.model;
280
- }
281
- const prismaSchema = new PrismaSchemaGenerator(model);
282
- const prismaSchemaText = await prismaSchema.generate();
283
- fs3.writeFileSync(path4.resolve(workDir, "schema.prisma"), prismaSchemaText);
284
- execSync2("npx prisma db push --schema ./schema.prisma --skip-generate --force-reset", {
285
- cwd: workDir,
286
- stdio: "ignore"
287
- });
288
- } else {
289
- if (provider === "postgresql") {
290
- invariant2(dbName, "dbName is required");
291
- const pgClient = new PGClient(TEST_PG_CONFIG);
292
- await pgClient.connect();
293
- await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`);
294
- await pgClient.query(`CREATE DATABASE "${dbName}"`);
295
- await pgClient.end();
296
- }
297
- }
298
- if (provider === "postgresql") {
299
- _options.dialect = new PostgresDialect({
300
- pool: new Pool({
301
- ...TEST_PG_CONFIG,
302
- database: dbName
303
- })
304
- });
305
- } else {
306
- _options.dialect = new SqliteDialect({
307
- database: new SQLite(path4.join(workDir, dbName))
308
- });
309
- }
310
- let client = new ZenStackClient(_schema, _options);
311
- if (!options?.usePrismaPush) {
312
- await client.$pushSchema();
313
- }
314
- if (plugins) {
315
- for (const plugin of plugins) {
316
- client = client.$use(plugin);
317
- }
318
- }
319
- return client;
320
- }
321
- __name(createTestClient, "createTestClient");
322
- async function createPolicyTestClient(schema, options) {
323
- return createTestClient(schema, {
324
- ...options,
325
- plugins: [
326
- ...options?.plugins ?? [],
327
- new PolicyPlugin()
328
- ]
329
- });
330
- }
331
- __name(createPolicyTestClient, "createPolicyTestClient");
332
- function testLogger(e) {
333
- console.log(e.query.sql, e.query.parameters);
334
- }
335
- __name(testLogger, "testLogger");
336
- function getTestDbName(provider) {
337
- if (provider === "sqlite") {
338
- return "./test.db";
339
- }
340
- const testName = expect2.getState().currentTestName;
341
- const testPath = expect2.getState().testPath ?? "";
342
- invariant2(testName);
343
- const digest = createHash("md5").update(testName + testPath).digest("hex");
344
- return "test_" + testName.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").substring(0, 30) + digest.slice(0, 6);
345
- }
346
- __name(getTestDbName, "getTestDbName");
347
-
348
- // src/vitest-ext.ts
349
- import { InputValidationError, NotFoundError, RejectedByPolicyError } from "@zenstackhq/runtime";
350
- import { expect as expect3 } from "vitest";
351
- function isPromise(value) {
352
- return typeof value.then === "function" && typeof value.catch === "function";
353
- }
354
- __name(isPromise, "isPromise");
355
- function expectError(err, errorType) {
356
- if (err instanceof errorType) {
357
- return {
358
- message: /* @__PURE__ */ __name(() => "", "message"),
359
- pass: true
360
- };
361
- } else {
362
- return {
363
- message: /* @__PURE__ */ __name(() => `expected ${errorType}, got ${err}`, "message"),
364
- pass: false
365
- };
366
- }
367
- }
368
- __name(expectError, "expectError");
369
- function expectErrorMessages(expectedMessages, message) {
370
- for (const m of expectedMessages) {
371
- if (!message.includes(m)) {
372
- return {
373
- message: /* @__PURE__ */ __name(() => `expected message not found in error: ${m}, got message: ${message}`, "message"),
374
- pass: false
375
- };
376
- }
377
- }
378
- return void 0;
379
- }
380
- __name(expectErrorMessages, "expectErrorMessages");
381
- expect3.extend({
382
- async toResolveTruthy(received) {
383
- if (!isPromise(received)) {
384
- return {
385
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
386
- pass: false
387
- };
388
- }
389
- const r = await received;
390
- return {
391
- pass: !!r,
392
- message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a truthy value, but got ${r}`, "message")
393
- };
394
- },
395
- async toResolveFalsy(received) {
396
- if (!isPromise(received)) {
397
- return {
398
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
399
- pass: false
400
- };
401
- }
402
- const r = await received;
403
- return {
404
- pass: !r,
405
- message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a falsy value, but got ${r}`, "message")
406
- };
407
- },
408
- async toResolveNull(received) {
409
- if (!isPromise(received)) {
410
- return {
411
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
412
- pass: false
413
- };
414
- }
415
- const r = await received;
416
- return {
417
- pass: r === null,
418
- message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a null value, but got ${r}`, "message")
419
- };
420
- },
421
- async toResolveWithLength(received, length) {
422
- const r = await received;
423
- return {
424
- pass: Array.isArray(r) && r.length === length,
425
- message: /* @__PURE__ */ __name(() => `Expected promise to resolve with an array with length ${length}, but got ${r}`, "message")
426
- };
427
- },
428
- async toBeRejectedNotFound(received) {
429
- if (!isPromise(received)) {
430
- return {
431
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
432
- pass: false
433
- };
434
- }
435
- try {
436
- await received;
437
- } catch (err) {
438
- return expectError(err, NotFoundError);
439
- }
440
- return {
441
- message: /* @__PURE__ */ __name(() => `expected NotFoundError, got no error`, "message"),
442
- pass: false
443
- };
444
- },
445
- async toBeRejectedByPolicy(received, expectedMessages) {
446
- if (!isPromise(received)) {
447
- return {
448
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
449
- pass: false
450
- };
451
- }
452
- try {
453
- await received;
454
- } catch (err) {
455
- if (expectedMessages && err instanceof RejectedByPolicyError) {
456
- const r = expectErrorMessages(expectedMessages, err.message || "");
457
- if (r) {
458
- return r;
459
- }
460
- }
461
- return expectError(err, RejectedByPolicyError);
462
- }
463
- return {
464
- message: /* @__PURE__ */ __name(() => `expected PolicyError, got no error`, "message"),
465
- pass: false
466
- };
467
- },
468
- async toBeRejectedByValidation(received, expectedMessages) {
469
- if (!isPromise(received)) {
470
- return {
471
- message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
472
- pass: false
473
- };
474
- }
475
- try {
476
- await received;
477
- } catch (err) {
478
- if (expectedMessages && err instanceof InputValidationError) {
479
- const r = expectErrorMessages(expectedMessages, err.message || "");
480
- if (r) {
481
- return r;
482
- }
483
- }
484
- return expectError(err, InputValidationError);
485
- }
486
- return {
487
- message: /* @__PURE__ */ __name(() => `expected InputValidationError, got no error`, "message"),
488
- pass: false
489
- };
490
- }
491
- });
492
- export {
493
- createPolicyTestClient,
494
- createTestClient,
495
- createTestProject,
496
- generateTsSchema,
497
- generateTsSchemaFromFile,
498
- generateTsSchemaInPlace,
499
- getTestDbProvider,
500
- loadSchema,
501
- loadSchemaWithError,
502
- testLogger
503
- };
504
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/runtime';\nimport type { SchemaDef } from '@zenstackhq/runtime/schema';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql';\n}\n\nconst TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> & {\n provider?: 'sqlite' | 'postgresql';\n dbName?: string;\n usePrismaPush?: boolean;\n extraSourceFiles?: Record<string, string>;\n workDir?: string;\n debug?: boolean;\n};\n\nexport async function createTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n schemaFile?: string,\n): Promise<ClientContract<Schema>>;\nexport async function createTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n schemaFile?: string,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: Schema;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n\n const dbName = options?.dbName ?? getTestDbName(provider);\n\n const dbUrl =\n provider === 'sqlite'\n ? `file:${dbName}`\n : `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}/${dbName}`;\n\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles);\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n type: provider,\n },\n } as Schema;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (schemaFile) {\n let schemaContent = fs.readFileSync(schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n }\n\n const { plugins, ...rest } = options ?? {};\n const _options: ClientOptions<Schema> = {\n ...rest,\n } as ClientOptions<Schema>;\n\n if (options?.usePrismaPush) {\n invariant(typeof schema === 'string' || schemaFile, 'a schema file must be provided when using prisma db push');\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: 'ignore',\n });\n } else {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n }\n }\n\n if (provider === 'postgresql') {\n _options.dialect = new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n });\n } else {\n _options.dialect = new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n });\n }\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush) {\n await client.$pushSchema();\n }\n\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName;\n const testPath = expect.getState().testPath ?? '';\n invariant(testName);\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'runtime', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport type { SchemaDef } from '@zenstackhq/sdk/schema';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: 'sqlite' | 'postgresql', dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(zmodelPath, `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${schemaText}`);\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, workDir);\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n return { workDir, schema: module.schema as SchemaDef };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, workDir);\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\nimport path from 'node:path';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [path.resolve(__dirname, '../node_modules/@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { InputValidationError, NotFoundError, RejectedByPolicyError } from '@zenstackhq/runtime';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectError(err: any, errorType: any) {\n if (err instanceof errorType) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ${errorType}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.includes(m)) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectError(err, NotFoundError);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof RejectedByPolicyError) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectError(err, RejectedByPolicyError);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof InputValidationError) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectError(err, InputValidationError);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["invariant","PolicyPlugin","ZenStackClient","PrismaSchemaGenerator","SQLite","PostgresDialect","SqliteDialect","execSync","createHash","fs","path","Client","PGClient","Pool","expect","fs","path","tmp","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","invariant","TsSchemaGenerator","execSync","crypto","fs","os","path","match","expect","loadDocument","path","loadDocumentWithPlugins","filePath","pluginModelFiles","path","resolve","__dirname","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","generateTsSchema","schemaText","extraSourceFiles","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","fileName","content","Object","entries","filePath","resolve","endsWith","mkdirSync","dirname","recursive","compileAndLoad","execSync","cwd","stdio","module","schema","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","name","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","createTestClient","schema","options","schemaFile","workDir","_schema","provider","dbName","getTestDbName","dbUrl","model","generated","generateTsSchema","extraSourceFiles","type","createTestProject","schemaContent","fs","readFileSync","replace","writeFileSync","path","join","invariant","debug","console","log","plugins","rest","_options","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","resolve","execSync","cwd","stdio","pgClient","PGClient","connect","query","end","dialect","PostgresDialect","pool","Pool","database","SqliteDialect","SQLite","client","ZenStackClient","$pushSchema","plugin","$use","createPolicyTestClient","PolicyPlugin","testLogger","e","sql","parameters","testName","expect","getState","currentTestName","testPath","digest","createHash","update","toLowerCase","substring","slice","InputValidationError","NotFoundError","RejectedByPolicyError","expect","isPromise","value","then","catch","expectError","err","errorType","message","pass","expectErrorMessages","expectedMessages","m","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","NotFoundError","toBeRejectedByPolicy","RejectedByPolicyError","toBeRejectedByValidation","InputValidationError"]}