postgresdk 0.6.4 → 0.6.5
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/cli.js +129 -8
- package/dist/emit-tests.d.ts +8 -0
- package/dist/index.js +129 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
@@ -2354,7 +2354,12 @@ import type { Insert${Type}, Update${Type}, Select${Type} } from '${clientPath}/
|
|
2354
2354
|
* Basic tests for ${tableName} table operations
|
2355
2355
|
*
|
2356
2356
|
* These tests demonstrate basic CRUD operations.
|
2357
|
-
*
|
2357
|
+
* The test data is auto-generated and may need adjustment for your specific schema.
|
2358
|
+
*
|
2359
|
+
* If tests fail due to validation errors:
|
2360
|
+
* 1. Check which fields are required by your API
|
2361
|
+
* 2. Update the test data below to match your schema requirements
|
2362
|
+
* 3. Consider adding your own business logic tests in separate files
|
2358
2363
|
*/
|
2359
2364
|
describe('${Type} SDK Operations', () => {
|
2360
2365
|
let sdk: SDK;
|
@@ -2417,6 +2422,38 @@ export function randomDate(): Date {
|
|
2417
2422
|
}
|
2418
2423
|
`;
|
2419
2424
|
}
|
2425
|
+
function emitVitestConfig() {
|
2426
|
+
return `import { defineConfig } from 'vitest/config';
|
2427
|
+
|
2428
|
+
export default defineConfig({
|
2429
|
+
test: {
|
2430
|
+
globals: true,
|
2431
|
+
environment: 'node',
|
2432
|
+
testTimeout: 30000,
|
2433
|
+
hookTimeout: 30000,
|
2434
|
+
// The reporters are configured via CLI in the test script
|
2435
|
+
},
|
2436
|
+
});
|
2437
|
+
`;
|
2438
|
+
}
|
2439
|
+
function emitTestGitignore() {
|
2440
|
+
return `# Test results
|
2441
|
+
test-results/
|
2442
|
+
*.log
|
2443
|
+
|
2444
|
+
# Node modules (if tests have their own dependencies)
|
2445
|
+
node_modules/
|
2446
|
+
|
2447
|
+
# Environment files
|
2448
|
+
.env
|
2449
|
+
.env.local
|
2450
|
+
.env.test
|
2451
|
+
|
2452
|
+
# Coverage reports
|
2453
|
+
coverage/
|
2454
|
+
*.lcov
|
2455
|
+
`;
|
2456
|
+
}
|
2420
2457
|
function emitDockerCompose() {
|
2421
2458
|
return `# Docker Compose for Test Database
|
2422
2459
|
#
|
@@ -2502,7 +2539,14 @@ echo ""
|
|
2502
2539
|
# sleep 3
|
2503
2540
|
|
2504
2541
|
echo "\uD83E\uDDEA Running tests..."
|
2505
|
-
|
2542
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
2543
|
+
TEST_RESULTS_DIR="$SCRIPT_DIR/test-results"
|
2544
|
+
mkdir -p "$TEST_RESULTS_DIR"
|
2545
|
+
|
2546
|
+
# Run tests with appropriate reporter based on framework
|
2547
|
+
${getTestCommand(framework, runCommand)}
|
2548
|
+
|
2549
|
+
TEST_EXIT_CODE=$?
|
2506
2550
|
|
2507
2551
|
# Cleanup
|
2508
2552
|
# if [ ! -z "\${SERVER_PID}" ]; then
|
@@ -2510,12 +2554,34 @@ ${runCommand} "$@"
|
|
2510
2554
|
# kill $SERVER_PID 2>/dev/null || true
|
2511
2555
|
# fi
|
2512
2556
|
|
2513
|
-
|
2557
|
+
if [ $TEST_EXIT_CODE -eq 0 ]; then
|
2558
|
+
echo "✅ Tests completed successfully!"
|
2559
|
+
else
|
2560
|
+
echo "❌ Tests failed with exit code $TEST_EXIT_CODE"
|
2561
|
+
fi
|
2562
|
+
|
2563
|
+
echo ""
|
2564
|
+
echo "\uD83D\uDCCA Test results saved to:"
|
2565
|
+
echo " $TEST_RESULTS_DIR/"
|
2514
2566
|
echo ""
|
2515
2567
|
echo "To stop the test database, run:"
|
2516
2568
|
echo " cd $SCRIPT_DIR && docker-compose down"
|
2569
|
+
|
2570
|
+
exit $TEST_EXIT_CODE
|
2517
2571
|
`;
|
2518
2572
|
}
|
2573
|
+
function getTestCommand(framework, baseCommand) {
|
2574
|
+
switch (framework) {
|
2575
|
+
case "vitest":
|
2576
|
+
return `${baseCommand} --reporter=default --reporter=json --outputFile="$TEST_RESULTS_DIR/results-\${TIMESTAMP}.json" "$@"`;
|
2577
|
+
case "jest":
|
2578
|
+
return `${baseCommand} --json --outputFile="$TEST_RESULTS_DIR/results-\${TIMESTAMP}.json" "$@"`;
|
2579
|
+
case "bun":
|
2580
|
+
return `${baseCommand} "$@" 2>&1 | tee "$TEST_RESULTS_DIR/results-\${TIMESTAMP}.txt"`;
|
2581
|
+
default:
|
2582
|
+
return `${baseCommand} "$@"`;
|
2583
|
+
}
|
2584
|
+
}
|
2519
2585
|
function getFrameworkImports(framework) {
|
2520
2586
|
switch (framework) {
|
2521
2587
|
case "vitest":
|
@@ -2531,14 +2597,20 @@ function getFrameworkImports(framework) {
|
|
2531
2597
|
function generateSampleData(table) {
|
2532
2598
|
const fields = [];
|
2533
2599
|
for (const col of table.columns) {
|
2534
|
-
if (col.
|
2600
|
+
if (col.name === "id" && col.hasDefault) {
|
2535
2601
|
continue;
|
2536
2602
|
}
|
2537
|
-
if (col.
|
2603
|
+
if ((col.name === "created_at" || col.name === "updated_at") && col.hasDefault) {
|
2538
2604
|
continue;
|
2539
2605
|
}
|
2540
|
-
|
2541
|
-
|
2606
|
+
if (col.name === "deleted_at") {
|
2607
|
+
continue;
|
2608
|
+
}
|
2609
|
+
const isImportant = col.name.endsWith("_id") || col.name.endsWith("_by") || col.name.includes("email") || col.name.includes("name") || col.name.includes("phone") || col.name.includes("address") || col.name.includes("description") || col.name.includes("color") || col.name.includes("type") || col.name.includes("status") || col.name.includes("subject");
|
2610
|
+
if (!col.nullable || isImportant) {
|
2611
|
+
const value = getSampleValue(col.pgType, col.name);
|
2612
|
+
fields.push(` ${col.name}: ${value}`);
|
2613
|
+
}
|
2542
2614
|
}
|
2543
2615
|
return fields.length > 0 ? `{
|
2544
2616
|
${fields.join(`,
|
@@ -2564,15 +2636,51 @@ ${fields.join(`,
|
|
2564
2636
|
}
|
2565
2637
|
function getSampleValue(type, name, isUpdate = false) {
|
2566
2638
|
const suffix = isUpdate ? ' + " (updated)"' : "";
|
2639
|
+
if (name.endsWith("_id") || name.endsWith("_by")) {
|
2640
|
+
return `'550e8400-e29b-41d4-a716-446655440000'`;
|
2641
|
+
}
|
2567
2642
|
if (name.includes("email")) {
|
2568
2643
|
return `'test${isUpdate ? ".updated" : ""}@example.com'`;
|
2569
2644
|
}
|
2645
|
+
if (name === "color") {
|
2646
|
+
return `'#${isUpdate ? "FF0000" : "0000FF"}'`;
|
2647
|
+
}
|
2648
|
+
if (name === "gender") {
|
2649
|
+
return `'${isUpdate ? "F" : "M"}'`;
|
2650
|
+
}
|
2651
|
+
if (name.includes("phone")) {
|
2652
|
+
return `'${isUpdate ? "555-0200" : "555-0100"}'`;
|
2653
|
+
}
|
2654
|
+
if (name.includes("address")) {
|
2655
|
+
return `'123 ${isUpdate ? "Updated" : "Test"} Street'`;
|
2656
|
+
}
|
2657
|
+
if (name === "type" || name === "status") {
|
2658
|
+
return `'${isUpdate ? "updated" : "active"}'`;
|
2659
|
+
}
|
2660
|
+
if (name === "subject") {
|
2661
|
+
return `'Test Subject${isUpdate ? " Updated" : ""}'`;
|
2662
|
+
}
|
2570
2663
|
if (name.includes("name") || name.includes("title")) {
|
2571
2664
|
return `'Test ${pascal(name)}'${suffix}`;
|
2572
2665
|
}
|
2573
2666
|
if (name.includes("description") || name.includes("bio") || name.includes("content")) {
|
2574
2667
|
return `'Test description'${suffix}`;
|
2575
2668
|
}
|
2669
|
+
if (name.includes("preferences") || name.includes("settings")) {
|
2670
|
+
return `'Test preferences'${suffix}`;
|
2671
|
+
}
|
2672
|
+
if (name.includes("restrictions") || name.includes("dietary")) {
|
2673
|
+
return `['vegetarian']`;
|
2674
|
+
}
|
2675
|
+
if (name.includes("location") || name.includes("clinic")) {
|
2676
|
+
return `'Test Location'${suffix}`;
|
2677
|
+
}
|
2678
|
+
if (name.includes("specialty")) {
|
2679
|
+
return `'General'`;
|
2680
|
+
}
|
2681
|
+
if (name.includes("tier")) {
|
2682
|
+
return `'Standard'`;
|
2683
|
+
}
|
2576
2684
|
switch (type) {
|
2577
2685
|
case "text":
|
2578
2686
|
case "varchar":
|
@@ -2601,7 +2709,10 @@ function getSampleValue(type, name, isUpdate = false) {
|
|
2601
2709
|
case "jsonb":
|
2602
2710
|
return `{ key: 'value' }`;
|
2603
2711
|
case "uuid":
|
2604
|
-
return `'${isUpdate ? "
|
2712
|
+
return `'${isUpdate ? "550e8400-e29b-41d4-a716-446655440001" : "550e8400-e29b-41d4-a716-446655440000"}'`;
|
2713
|
+
case "text[]":
|
2714
|
+
case "varchar[]":
|
2715
|
+
return `['item1', 'item2']`;
|
2605
2716
|
default:
|
2606
2717
|
return `'test'`;
|
2607
2718
|
}
|
@@ -2823,6 +2934,16 @@ async function generate(configPath) {
|
|
2823
2934
|
path: join(testDir, "run-tests.sh"),
|
2824
2935
|
content: emitTestScript(testFramework)
|
2825
2936
|
});
|
2937
|
+
files.push({
|
2938
|
+
path: join(testDir, ".gitignore"),
|
2939
|
+
content: emitTestGitignore()
|
2940
|
+
});
|
2941
|
+
if (testFramework === "vitest") {
|
2942
|
+
files.push({
|
2943
|
+
path: join(testDir, "vitest.config.ts"),
|
2944
|
+
content: emitVitestConfig()
|
2945
|
+
});
|
2946
|
+
}
|
2826
2947
|
for (const table of Object.values(model.tables)) {
|
2827
2948
|
files.push({
|
2828
2949
|
path: join(testDir, `${table.name}.test.ts`),
|
package/dist/emit-tests.d.ts
CHANGED
@@ -7,6 +7,14 @@ export declare function emitTableTest(table: Table, clientPath: string, framewor
|
|
7
7
|
* Generate a test setup file
|
8
8
|
*/
|
9
9
|
export declare function emitTestSetup(clientPath: string, framework?: "vitest" | "jest" | "bun"): string;
|
10
|
+
/**
|
11
|
+
* Generate vitest config file
|
12
|
+
*/
|
13
|
+
export declare function emitVitestConfig(): string;
|
14
|
+
/**
|
15
|
+
* Generate .gitignore for test directory
|
16
|
+
*/
|
17
|
+
export declare function emitTestGitignore(): string;
|
10
18
|
/**
|
11
19
|
* Generate docker-compose.yml for test database
|
12
20
|
*/
|
package/dist/index.js
CHANGED
@@ -2084,7 +2084,12 @@ import type { Insert${Type}, Update${Type}, Select${Type} } from '${clientPath}/
|
|
2084
2084
|
* Basic tests for ${tableName} table operations
|
2085
2085
|
*
|
2086
2086
|
* These tests demonstrate basic CRUD operations.
|
2087
|
-
*
|
2087
|
+
* The test data is auto-generated and may need adjustment for your specific schema.
|
2088
|
+
*
|
2089
|
+
* If tests fail due to validation errors:
|
2090
|
+
* 1. Check which fields are required by your API
|
2091
|
+
* 2. Update the test data below to match your schema requirements
|
2092
|
+
* 3. Consider adding your own business logic tests in separate files
|
2088
2093
|
*/
|
2089
2094
|
describe('${Type} SDK Operations', () => {
|
2090
2095
|
let sdk: SDK;
|
@@ -2147,6 +2152,38 @@ export function randomDate(): Date {
|
|
2147
2152
|
}
|
2148
2153
|
`;
|
2149
2154
|
}
|
2155
|
+
function emitVitestConfig() {
|
2156
|
+
return `import { defineConfig } from 'vitest/config';
|
2157
|
+
|
2158
|
+
export default defineConfig({
|
2159
|
+
test: {
|
2160
|
+
globals: true,
|
2161
|
+
environment: 'node',
|
2162
|
+
testTimeout: 30000,
|
2163
|
+
hookTimeout: 30000,
|
2164
|
+
// The reporters are configured via CLI in the test script
|
2165
|
+
},
|
2166
|
+
});
|
2167
|
+
`;
|
2168
|
+
}
|
2169
|
+
function emitTestGitignore() {
|
2170
|
+
return `# Test results
|
2171
|
+
test-results/
|
2172
|
+
*.log
|
2173
|
+
|
2174
|
+
# Node modules (if tests have their own dependencies)
|
2175
|
+
node_modules/
|
2176
|
+
|
2177
|
+
# Environment files
|
2178
|
+
.env
|
2179
|
+
.env.local
|
2180
|
+
.env.test
|
2181
|
+
|
2182
|
+
# Coverage reports
|
2183
|
+
coverage/
|
2184
|
+
*.lcov
|
2185
|
+
`;
|
2186
|
+
}
|
2150
2187
|
function emitDockerCompose() {
|
2151
2188
|
return `# Docker Compose for Test Database
|
2152
2189
|
#
|
@@ -2232,7 +2269,14 @@ echo ""
|
|
2232
2269
|
# sleep 3
|
2233
2270
|
|
2234
2271
|
echo "\uD83E\uDDEA Running tests..."
|
2235
|
-
|
2272
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
2273
|
+
TEST_RESULTS_DIR="$SCRIPT_DIR/test-results"
|
2274
|
+
mkdir -p "$TEST_RESULTS_DIR"
|
2275
|
+
|
2276
|
+
# Run tests with appropriate reporter based on framework
|
2277
|
+
${getTestCommand(framework, runCommand)}
|
2278
|
+
|
2279
|
+
TEST_EXIT_CODE=$?
|
2236
2280
|
|
2237
2281
|
# Cleanup
|
2238
2282
|
# if [ ! -z "\${SERVER_PID}" ]; then
|
@@ -2240,12 +2284,34 @@ ${runCommand} "$@"
|
|
2240
2284
|
# kill $SERVER_PID 2>/dev/null || true
|
2241
2285
|
# fi
|
2242
2286
|
|
2243
|
-
|
2287
|
+
if [ $TEST_EXIT_CODE -eq 0 ]; then
|
2288
|
+
echo "✅ Tests completed successfully!"
|
2289
|
+
else
|
2290
|
+
echo "❌ Tests failed with exit code $TEST_EXIT_CODE"
|
2291
|
+
fi
|
2292
|
+
|
2293
|
+
echo ""
|
2294
|
+
echo "\uD83D\uDCCA Test results saved to:"
|
2295
|
+
echo " $TEST_RESULTS_DIR/"
|
2244
2296
|
echo ""
|
2245
2297
|
echo "To stop the test database, run:"
|
2246
2298
|
echo " cd $SCRIPT_DIR && docker-compose down"
|
2299
|
+
|
2300
|
+
exit $TEST_EXIT_CODE
|
2247
2301
|
`;
|
2248
2302
|
}
|
2303
|
+
function getTestCommand(framework, baseCommand) {
|
2304
|
+
switch (framework) {
|
2305
|
+
case "vitest":
|
2306
|
+
return `${baseCommand} --reporter=default --reporter=json --outputFile="$TEST_RESULTS_DIR/results-\${TIMESTAMP}.json" "$@"`;
|
2307
|
+
case "jest":
|
2308
|
+
return `${baseCommand} --json --outputFile="$TEST_RESULTS_DIR/results-\${TIMESTAMP}.json" "$@"`;
|
2309
|
+
case "bun":
|
2310
|
+
return `${baseCommand} "$@" 2>&1 | tee "$TEST_RESULTS_DIR/results-\${TIMESTAMP}.txt"`;
|
2311
|
+
default:
|
2312
|
+
return `${baseCommand} "$@"`;
|
2313
|
+
}
|
2314
|
+
}
|
2249
2315
|
function getFrameworkImports(framework) {
|
2250
2316
|
switch (framework) {
|
2251
2317
|
case "vitest":
|
@@ -2261,14 +2327,20 @@ function getFrameworkImports(framework) {
|
|
2261
2327
|
function generateSampleData(table) {
|
2262
2328
|
const fields = [];
|
2263
2329
|
for (const col of table.columns) {
|
2264
|
-
if (col.
|
2330
|
+
if (col.name === "id" && col.hasDefault) {
|
2331
|
+
continue;
|
2332
|
+
}
|
2333
|
+
if ((col.name === "created_at" || col.name === "updated_at") && col.hasDefault) {
|
2265
2334
|
continue;
|
2266
2335
|
}
|
2267
|
-
if (col.
|
2336
|
+
if (col.name === "deleted_at") {
|
2268
2337
|
continue;
|
2269
2338
|
}
|
2270
|
-
const
|
2271
|
-
|
2339
|
+
const isImportant = col.name.endsWith("_id") || col.name.endsWith("_by") || col.name.includes("email") || col.name.includes("name") || col.name.includes("phone") || col.name.includes("address") || col.name.includes("description") || col.name.includes("color") || col.name.includes("type") || col.name.includes("status") || col.name.includes("subject");
|
2340
|
+
if (!col.nullable || isImportant) {
|
2341
|
+
const value = getSampleValue(col.pgType, col.name);
|
2342
|
+
fields.push(` ${col.name}: ${value}`);
|
2343
|
+
}
|
2272
2344
|
}
|
2273
2345
|
return fields.length > 0 ? `{
|
2274
2346
|
${fields.join(`,
|
@@ -2294,15 +2366,51 @@ ${fields.join(`,
|
|
2294
2366
|
}
|
2295
2367
|
function getSampleValue(type, name, isUpdate = false) {
|
2296
2368
|
const suffix = isUpdate ? ' + " (updated)"' : "";
|
2369
|
+
if (name.endsWith("_id") || name.endsWith("_by")) {
|
2370
|
+
return `'550e8400-e29b-41d4-a716-446655440000'`;
|
2371
|
+
}
|
2297
2372
|
if (name.includes("email")) {
|
2298
2373
|
return `'test${isUpdate ? ".updated" : ""}@example.com'`;
|
2299
2374
|
}
|
2375
|
+
if (name === "color") {
|
2376
|
+
return `'#${isUpdate ? "FF0000" : "0000FF"}'`;
|
2377
|
+
}
|
2378
|
+
if (name === "gender") {
|
2379
|
+
return `'${isUpdate ? "F" : "M"}'`;
|
2380
|
+
}
|
2381
|
+
if (name.includes("phone")) {
|
2382
|
+
return `'${isUpdate ? "555-0200" : "555-0100"}'`;
|
2383
|
+
}
|
2384
|
+
if (name.includes("address")) {
|
2385
|
+
return `'123 ${isUpdate ? "Updated" : "Test"} Street'`;
|
2386
|
+
}
|
2387
|
+
if (name === "type" || name === "status") {
|
2388
|
+
return `'${isUpdate ? "updated" : "active"}'`;
|
2389
|
+
}
|
2390
|
+
if (name === "subject") {
|
2391
|
+
return `'Test Subject${isUpdate ? " Updated" : ""}'`;
|
2392
|
+
}
|
2300
2393
|
if (name.includes("name") || name.includes("title")) {
|
2301
2394
|
return `'Test ${pascal(name)}'${suffix}`;
|
2302
2395
|
}
|
2303
2396
|
if (name.includes("description") || name.includes("bio") || name.includes("content")) {
|
2304
2397
|
return `'Test description'${suffix}`;
|
2305
2398
|
}
|
2399
|
+
if (name.includes("preferences") || name.includes("settings")) {
|
2400
|
+
return `'Test preferences'${suffix}`;
|
2401
|
+
}
|
2402
|
+
if (name.includes("restrictions") || name.includes("dietary")) {
|
2403
|
+
return `['vegetarian']`;
|
2404
|
+
}
|
2405
|
+
if (name.includes("location") || name.includes("clinic")) {
|
2406
|
+
return `'Test Location'${suffix}`;
|
2407
|
+
}
|
2408
|
+
if (name.includes("specialty")) {
|
2409
|
+
return `'General'`;
|
2410
|
+
}
|
2411
|
+
if (name.includes("tier")) {
|
2412
|
+
return `'Standard'`;
|
2413
|
+
}
|
2306
2414
|
switch (type) {
|
2307
2415
|
case "text":
|
2308
2416
|
case "varchar":
|
@@ -2331,7 +2439,10 @@ function getSampleValue(type, name, isUpdate = false) {
|
|
2331
2439
|
case "jsonb":
|
2332
2440
|
return `{ key: 'value' }`;
|
2333
2441
|
case "uuid":
|
2334
|
-
return `'${isUpdate ? "
|
2442
|
+
return `'${isUpdate ? "550e8400-e29b-41d4-a716-446655440001" : "550e8400-e29b-41d4-a716-446655440000"}'`;
|
2443
|
+
case "text[]":
|
2444
|
+
case "varchar[]":
|
2445
|
+
return `['item1', 'item2']`;
|
2335
2446
|
default:
|
2336
2447
|
return `'test'`;
|
2337
2448
|
}
|
@@ -2553,6 +2664,16 @@ async function generate(configPath) {
|
|
2553
2664
|
path: join(testDir, "run-tests.sh"),
|
2554
2665
|
content: emitTestScript(testFramework)
|
2555
2666
|
});
|
2667
|
+
files.push({
|
2668
|
+
path: join(testDir, ".gitignore"),
|
2669
|
+
content: emitTestGitignore()
|
2670
|
+
});
|
2671
|
+
if (testFramework === "vitest") {
|
2672
|
+
files.push({
|
2673
|
+
path: join(testDir, "vitest.config.ts"),
|
2674
|
+
content: emitVitestConfig()
|
2675
|
+
});
|
2676
|
+
}
|
2556
2677
|
for (const table of Object.values(model.tables)) {
|
2557
2678
|
files.push({
|
2558
2679
|
path: join(testDir, `${table.name}.test.ts`),
|