rwsdk 1.0.0-beta.27-test.20251116215153 → 1.0.0-beta.29
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/lib/e2e/environment.mjs +6 -1
- package/dist/lib/e2e/release.d.mts +1 -0
- package/dist/lib/e2e/release.mjs +16 -3
- package/dist/lib/e2e/tarball.mjs +3 -10
- package/dist/lib/e2e/testHarness.mjs +6 -3
- package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +13 -3
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +34 -20
- package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +9 -2
- package/dist/runtime/lib/db/typeInference/database.d.ts +16 -2
- package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.js +80 -5
- package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.js +102 -1
- package/dist/runtime/lib/db/typeInference/typetests/testUtils.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/utils.d.ts +59 -9
- package/dist/runtime/lib/links.d.ts +18 -25
- package/dist/runtime/lib/links.js +70 -42
- package/dist/runtime/lib/links.test.d.ts +1 -0
- package/dist/runtime/lib/links.test.js +20 -0
- package/dist/runtime/lib/realtime/worker.d.ts +1 -1
- package/dist/runtime/lib/router.d.ts +23 -9
- package/dist/runtime/lib/router.js +14 -36
- package/dist/runtime/lib/stitchDocumentAndAppStreams.d.ts +66 -0
- package/dist/runtime/lib/stitchDocumentAndAppStreams.js +167 -28
- package/dist/runtime/lib/stitchDocumentAndAppStreams.test.js +43 -9
- package/dist/runtime/worker.d.ts +3 -1
- package/dist/runtime/worker.js +1 -0
- package/dist/use-synced-state/worker.d.mts +1 -1
- package/dist/vite/constants.d.mts +1 -0
- package/dist/vite/constants.mjs +1 -0
- package/dist/vite/ssrBridgePlugin.mjs +9 -0
- package/package.json +2 -2
|
@@ -144,8 +144,13 @@ export async function copyProjectToTempDir(projectDir, resourceUniqueKey, packag
|
|
|
144
144
|
// Determine the source directory to copy from
|
|
145
145
|
const sourceDir = monorepoRoot || projectDir;
|
|
146
146
|
// Create unique project directory name
|
|
147
|
+
// Format: {projectName}-t-{hash} (kept under 54 chars for Cloudflare limit)
|
|
147
148
|
const originalDirName = basename(sourceDir);
|
|
148
|
-
const
|
|
149
|
+
const slugified = slugify(originalDirName);
|
|
150
|
+
// Truncate project name to leave room for "-t-" (3 chars) + hash (8 chars) = 11 chars
|
|
151
|
+
// Max project name: 54 - 11 = 43 chars
|
|
152
|
+
const truncatedProjectName = slugified.substring(0, 43);
|
|
153
|
+
const workerName = `${truncatedProjectName}-t-${resourceUniqueKey}`;
|
|
149
154
|
const tempCopyRoot = resolve(tempDir.path, workerName);
|
|
150
155
|
// If it's a monorepo, the targetDir for commands is a subdirectory
|
|
151
156
|
const targetDir = monorepoRoot
|
|
@@ -39,6 +39,7 @@ export declare function runRelease(cwd: string, projectDir: string, resourceUniq
|
|
|
39
39
|
/**
|
|
40
40
|
* Check if a resource name includes a specific resource unique key
|
|
41
41
|
* This is used to identify resources created during our tests
|
|
42
|
+
* Handles both full format (adjective-animal-hash) and hash-only format
|
|
42
43
|
*/
|
|
43
44
|
export declare function isRelatedToTest(resourceName: string, resourceUniqueKey: string): boolean;
|
|
44
45
|
/**
|
package/dist/lib/e2e/release.mjs
CHANGED
|
@@ -245,9 +245,15 @@ export async function runRelease(cwd, projectDir, resourceUniqueKey) {
|
|
|
245
245
|
await ensureCloudflareAccountId(cwd, projectDir);
|
|
246
246
|
// Extract worker name from directory name to ensure consistency
|
|
247
247
|
const dirName = cwd ? basename(cwd) : "unknown-worker";
|
|
248
|
+
// Extract hash part from resourceUniqueKey for matching
|
|
249
|
+
// resourceUniqueKey format is typically "adjective-animal-hash" or just "hash"
|
|
250
|
+
const hashPart = resourceUniqueKey.includes("-")
|
|
251
|
+
? resourceUniqueKey.split("-").pop() || resourceUniqueKey.substring(0, 8)
|
|
252
|
+
: resourceUniqueKey.substring(0, 8);
|
|
253
|
+
const uniqueKeyForMatching = hashPart.substring(0, 8);
|
|
248
254
|
// Ensure resource unique key is included in worker name for tracking
|
|
249
|
-
if (resourceUniqueKey && !dirName.includes(
|
|
250
|
-
log(`Worker name doesn't contain our unique key, this is unexpected: ${dirName}, key: ${
|
|
255
|
+
if (resourceUniqueKey && !dirName.includes(uniqueKeyForMatching)) {
|
|
256
|
+
log(`Worker name doesn't contain our unique key, this is unexpected: ${dirName}, key: ${uniqueKeyForMatching}`);
|
|
251
257
|
console.log(`⚠️ Worker name doesn't contain our unique key. This might cause cleanup issues.`);
|
|
252
258
|
}
|
|
253
259
|
// Ensure the worker name in wrangler.jsonc matches our unique name
|
|
@@ -376,9 +382,16 @@ export async function runRelease(cwd, projectDir, resourceUniqueKey) {
|
|
|
376
382
|
/**
|
|
377
383
|
* Check if a resource name includes a specific resource unique key
|
|
378
384
|
* This is used to identify resources created during our tests
|
|
385
|
+
* Handles both full format (adjective-animal-hash) and hash-only format
|
|
379
386
|
*/
|
|
380
387
|
export function isRelatedToTest(resourceName, resourceUniqueKey) {
|
|
381
|
-
|
|
388
|
+
// Extract hash part if resourceUniqueKey contains dashes (full format)
|
|
389
|
+
// Otherwise use as-is (hash-only format)
|
|
390
|
+
const hashPart = resourceUniqueKey.includes("-")
|
|
391
|
+
? resourceUniqueKey.split("-").pop() || resourceUniqueKey.substring(0, 8)
|
|
392
|
+
: resourceUniqueKey;
|
|
393
|
+
const uniqueKeyForMatching = hashPart.substring(0, 8);
|
|
394
|
+
return resourceName.includes(uniqueKeyForMatching);
|
|
382
395
|
}
|
|
383
396
|
/**
|
|
384
397
|
* Delete the worker using wrangler
|
package/dist/lib/e2e/tarball.mjs
CHANGED
|
@@ -2,9 +2,8 @@ import { createHash } from "crypto";
|
|
|
2
2
|
import { $ } from "execa";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { adjectives, animals, uniqueNamesGenerator, } from "unique-names-generator";
|
|
6
5
|
import { ROOT_DIR } from "../constants.mjs";
|
|
7
|
-
import { copyProjectToTempDir
|
|
6
|
+
import { copyProjectToTempDir } from "./environment.mjs";
|
|
8
7
|
const log = (message) => console.log(message);
|
|
9
8
|
/**
|
|
10
9
|
* Copies wrangler cache from monorepo to temp directory for deployment tests
|
|
@@ -66,18 +65,12 @@ async function copyWranglerCache(targetDir, sdkRoot) {
|
|
|
66
65
|
export async function setupTarballEnvironment({ projectDir, monorepoRoot, packageManager = "pnpm", }) {
|
|
67
66
|
log(`🚀 Setting up tarball environment for ${projectDir}`);
|
|
68
67
|
// Generate a resource unique key for this test run
|
|
69
|
-
|
|
70
|
-
dictionaries: [adjectives, animals],
|
|
71
|
-
separator: "-",
|
|
72
|
-
length: 2,
|
|
73
|
-
style: "lowerCase",
|
|
74
|
-
});
|
|
75
|
-
// Create a short unique hash based on the timestamp
|
|
68
|
+
// Use just the hash to keep worker names short (under Cloudflare's 54 char limit)
|
|
76
69
|
const hash = createHash("md5")
|
|
77
70
|
.update(Date.now().toString())
|
|
78
71
|
.digest("hex")
|
|
79
72
|
.substring(0, 8);
|
|
80
|
-
const resourceUniqueKey =
|
|
73
|
+
const resourceUniqueKey = hash;
|
|
81
74
|
try {
|
|
82
75
|
const { tempDir, targetDir } = await copyProjectToTempDir(projectDir, resourceUniqueKey, packageManager, monorepoRoot);
|
|
83
76
|
// Copy wrangler cache to improve deployment performance
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
import path, { basename, dirname, join as pathJoin } from "path";
|
|
3
3
|
import puppeteer from "puppeteer-core";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
4
5
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, test, } from "vitest";
|
|
5
6
|
import { launchBrowser } from "./browser.mjs";
|
|
6
|
-
import { ensureTmpDir } from "./utils.mjs";
|
|
7
7
|
import { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, } from "./constants.mjs";
|
|
8
8
|
import { runDevServer } from "./dev.mjs";
|
|
9
9
|
import { poll, pollValue } from "./poll.mjs";
|
|
10
10
|
import { deleteD1Database, deleteWorker, isRelatedToTest, runRelease, } from "./release.mjs";
|
|
11
11
|
import { setupTarballEnvironment } from "./tarball.mjs";
|
|
12
|
-
import {
|
|
12
|
+
import { ensureTmpDir } from "./utils.mjs";
|
|
13
13
|
export { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, };
|
|
14
14
|
// Environment variable flags for skipping tests
|
|
15
15
|
const SKIP_DEV_SERVER_TESTS = process.env.RWSDK_SKIP_DEV === "1";
|
|
@@ -223,7 +223,10 @@ export function createDeployment() {
|
|
|
223
223
|
}
|
|
224
224
|
const newInstance = await pollValue(async () => {
|
|
225
225
|
const dirName = basename(projectDir);
|
|
226
|
-
|
|
226
|
+
// Match formats: {projectName}-t-{hash}, {projectName}-test-{hash}, or {projectName}-e2e-test-{hash}
|
|
227
|
+
const match = dirName.match(/-t-([a-f0-9]+)$/) ||
|
|
228
|
+
dirName.match(/-test-([a-f0-9]+)$/) ||
|
|
229
|
+
dirName.match(/-e2e-test-([a-f0-9]+)$/);
|
|
227
230
|
const resourceUniqueKey = match
|
|
228
231
|
? match[1]
|
|
229
232
|
: Math.random().toString(36).substring(2, 15);
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { CheckConstraintNode, Expression, ForeignKeyConstraintBuilder, PrimaryKeyConstraintNode, sql, UniqueConstraintNode } from "kysely";
|
|
2
2
|
import { AddColumnOp, AlterColumnOp, AlterOperation, DropColumnOp, ExecutedBuilder, ModifyColumnOp, RenameColumnOp, SqlToTsType } from "../utils";
|
|
3
3
|
import { AlterColumnBuilderCallback } from "./alterColumn";
|
|
4
|
-
import { ColumnDefinitionBuilder } from "./columnDefinition";
|
|
4
|
+
import { ColumnDefinitionBuilder, ColumnDescriptor } from "./columnDefinition";
|
|
5
5
|
type DataTypeExpression = string | typeof sql;
|
|
6
|
+
type InitialDescriptor<TType> = {
|
|
7
|
+
tsType: TType;
|
|
8
|
+
isNullable: true;
|
|
9
|
+
hasDefault: false;
|
|
10
|
+
isAutoIncrement: false;
|
|
11
|
+
};
|
|
6
12
|
interface CheckConstraintBuilder {
|
|
7
13
|
$call<T>(func: (qb: this) => T): T;
|
|
8
14
|
toOperationNode(): CheckConstraintNode;
|
|
@@ -31,14 +37,18 @@ export interface AlterTableBuilder<TName extends string, TOps extends AlterOpera
|
|
|
31
37
|
readonly __renamedFrom: TName;
|
|
32
38
|
};
|
|
33
39
|
setSchema(newSchema: string): AlterTableBuilder<TName, TOps>;
|
|
34
|
-
addColumn<K extends string, T extends DataTypeExpression>(name: K, type: T
|
|
40
|
+
addColumn<K extends string, T extends DataTypeExpression>(name: K, type: T): AlterTableBuilder<TName, [
|
|
41
|
+
...TOps,
|
|
42
|
+
AddColumnOp<K, T, InitialDescriptor<SqlToTsType<T>>>
|
|
43
|
+
]>;
|
|
44
|
+
addColumn<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor>(name: K, type: T, build: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): AlterTableBuilder<TName, [...TOps, AddColumnOp<K, T, TDescriptor>]>;
|
|
35
45
|
dropColumn<K extends string>(name: K): AlterTableBuilder<TName, [...TOps, DropColumnOp<K>]>;
|
|
36
46
|
renameColumn<KFrom extends string, KTo extends string>(from: KFrom, to: KTo): AlterTableBuilder<TName, [...TOps, RenameColumnOp<KFrom, KTo>]>;
|
|
37
47
|
alterColumn<K extends string, const TCallback extends AlterColumnBuilderCallback>(column: K, alteration: TCallback): AlterTableBuilder<TName, [
|
|
38
48
|
...TOps,
|
|
39
49
|
AlterColumnOp<K, ReturnType<TCallback>["__alteration"]>
|
|
40
50
|
]>;
|
|
41
|
-
modifyColumn<K extends string, T extends DataTypeExpression>(column: K, type: T, build?: (col: ColumnDefinitionBuilder<SqlToTsType<T
|
|
51
|
+
modifyColumn<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor>(column: K, type: T, build?: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): AlterTableBuilder<TName, [...TOps, ModifyColumnOp<K, T, TDescriptor>]>;
|
|
42
52
|
addUniqueConstraint(constraintName: string, columns: string[], build?: (builder: UniqueConstraintBuilder) => UniqueConstraintBuilder): AlterTableBuilder<TName, TOps>;
|
|
43
53
|
addPrimaryKeyConstraint(constraintName: string, columns: string[], build?: (builder: PrimaryKeyConstraintBuilder) => PrimaryKeyConstraintBuilder): AlterTableBuilder<TName, TOps>;
|
|
44
54
|
addCheckConstraint(constraintName: string, checkExpression: Expression<any>, build?: (builder: CheckConstraintBuilder) => CheckConstraintBuilder): AlterTableBuilder<TName, TOps>;
|
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
import { ColumnDefinitionNode, Expression, sql } from "kysely";
|
|
2
2
|
type DefaultValueExpression = string | number | boolean | null | ReturnType<typeof sql>;
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
3
|
+
export type ColumnDescriptor = {
|
|
4
|
+
tsType: any;
|
|
5
|
+
isNullable: boolean;
|
|
6
|
+
hasDefault: boolean;
|
|
7
|
+
isAutoIncrement: boolean;
|
|
8
|
+
};
|
|
9
|
+
export interface ColumnDefinitionBuilder<TDescriptor extends ColumnDescriptor> {
|
|
10
|
+
autoIncrement(): ColumnDefinitionBuilder<{
|
|
11
|
+
[K in keyof TDescriptor]: K extends "isAutoIncrement" ? true : TDescriptor[K];
|
|
12
|
+
}>;
|
|
13
|
+
identity(): ColumnDefinitionBuilder<TDescriptor>;
|
|
14
|
+
primaryKey(): ColumnDefinitionBuilder<{
|
|
15
|
+
[K in keyof TDescriptor]: K extends "isNullable" ? false : TDescriptor[K];
|
|
16
|
+
}>;
|
|
17
|
+
references(ref: string): ColumnDefinitionBuilder<TDescriptor>;
|
|
18
|
+
onDelete(onDelete: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TDescriptor>;
|
|
19
|
+
onUpdate(onUpdate: "no action" | "restrict" | "cascade" | "set null" | "set default"): ColumnDefinitionBuilder<TDescriptor>;
|
|
20
|
+
unique(): ColumnDefinitionBuilder<TDescriptor>;
|
|
21
|
+
notNull(): ColumnDefinitionBuilder<{
|
|
22
|
+
[K in keyof TDescriptor]: K extends "isNullable" ? false : TDescriptor[K];
|
|
23
|
+
}>;
|
|
24
|
+
unsigned(): ColumnDefinitionBuilder<TDescriptor>;
|
|
25
|
+
defaultTo(value: DefaultValueExpression): ColumnDefinitionBuilder<{
|
|
26
|
+
[K in keyof TDescriptor]: K extends "isNullable" ? false : K extends "hasDefault" ? true : TDescriptor[K];
|
|
27
|
+
}>;
|
|
28
|
+
check(expression: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
|
|
29
|
+
generatedAlwaysAs(expression: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
|
|
30
|
+
generatedAlwaysAsIdentity(): ColumnDefinitionBuilder<TDescriptor>;
|
|
31
|
+
generatedByDefaultAsIdentity(): ColumnDefinitionBuilder<TDescriptor>;
|
|
32
|
+
stored(): ColumnDefinitionBuilder<TDescriptor>;
|
|
33
|
+
modifyFront(modifier: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
|
|
34
|
+
nullsNotDistinct(): ColumnDefinitionBuilder<TDescriptor>;
|
|
35
|
+
ifNotExists(): ColumnDefinitionBuilder<TDescriptor>;
|
|
36
|
+
modifyEnd(modifier: Expression<any>): ColumnDefinitionBuilder<TDescriptor>;
|
|
23
37
|
$call<T>(func: (qb: this) => T): T;
|
|
24
38
|
toOperationNode(): ColumnDefinitionNode;
|
|
25
39
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CheckConstraintNode, CompiledQuery, CreateTableNode, Expression, ForeignKeyConstraintBuilder, PrimaryKeyConstraintNode, UniqueConstraintNode } from "kysely";
|
|
2
2
|
import { ExecutedBuilder, Prettify, SqlToTsType } from "../utils";
|
|
3
|
-
import { ColumnDefinitionBuilder } from "./columnDefinition";
|
|
3
|
+
import { ColumnDefinitionBuilder, ColumnDescriptor } from "./columnDefinition";
|
|
4
4
|
interface CheckConstraintBuilder {
|
|
5
5
|
$call<T>(func: (qb: this) => T): T;
|
|
6
6
|
toOperationNode(): CheckConstraintNode;
|
|
@@ -22,13 +22,20 @@ interface PrimaryKeyConstraintBuilder {
|
|
|
22
22
|
$call<T>(func: (qb: this) => T): T;
|
|
23
23
|
toOperationNode(): PrimaryKeyConstraintNode;
|
|
24
24
|
}
|
|
25
|
+
type InitialDescriptor<TType> = {
|
|
26
|
+
tsType: TType;
|
|
27
|
+
isNullable: true;
|
|
28
|
+
hasDefault: false;
|
|
29
|
+
isAutoIncrement: false;
|
|
30
|
+
};
|
|
25
31
|
export interface CreateTableBuilder<TName extends string, TSchema extends Record<string, any> = {}> {
|
|
26
32
|
readonly __tableName: TName;
|
|
27
33
|
readonly __addedColumns: TSchema;
|
|
28
34
|
temporary(): CreateTableBuilder<TName, TSchema>;
|
|
29
35
|
onCommit(onCommit: "preserve rows" | "delete rows" | "drop"): CreateTableBuilder<TName, TSchema>;
|
|
30
36
|
ifNotExists(): CreateTableBuilder<TName, TSchema>;
|
|
31
|
-
addColumn<K extends string, T extends string>(name: K, type: T
|
|
37
|
+
addColumn<K extends string, T extends string>(name: K, type: T): CreateTableBuilder<TName, Prettify<(TSchema extends Record<string, any> ? TSchema : {}) & Record<K, InitialDescriptor<SqlToTsType<T>>>>>;
|
|
38
|
+
addColumn<K extends string, T extends string, TDescriptor extends ColumnDescriptor>(name: K, type: T, build: (col: ColumnDefinitionBuilder<InitialDescriptor<SqlToTsType<T>>>) => ColumnDefinitionBuilder<TDescriptor>): CreateTableBuilder<TName, Prettify<(TSchema extends Record<string, any> ? TSchema : {}) & Record<K, TDescriptor>>>;
|
|
32
39
|
addUniqueConstraint(constraintName: string, columns: (keyof TSchema)[], build?: (builder: UniqueConstraintBuilder) => UniqueConstraintBuilder): CreateTableBuilder<TName, TSchema>;
|
|
33
40
|
addPrimaryKeyConstraint(constraintName: string, columns: (keyof TSchema)[], build?: (builder: PrimaryKeyConstraintBuilder) => PrimaryKeyConstraintBuilder): CreateTableBuilder<TName, TSchema>;
|
|
34
41
|
addCheckConstraint(constraintName: string, checkExpression: Expression<any>, build?: (builder: CheckConstraintBuilder) => CheckConstraintBuilder): CreateTableBuilder<TName, TSchema>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Kysely } from "kysely";
|
|
1
|
+
import { Generated, Kysely } from "kysely";
|
|
2
2
|
import { AlterTableBuilder } from "./builders/alterTable";
|
|
3
3
|
import { CreateTableBuilder } from "./builders/createTable";
|
|
4
4
|
import { DropTableBuilder } from "./builders/dropTable";
|
|
5
5
|
import { SchemaBuilder } from "./builders/schema";
|
|
6
6
|
import { ExecutedBuilder, Prettify, ProcessAlteredTable, UnionToTuple } from "./utils";
|
|
7
|
+
import { ColumnDescriptor } from "./builders/columnDefinition";
|
|
7
8
|
export interface InferenceBuilder {
|
|
8
9
|
schema: SchemaBuilder;
|
|
9
10
|
}
|
|
@@ -23,5 +24,18 @@ type ApplyBuilders<TSchema, TBuildersTuple> = TBuildersTuple extends [
|
|
|
23
24
|
...infer TRest
|
|
24
25
|
] ? ApplyBuilders<ApplyBuilder<TSchema, THead>, TRest> : TSchema;
|
|
25
26
|
type ProcessMigrations<TMigrations extends Migrations, TKeys, TSchema = {}> = TKeys extends [infer THeadKey, ...infer TRestKeys] ? THeadKey extends keyof TMigrations ? ProcessMigrations<TMigrations, TRestKeys, ApplyBuilders<TSchema, UnionToTuple<BuildersFromMigration<TMigrations[THeadKey]>>>> : TSchema : TSchema;
|
|
26
|
-
|
|
27
|
+
type TableToSelectType<TTable> = Prettify<{
|
|
28
|
+
[K in keyof TTable]: TTable[K] extends ColumnDescriptor ? TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"] : TTable[K];
|
|
29
|
+
}>;
|
|
30
|
+
type TableToKyselySchema<TTable> = Prettify<{
|
|
31
|
+
[K in keyof TTable]: TTable[K] extends ColumnDescriptor ? TTable[K]["hasDefault"] extends true ? Generated<TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"]> : TTable[K]["isAutoIncrement"] extends true ? Generated<TTable[K]["tsType"]> : TTable[K]["isNullable"] extends true ? TTable[K]["tsType"] | null : TTable[K]["tsType"] : TTable[K];
|
|
32
|
+
}>;
|
|
33
|
+
type DatabaseWithDescriptors<TMigrations extends Migrations = Migrations> = ProcessMigrations<TMigrations, UnionToTuple<keyof TMigrations>>;
|
|
34
|
+
export type Database<TMigrations extends Migrations = Migrations> = Prettify<{
|
|
35
|
+
[K in keyof DatabaseWithDescriptors<TMigrations>]: TableToSelectType<DatabaseWithDescriptors<TMigrations>[K]>;
|
|
36
|
+
} & {
|
|
37
|
+
__kyselySchema: {
|
|
38
|
+
[K in keyof DatabaseWithDescriptors<TMigrations>]: TableToKyselySchema<DatabaseWithDescriptors<TMigrations>[K]>;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
27
41
|
export {};
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
},
|
|
98
98
|
},
|
|
99
99
|
};
|
|
100
|
-
//(_test:
|
|
100
|
+
//(_test: ExpectDb<Actual, Expected>) => {};
|
|
101
101
|
};
|
|
102
102
|
(_it = "alterTable addUniqueConstraint") => {
|
|
103
103
|
const migrations = {
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
},
|
|
125
125
|
};
|
|
126
|
-
//(_test:
|
|
126
|
+
//(_test: ExpectDb<Actual, Expected>) => {};
|
|
127
127
|
};
|
|
128
128
|
(_it = "alterTable drop column") => {
|
|
129
129
|
const migrations = {
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
up: async (db) => [
|
|
154
154
|
await db.schema
|
|
155
155
|
.createTable("users")
|
|
156
|
-
.addColumn("id", "integer")
|
|
156
|
+
.addColumn("id", "integer", (c) => c.primaryKey().autoIncrement())
|
|
157
157
|
.execute(),
|
|
158
158
|
],
|
|
159
159
|
},
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
return [
|
|
243
243
|
await db.schema
|
|
244
244
|
.createTable("users")
|
|
245
|
-
.addColumn("id", "integer")
|
|
245
|
+
.addColumn("id", "integer", (col) => col.notNull())
|
|
246
246
|
.execute(),
|
|
247
247
|
];
|
|
248
248
|
},
|
|
@@ -271,7 +271,7 @@
|
|
|
271
271
|
return [
|
|
272
272
|
await db.schema
|
|
273
273
|
.createTable("users")
|
|
274
|
-
.addColumn("id", "integer")
|
|
274
|
+
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
|
|
275
275
|
.execute(),
|
|
276
276
|
];
|
|
277
277
|
},
|
|
@@ -357,4 +357,79 @@
|
|
|
357
357
|
};
|
|
358
358
|
(_test) => { };
|
|
359
359
|
};
|
|
360
|
+
(_it = "alterTable addColumn with notNull") => {
|
|
361
|
+
const migrations = {
|
|
362
|
+
"0": {
|
|
363
|
+
async up(db) {
|
|
364
|
+
return [
|
|
365
|
+
await db.schema
|
|
366
|
+
.createTable("users")
|
|
367
|
+
.addColumn("id", "integer", (col) => col.primaryKey())
|
|
368
|
+
.execute(),
|
|
369
|
+
];
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
"1": {
|
|
373
|
+
async up(db) {
|
|
374
|
+
return [
|
|
375
|
+
await db.schema
|
|
376
|
+
.alterTable("users")
|
|
377
|
+
.addColumn("email", "text", (col) => col.notNull())
|
|
378
|
+
.execute(),
|
|
379
|
+
];
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
(_test) => { };
|
|
384
|
+
};
|
|
385
|
+
(_it = "alterTable modifyColumn with notNull") => {
|
|
386
|
+
const migrations = {
|
|
387
|
+
"0": {
|
|
388
|
+
async up(db) {
|
|
389
|
+
return [
|
|
390
|
+
await db.schema
|
|
391
|
+
.createTable("products")
|
|
392
|
+
.addColumn("price", "real")
|
|
393
|
+
.execute(),
|
|
394
|
+
];
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
"1": {
|
|
398
|
+
async up(db) {
|
|
399
|
+
return [
|
|
400
|
+
await db.schema
|
|
401
|
+
.alterTable("products")
|
|
402
|
+
.modifyColumn("price", "real", (col) => col.notNull())
|
|
403
|
+
.execute(),
|
|
404
|
+
];
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
(_test) => { };
|
|
409
|
+
};
|
|
410
|
+
(_it = "alterTable modifyColumn nullable to non-nullable") => {
|
|
411
|
+
const migrations = {
|
|
412
|
+
"0": {
|
|
413
|
+
async up(db) {
|
|
414
|
+
return [
|
|
415
|
+
await db.schema
|
|
416
|
+
.createTable("orders")
|
|
417
|
+
.addColumn("status", "text")
|
|
418
|
+
.execute(),
|
|
419
|
+
];
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
"1": {
|
|
423
|
+
async up(db) {
|
|
424
|
+
return [
|
|
425
|
+
await db.schema
|
|
426
|
+
.alterTable("orders")
|
|
427
|
+
.modifyColumn("status", "text", (col) => col.notNull().defaultTo("pending"))
|
|
428
|
+
.execute(),
|
|
429
|
+
];
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
(_test) => { };
|
|
434
|
+
};
|
|
360
435
|
export {};
|
|
@@ -22,9 +22,11 @@ import { sql } from "kysely";
|
|
|
22
22
|
await db.schema
|
|
23
23
|
.createTable("users")
|
|
24
24
|
.addColumn("username", "text", (col) => col.notNull())
|
|
25
|
-
.addColumn("age", "integer", (col) => col.defaultTo(18))
|
|
26
25
|
.addColumn("active", "boolean", (col) => col.defaultTo(true))
|
|
27
26
|
.addColumn("anotherBoolean", "boolean", (col) => col.defaultTo(sql `true`))
|
|
27
|
+
.addColumn("email", "text", (col) => col)
|
|
28
|
+
.addColumn("favoriteColor", "text", (col) => col.unique())
|
|
29
|
+
.addColumn("name", "text", (col) => col.defaultTo("John Doe"))
|
|
28
30
|
.execute(),
|
|
29
31
|
];
|
|
30
32
|
},
|
|
@@ -32,3 +34,102 @@ import { sql } from "kysely";
|
|
|
32
34
|
};
|
|
33
35
|
(_test) => { };
|
|
34
36
|
};
|
|
37
|
+
(_it = "createTable column without callback is nullable") => {
|
|
38
|
+
const migrations = {
|
|
39
|
+
"001_init": {
|
|
40
|
+
async up(db) {
|
|
41
|
+
return [
|
|
42
|
+
await db.schema
|
|
43
|
+
.createTable("posts")
|
|
44
|
+
.addColumn("title", "text")
|
|
45
|
+
.addColumn("body", "text")
|
|
46
|
+
.execute(),
|
|
47
|
+
];
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
(_test) => { };
|
|
52
|
+
};
|
|
53
|
+
(_it = "createTable with primaryKey is non-nullable") => {
|
|
54
|
+
const migrations = {
|
|
55
|
+
"001_init": {
|
|
56
|
+
async up(db) {
|
|
57
|
+
return [
|
|
58
|
+
await db.schema
|
|
59
|
+
.createTable("users")
|
|
60
|
+
.addColumn("id", "integer", (col) => col.primaryKey())
|
|
61
|
+
.addColumn("email", "text", (col) => col.notNull())
|
|
62
|
+
.execute(),
|
|
63
|
+
];
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
(_test) => { };
|
|
68
|
+
};
|
|
69
|
+
(_it = "createTable with unique but no notNull is nullable") => {
|
|
70
|
+
const migrations = {
|
|
71
|
+
"001_init": {
|
|
72
|
+
async up(db) {
|
|
73
|
+
return [
|
|
74
|
+
await db.schema
|
|
75
|
+
.createTable("products")
|
|
76
|
+
.addColumn("sku", "text", (col) => col.unique())
|
|
77
|
+
.addColumn("name", "text", (col) => col)
|
|
78
|
+
.execute(),
|
|
79
|
+
];
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
(_test) => { };
|
|
84
|
+
};
|
|
85
|
+
(_it = "defaultTo makes columns non-nullable in Database type") => {
|
|
86
|
+
const migrations = {
|
|
87
|
+
"001_init": {
|
|
88
|
+
async up(db) {
|
|
89
|
+
return [
|
|
90
|
+
await db.schema
|
|
91
|
+
.createTable("users")
|
|
92
|
+
.addColumn("status", "text", (col) => col.defaultTo("active"))
|
|
93
|
+
.addColumn("count", "integer", (col) => col.defaultTo(0))
|
|
94
|
+
.execute(),
|
|
95
|
+
];
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
(_test) => { };
|
|
100
|
+
};
|
|
101
|
+
// --- Insert/Update Type Tests ---
|
|
102
|
+
(_it = "makes autoIncrement columns optional on insert") => {
|
|
103
|
+
const migrations = {
|
|
104
|
+
"001_init": {
|
|
105
|
+
async up(db) {
|
|
106
|
+
return [
|
|
107
|
+
await db.schema
|
|
108
|
+
.createTable("users")
|
|
109
|
+
.addColumn("id", "integer", (col) => col.primaryKey().autoIncrement())
|
|
110
|
+
.addColumn("username", "text", (col) => col.notNull())
|
|
111
|
+
.execute(),
|
|
112
|
+
];
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
const db = {};
|
|
117
|
+
db.insertInto("users").values({ username: "test" });
|
|
118
|
+
};
|
|
119
|
+
(_it = "makes defaultTo columns optional on insert") => {
|
|
120
|
+
const migrations = {
|
|
121
|
+
"001_init": {
|
|
122
|
+
async up(db) {
|
|
123
|
+
return [
|
|
124
|
+
await db.schema
|
|
125
|
+
.createTable("users")
|
|
126
|
+
.addColumn("username", "text", (col) => col.notNull())
|
|
127
|
+
.addColumn("status", "text", (col) => col.notNull().defaultTo("active"))
|
|
128
|
+
.execute(),
|
|
129
|
+
];
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
const db = {};
|
|
134
|
+
db.insertInto("users").values({ username: "test" });
|
|
135
|
+
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { sql } from "kysely";
|
|
2
|
+
import { ColumnDescriptor } from "./builders/columnDefinition";
|
|
2
3
|
type DataTypeExpression = string | typeof sql;
|
|
3
|
-
export type AddColumnOp<K extends string, T extends DataTypeExpression> = {
|
|
4
|
+
export type AddColumnOp<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor> = {
|
|
4
5
|
op: "addColumn";
|
|
5
6
|
name: K;
|
|
6
7
|
type: T;
|
|
8
|
+
descriptor: TDescriptor;
|
|
7
9
|
};
|
|
8
10
|
export type DropColumnOp<K extends string> = {
|
|
9
11
|
op: "dropColumn";
|
|
@@ -14,10 +16,11 @@ export type RenameColumnOp<KFrom extends string, KTo extends string> = {
|
|
|
14
16
|
from: KFrom;
|
|
15
17
|
to: KTo;
|
|
16
18
|
};
|
|
17
|
-
export type ModifyColumnOp<K extends string, T extends DataTypeExpression> = {
|
|
19
|
+
export type ModifyColumnOp<K extends string, T extends DataTypeExpression, TDescriptor extends ColumnDescriptor> = {
|
|
18
20
|
op: "modifyColumn";
|
|
19
21
|
name: K;
|
|
20
22
|
type: T;
|
|
23
|
+
descriptor: TDescriptor;
|
|
21
24
|
};
|
|
22
25
|
export type Alteration = {
|
|
23
26
|
kind: "setDataType";
|
|
@@ -37,7 +40,7 @@ export type AlterColumnOp<K extends string, TAlteration extends Alteration> = {
|
|
|
37
40
|
name: K;
|
|
38
41
|
alteration: TAlteration;
|
|
39
42
|
};
|
|
40
|
-
export type AlterOperation = AddColumnOp<any, any> | DropColumnOp<any> | RenameColumnOp<any, any> | AlterColumnOp<any, any> | ModifyColumnOp<any, any>;
|
|
43
|
+
export type AlterOperation = AddColumnOp<any, any, any> | DropColumnOp<any> | RenameColumnOp<any, any> | AlterColumnOp<any, any> | ModifyColumnOp<any, any, any>;
|
|
41
44
|
export type SqlToTsType<T extends string | typeof sql> = T extends "text" ? string : T extends "integer" ? number : T extends "blob" ? Uint8Array : T extends "real" ? number : T extends "boolean" ? boolean : T extends typeof sql ? any : never;
|
|
42
45
|
export type Prettify<T> = {
|
|
43
46
|
[K in keyof T]: T[K];
|
|
@@ -57,17 +60,64 @@ export type Cast<A, B> = A extends B ? A : B;
|
|
|
57
60
|
/**
|
|
58
61
|
* Applies a single alteration operation to a schema.
|
|
59
62
|
*/
|
|
60
|
-
type ApplyOp<TSchema, THeadOp> = THeadOp extends AddColumnOp<infer K, infer
|
|
61
|
-
[P in K]:
|
|
63
|
+
type ApplyOp<TSchema, THeadOp> = THeadOp extends AddColumnOp<infer K, any, infer TDescriptor> ? Prettify<TSchema & {
|
|
64
|
+
[P in K]: TDescriptor;
|
|
62
65
|
}> : THeadOp extends DropColumnOp<infer K> ? Omit<TSchema, K> : THeadOp extends RenameColumnOp<infer KFrom, infer KTo> ? KFrom extends keyof TSchema ? Prettify<Omit<TSchema, KFrom> & {
|
|
63
66
|
[P in KTo]: TSchema[KFrom];
|
|
64
|
-
}> : TSchema : THeadOp extends AlterColumnOp<infer K, infer TAlt> ? TAlt extends {
|
|
67
|
+
}> : TSchema : THeadOp extends AlterColumnOp<infer K, infer TAlt> ? K extends keyof TSchema ? TAlt extends {
|
|
65
68
|
kind: "setDataType";
|
|
66
69
|
dataType: infer DT extends string;
|
|
67
70
|
} ? Prettify<Omit<TSchema, K> & {
|
|
68
|
-
[P in K]:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
[P in K]: {
|
|
72
|
+
tsType: SqlToTsType<DT>;
|
|
73
|
+
isNullable: TSchema[K] extends {
|
|
74
|
+
isNullable: infer N;
|
|
75
|
+
} ? N : true;
|
|
76
|
+
hasDefault: TSchema[K] extends {
|
|
77
|
+
hasDefault: infer D;
|
|
78
|
+
} ? D : false;
|
|
79
|
+
isAutoIncrement: TSchema[K] extends {
|
|
80
|
+
isAutoIncrement: infer A;
|
|
81
|
+
} ? A : false;
|
|
82
|
+
};
|
|
83
|
+
}> : TAlt extends {
|
|
84
|
+
kind: "setDefault";
|
|
85
|
+
} ? Prettify<Omit<TSchema, K> & {
|
|
86
|
+
[P in K]: TSchema[K] extends ColumnDescriptor ? {
|
|
87
|
+
tsType: TSchema[K]["tsType"];
|
|
88
|
+
isNullable: false;
|
|
89
|
+
hasDefault: true;
|
|
90
|
+
isAutoIncrement: TSchema[K]["isAutoIncrement"];
|
|
91
|
+
} : TSchema[K];
|
|
92
|
+
}> : TAlt extends {
|
|
93
|
+
kind: "dropDefault";
|
|
94
|
+
} ? Prettify<Omit<TSchema, K> & {
|
|
95
|
+
[P in K]: TSchema[K] extends ColumnDescriptor ? {
|
|
96
|
+
tsType: TSchema[K]["tsType"];
|
|
97
|
+
isNullable: TSchema[K]["isNullable"];
|
|
98
|
+
hasDefault: false;
|
|
99
|
+
isAutoIncrement: TSchema[K]["isAutoIncrement"];
|
|
100
|
+
} : TSchema[K];
|
|
101
|
+
}> : TAlt extends {
|
|
102
|
+
kind: "setNotNull";
|
|
103
|
+
} ? Prettify<Omit<TSchema, K> & {
|
|
104
|
+
[P in K]: TSchema[K] extends ColumnDescriptor ? {
|
|
105
|
+
tsType: TSchema[K]["tsType"];
|
|
106
|
+
isNullable: false;
|
|
107
|
+
hasDefault: TSchema[K]["hasDefault"];
|
|
108
|
+
isAutoIncrement: TSchema[K]["isAutoIncrement"];
|
|
109
|
+
} : TSchema[K];
|
|
110
|
+
}> : TAlt extends {
|
|
111
|
+
kind: "dropNotNull";
|
|
112
|
+
} ? Prettify<Omit<TSchema, K> & {
|
|
113
|
+
[P in K]: TSchema[K] extends ColumnDescriptor ? {
|
|
114
|
+
tsType: TSchema[K]["tsType"];
|
|
115
|
+
isNullable: true;
|
|
116
|
+
hasDefault: TSchema[K]["hasDefault"];
|
|
117
|
+
isAutoIncrement: TSchema[K]["isAutoIncrement"];
|
|
118
|
+
} : TSchema[K];
|
|
119
|
+
}> : TSchema : TSchema : THeadOp extends ModifyColumnOp<infer K, any, infer TDescriptor> ? Prettify<Omit<TSchema, K> & {
|
|
120
|
+
[P in K]: TDescriptor;
|
|
71
121
|
}> : TSchema;
|
|
72
122
|
/**
|
|
73
123
|
* Recursively processes a list of alteration operations (AST)
|