@xata.io/drizzle 0.0.0-alpha.vcf8f11cade1aeb5e318fc16f42ddc96e46b17b8e → 0.0.0-alpha.vcfd6a67de8fbe1990b37c436166fb2bdce576c79
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/.turbo/turbo-build.log +16 -5
- package/CHANGELOG.md +51 -3
- package/dist/index.cjs +54 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.mjs +56 -43
- package/dist/index.mjs.map +1 -1
- package/dist/pg.cjs +212 -0
- package/dist/pg.cjs.map +1 -0
- package/dist/pg.d.ts +61 -0
- package/dist/pg.mjs +206 -0
- package/dist/pg.mjs.map +1 -0
- package/package.json +11 -6
- package/test/{pg.test.ts → drizzle.test.ts} +273 -264
@@ -1,6 +1,6 @@
|
|
1
1
|
import { BaseClient, HostProvider, parseProviderString, XataApiClient } from '@xata.io/client';
|
2
2
|
import 'dotenv/config';
|
3
|
-
import { desc, eq, gt, gte, or, placeholder, sql
|
3
|
+
import { desc, DrizzleError, eq, gt, gte, or, placeholder, sql } from 'drizzle-orm';
|
4
4
|
import { Client } from 'pg';
|
5
5
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expectTypeOf, test } from 'vitest';
|
6
6
|
import { drizzle as drizzlePg, type XataDatabase } from '../src/pg';
|
@@ -9,7 +9,7 @@ import * as schema from './schema';
|
|
9
9
|
|
10
10
|
const { usersTable, postsTable, commentsTable, usersToGroupsTable, groupsTable } = schema;
|
11
11
|
|
12
|
-
const ENABLE_LOGGING =
|
12
|
+
const ENABLE_LOGGING = false;
|
13
13
|
|
14
14
|
declare module 'vitest' {
|
15
15
|
export interface TestContext {
|
@@ -25,10 +25,13 @@ if (apiKey === '') throw new Error('XATA_API_KEY environment variable is not set
|
|
25
25
|
const workspace = (process.env.XATA_WORKSPACE ?? '').split('-').pop() ?? '';
|
26
26
|
if (workspace === '') throw new Error('XATA_WORKSPACE environment variable is not set');
|
27
27
|
|
28
|
-
const region = process.env.XATA_REGION || 'eu-west-1';
|
29
|
-
|
30
28
|
const host = parseProviderString(process.env.XATA_API_PROVIDER) ?? 'production';
|
31
29
|
|
30
|
+
// TODO: Branches for pgroll only work in some regions for now
|
31
|
+
// const region = process.env.XATA_REGION || 'us-east-1';
|
32
|
+
const region =
|
33
|
+
host === 'production' ? 'us-east-1' : host === 'staging' ? 'eu-west-1' : process.env.XATA_REGION || 'us-east-1';
|
34
|
+
|
32
35
|
const database = `drizzle-test-${Math.random().toString(36).substring(7)}`;
|
33
36
|
|
34
37
|
const api = new XataApiClient({ apiKey, host, clientName: 'sdk-tests' });
|
@@ -48,27 +51,49 @@ function getDomain(host: HostProvider) {
|
|
48
51
|
}
|
49
52
|
}
|
50
53
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
function getDrizzleClient(type: string, database: string, branch: string) {
|
55
|
+
if (type === 'http') {
|
56
|
+
const xata = new BaseClient({
|
57
|
+
apiKey,
|
58
|
+
host,
|
59
|
+
clientName: 'sdk-tests',
|
60
|
+
databaseURL: `https://${workspace}.${region}.${getDomain(host)}/db/${database}`,
|
61
|
+
branch
|
62
|
+
});
|
58
63
|
|
59
|
-
|
64
|
+
return { db: drizzleHttp(xata, { schema, logger: ENABLE_LOGGING }) };
|
65
|
+
} else if (type === 'pg') {
|
66
|
+
const client = new Client({
|
67
|
+
connectionString: `postgresql://${workspace}:${apiKey}@${region}.sql.${getDomain(
|
68
|
+
host
|
69
|
+
)}:5432/${database}:${branch}`,
|
70
|
+
ssl: true
|
71
|
+
});
|
60
72
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
return { db: drizzlePg(client, { schema, logger: ENABLE_LOGGING }), client };
|
74
|
+
} else {
|
75
|
+
throw new Error(`Unknown type: ${type}`);
|
76
|
+
}
|
77
|
+
}
|
66
78
|
|
67
|
-
|
68
|
-
const
|
79
|
+
describe.concurrent.each([{ type: 'pg' }, { type: 'http' }])('Drizzle $type', ({ type }) => {
|
80
|
+
const dbName = `${database}-${type}`;
|
69
81
|
|
70
|
-
|
71
|
-
|
82
|
+
beforeAll(async () => {
|
83
|
+
await api.databases.createDatabase({
|
84
|
+
pathParams: { workspaceId: workspace, dbName },
|
85
|
+
body: { region, branchName: 'main' },
|
86
|
+
headers: { 'X-Features': 'feat-pgroll-migrations=1' }
|
87
|
+
});
|
88
|
+
|
89
|
+
await waitForReplication(dbName);
|
90
|
+
|
91
|
+
// For now, run the migrations via wire protocol
|
92
|
+
const { client, db } = getDrizzleClient('pg', dbName, 'main');
|
93
|
+
await client?.connect();
|
94
|
+
|
95
|
+
await db.execute(
|
96
|
+
sql`
|
72
97
|
CREATE TABLE "users" (
|
73
98
|
"id" serial PRIMARY KEY NOT NULL,
|
74
99
|
"name" text NOT NULL,
|
@@ -76,27 +101,27 @@ beforeAll(async () => {
|
|
76
101
|
"invited_by" int REFERENCES "users"("id")
|
77
102
|
);
|
78
103
|
`
|
79
|
-
|
80
|
-
|
81
|
-
|
104
|
+
);
|
105
|
+
await db.execute(
|
106
|
+
sql`
|
82
107
|
CREATE TABLE IF NOT EXISTS "groups" (
|
83
108
|
"id" serial PRIMARY KEY NOT NULL,
|
84
109
|
"name" text NOT NULL,
|
85
110
|
"description" text
|
86
111
|
);
|
87
112
|
`
|
88
|
-
|
89
|
-
|
90
|
-
|
113
|
+
);
|
114
|
+
await db.execute(
|
115
|
+
sql`
|
91
116
|
CREATE TABLE IF NOT EXISTS "users_to_groups" (
|
92
117
|
"id" serial PRIMARY KEY NOT NULL,
|
93
118
|
"user_id" int REFERENCES "users"("id"),
|
94
119
|
"group_id" int REFERENCES "groups"("id")
|
95
120
|
);
|
96
121
|
`
|
97
|
-
|
98
|
-
|
99
|
-
|
122
|
+
);
|
123
|
+
await db.execute(
|
124
|
+
sql`
|
100
125
|
CREATE TABLE IF NOT EXISTS "posts" (
|
101
126
|
"id" serial PRIMARY KEY NOT NULL,
|
102
127
|
"content" text NOT NULL,
|
@@ -104,9 +129,9 @@ beforeAll(async () => {
|
|
104
129
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
105
130
|
);
|
106
131
|
`
|
107
|
-
|
108
|
-
|
109
|
-
|
132
|
+
);
|
133
|
+
await db.execute(
|
134
|
+
sql`
|
110
135
|
CREATE TABLE IF NOT EXISTS "comments" (
|
111
136
|
"id" serial PRIMARY KEY NOT NULL,
|
112
137
|
"content" text NOT NULL,
|
@@ -115,9 +140,9 @@ beforeAll(async () => {
|
|
115
140
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
116
141
|
);
|
117
142
|
`
|
118
|
-
|
119
|
-
|
120
|
-
|
143
|
+
);
|
144
|
+
await db.execute(
|
145
|
+
sql`
|
121
146
|
CREATE TABLE IF NOT EXISTS "comment_likes" (
|
122
147
|
"id" serial PRIMARY KEY NOT NULL,
|
123
148
|
"creator" int REFERENCES "users"("id"),
|
@@ -125,49 +150,32 @@ beforeAll(async () => {
|
|
125
150
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
126
151
|
);
|
127
152
|
`
|
128
|
-
|
153
|
+
);
|
129
154
|
|
130
|
-
|
131
|
-
});
|
155
|
+
await client?.end();
|
156
|
+
});
|
132
157
|
|
133
|
-
afterAll(async () => {
|
134
|
-
|
135
|
-
});
|
158
|
+
afterAll(async () => {
|
159
|
+
await api.databases.deleteDatabase({ pathParams: { workspaceId: workspace, dbName } });
|
160
|
+
});
|
136
161
|
|
137
|
-
describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type', ({ type }) => {
|
138
162
|
beforeEach(async (ctx) => {
|
139
163
|
ctx.branch = `test-${Math.random().toString(36).substring(7)}`;
|
140
|
-
await api.
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
ctx.db = drizzleHttp(xata, { schema, logger: ENABLE_LOGGING });
|
152
|
-
} else if (type === 'pg') {
|
153
|
-
ctx.client = new Client({
|
154
|
-
connectionString: `postgresql://${workspace}:${apiKey}@${region}.sql.${getDomain(host)}:5432/${database}:${
|
155
|
-
ctx.branch
|
156
|
-
}`,
|
157
|
-
// Not sure why, but we are getting `error: SSL required` sometimes
|
158
|
-
ssl: { rejectUnauthorized: false }
|
159
|
-
});
|
160
|
-
|
161
|
-
await ctx.client.connect();
|
162
|
-
ctx.db = drizzlePg(ctx.client, { schema, logger: ENABLE_LOGGING });
|
163
|
-
} else {
|
164
|
-
throw new Error(`Unknown type: ${type}`);
|
165
|
-
}
|
164
|
+
await api.branch.createBranch({
|
165
|
+
pathParams: { workspace, region, dbBranchName: `${dbName}:${ctx.branch}` },
|
166
|
+
body: { from: 'main' }
|
167
|
+
});
|
168
|
+
|
169
|
+
const { db, client } = getDrizzleClient(type, dbName, ctx.branch);
|
170
|
+
await client?.connect();
|
171
|
+
|
172
|
+
ctx.db = db;
|
173
|
+
ctx.client = client;
|
166
174
|
});
|
167
175
|
|
168
176
|
afterEach(async (ctx) => {
|
169
177
|
await ctx.client?.end();
|
170
|
-
await api.
|
178
|
+
await api.branch.deleteBranch({ pathParams: { workspace, region, dbBranchName: `${dbName}:${ctx.branch}` } });
|
171
179
|
});
|
172
180
|
|
173
181
|
/*
|
@@ -887,133 +895,6 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
887
895
|
});
|
888
896
|
});
|
889
897
|
|
890
|
-
test.skip('[Find Many] Get users with posts in transaction', async (ctx) => {
|
891
|
-
let usersWithPosts: {
|
892
|
-
id: number;
|
893
|
-
name: string;
|
894
|
-
verified: boolean;
|
895
|
-
invitedBy: number | null;
|
896
|
-
posts: {
|
897
|
-
id: number;
|
898
|
-
content: string;
|
899
|
-
ownerId: number | null;
|
900
|
-
createdAt: Date;
|
901
|
-
}[];
|
902
|
-
}[] = [];
|
903
|
-
|
904
|
-
await ctx.db.transaction(async (tx) => {
|
905
|
-
await tx.insert(usersTable).values([
|
906
|
-
{ id: 1, name: 'Dan' },
|
907
|
-
{ id: 2, name: 'Andrew' },
|
908
|
-
{ id: 3, name: 'Alex' }
|
909
|
-
]);
|
910
|
-
|
911
|
-
await tx.insert(postsTable).values([
|
912
|
-
{ ownerId: 1, content: 'Post1' },
|
913
|
-
{ ownerId: 1, content: 'Post1.1' },
|
914
|
-
{ ownerId: 2, content: 'Post2' },
|
915
|
-
{ ownerId: 3, content: 'Post3' }
|
916
|
-
]);
|
917
|
-
|
918
|
-
usersWithPosts = await tx.query.usersTable.findMany({
|
919
|
-
where: ({ id }, { eq }) => eq(id, 1),
|
920
|
-
with: {
|
921
|
-
posts: {
|
922
|
-
where: ({ id }, { eq }) => eq(id, 1)
|
923
|
-
}
|
924
|
-
}
|
925
|
-
});
|
926
|
-
});
|
927
|
-
|
928
|
-
expectTypeOf(usersWithPosts).toEqualTypeOf<
|
929
|
-
{
|
930
|
-
id: number;
|
931
|
-
name: string;
|
932
|
-
verified: boolean;
|
933
|
-
invitedBy: number | null;
|
934
|
-
posts: {
|
935
|
-
id: number;
|
936
|
-
content: string;
|
937
|
-
ownerId: number | null;
|
938
|
-
createdAt: Date;
|
939
|
-
}[];
|
940
|
-
}[]
|
941
|
-
>();
|
942
|
-
|
943
|
-
ctx.expect(usersWithPosts.length).eq(1);
|
944
|
-
ctx.expect(usersWithPosts[0]?.posts.length).eq(1);
|
945
|
-
|
946
|
-
ctx.expect(usersWithPosts[0]).toEqual({
|
947
|
-
id: 1,
|
948
|
-
name: 'Dan',
|
949
|
-
verified: false,
|
950
|
-
invitedBy: null,
|
951
|
-
posts: [{ id: 1, ownerId: 1, content: 'Post1', createdAt: usersWithPosts[0]?.posts[0]?.createdAt }]
|
952
|
-
});
|
953
|
-
});
|
954
|
-
|
955
|
-
test.skip('[Find Many] Get users with posts in rollbacked transaction', async (ctx) => {
|
956
|
-
let usersWithPosts: {
|
957
|
-
id: number;
|
958
|
-
name: string;
|
959
|
-
verified: boolean;
|
960
|
-
invitedBy: number | null;
|
961
|
-
posts: {
|
962
|
-
id: number;
|
963
|
-
content: string;
|
964
|
-
ownerId: number | null;
|
965
|
-
createdAt: Date;
|
966
|
-
}[];
|
967
|
-
}[] = [];
|
968
|
-
|
969
|
-
await ctx
|
970
|
-
.expect(
|
971
|
-
ctx.db.transaction(async (tx) => {
|
972
|
-
await tx.insert(usersTable).values([
|
973
|
-
{ id: 1, name: 'Dan' },
|
974
|
-
{ id: 2, name: 'Andrew' },
|
975
|
-
{ id: 3, name: 'Alex' }
|
976
|
-
]);
|
977
|
-
|
978
|
-
await tx.insert(postsTable).values([
|
979
|
-
{ ownerId: 1, content: 'Post1' },
|
980
|
-
{ ownerId: 1, content: 'Post1.1' },
|
981
|
-
{ ownerId: 2, content: 'Post2' },
|
982
|
-
{ ownerId: 3, content: 'Post3' }
|
983
|
-
]);
|
984
|
-
|
985
|
-
tx.rollback();
|
986
|
-
|
987
|
-
usersWithPosts = await tx.query.usersTable.findMany({
|
988
|
-
where: ({ id }, { eq }) => eq(id, 1),
|
989
|
-
with: {
|
990
|
-
posts: {
|
991
|
-
where: ({ id }, { eq }) => eq(id, 1)
|
992
|
-
}
|
993
|
-
}
|
994
|
-
});
|
995
|
-
})
|
996
|
-
)
|
997
|
-
.rejects.toThrowError(new TransactionRollbackError());
|
998
|
-
|
999
|
-
expectTypeOf(usersWithPosts).toEqualTypeOf<
|
1000
|
-
{
|
1001
|
-
id: number;
|
1002
|
-
name: string;
|
1003
|
-
verified: boolean;
|
1004
|
-
invitedBy: number | null;
|
1005
|
-
posts: {
|
1006
|
-
id: number;
|
1007
|
-
content: string;
|
1008
|
-
ownerId: number | null;
|
1009
|
-
createdAt: Date;
|
1010
|
-
}[];
|
1011
|
-
}[]
|
1012
|
-
>();
|
1013
|
-
|
1014
|
-
ctx.expect(usersWithPosts.length).eq(0);
|
1015
|
-
});
|
1016
|
-
|
1017
898
|
// select only custom
|
1018
899
|
test('[Find Many] Get only custom fields', async (ctx) => {
|
1019
900
|
await ctx.db.insert(usersTable).values([
|
@@ -1330,7 +1211,7 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1330
1211
|
columns: {},
|
1331
1212
|
where: gte(postsTable.id, 2),
|
1332
1213
|
extras: ({ content }) => ({
|
1333
|
-
|
1214
|
+
contentLower: sql<string>`lower(${content})`.as('content_lower')
|
1334
1215
|
})
|
1335
1216
|
}
|
1336
1217
|
},
|
@@ -1344,7 +1225,7 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1344
1225
|
| {
|
1345
1226
|
lowerName: string;
|
1346
1227
|
posts: {
|
1347
|
-
|
1228
|
+
contentLower: string;
|
1348
1229
|
}[];
|
1349
1230
|
}
|
1350
1231
|
| undefined
|
@@ -1354,7 +1235,7 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1354
1235
|
|
1355
1236
|
ctx.expect(usersWithPosts).toEqual({
|
1356
1237
|
lowerName: 'dan',
|
1357
|
-
posts: [{
|
1238
|
+
posts: [{ contentLower: 'post1.2' }, { contentLower: 'post1.3' }]
|
1358
1239
|
});
|
1359
1240
|
});
|
1360
1241
|
|
@@ -1465,41 +1346,43 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1465
1346
|
});
|
1466
1347
|
|
1467
1348
|
// columns {}
|
1468
|
-
test
|
1349
|
+
test('[Find Many] Get select {}', async (ctx) => {
|
1469
1350
|
await ctx.db.insert(usersTable).values([
|
1470
1351
|
{ id: 1, name: 'Dan' },
|
1471
1352
|
{ id: 2, name: 'Andrew' },
|
1472
1353
|
{ id: 3, name: 'Alex' }
|
1473
1354
|
]);
|
1474
1355
|
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
ctx.expect(users[2]).toEqual({});
|
1356
|
+
await ctx
|
1357
|
+
.expect(
|
1358
|
+
async () =>
|
1359
|
+
await ctx.db.query.usersTable.findMany({
|
1360
|
+
columns: {}
|
1361
|
+
})
|
1362
|
+
)
|
1363
|
+
.rejects.toThrow(DrizzleError);
|
1484
1364
|
});
|
1485
1365
|
|
1486
1366
|
// columns {}
|
1487
|
-
test
|
1367
|
+
test('[Find One] Get select {}', async (ctx) => {
|
1488
1368
|
await ctx.db.insert(usersTable).values([
|
1489
1369
|
{ id: 1, name: 'Dan' },
|
1490
1370
|
{ id: 2, name: 'Andrew' },
|
1491
1371
|
{ id: 3, name: 'Alex' }
|
1492
1372
|
]);
|
1493
1373
|
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1374
|
+
await ctx
|
1375
|
+
.expect(
|
1376
|
+
async () =>
|
1377
|
+
await ctx.db.query.usersTable.findFirst({
|
1378
|
+
columns: {}
|
1379
|
+
})
|
1380
|
+
)
|
1381
|
+
.rejects.toThrow(DrizzleError);
|
1499
1382
|
});
|
1500
1383
|
|
1501
1384
|
// deep select {}
|
1502
|
-
test
|
1385
|
+
test('[Find Many] Get deep select {}', async (ctx) => {
|
1503
1386
|
await ctx.db.insert(usersTable).values([
|
1504
1387
|
{ id: 1, name: 'Dan' },
|
1505
1388
|
{ id: 2, name: 'Andrew' },
|
@@ -1512,24 +1395,23 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1512
1395
|
{ ownerId: 3, content: 'Post3' }
|
1513
1396
|
]);
|
1514
1397
|
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
ctx.expect(users[2]).toEqual({ posts: [{}] });
|
1398
|
+
await ctx
|
1399
|
+
.expect(
|
1400
|
+
async () =>
|
1401
|
+
await ctx.db.query.usersTable.findMany({
|
1402
|
+
columns: {},
|
1403
|
+
with: {
|
1404
|
+
posts: {
|
1405
|
+
columns: {}
|
1406
|
+
}
|
1407
|
+
}
|
1408
|
+
})
|
1409
|
+
)
|
1410
|
+
.rejects.toThrow(DrizzleError);
|
1529
1411
|
});
|
1530
1412
|
|
1531
1413
|
// deep select {}
|
1532
|
-
test
|
1414
|
+
test('[Find One] Get deep select {}', async (ctx) => {
|
1533
1415
|
await ctx.db.insert(usersTable).values([
|
1534
1416
|
{ id: 1, name: 'Dan' },
|
1535
1417
|
{ id: 2, name: 'Andrew' },
|
@@ -1542,16 +1424,19 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
1542
1424
|
{ ownerId: 3, content: 'Post3' }
|
1543
1425
|
]);
|
1544
1426
|
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1427
|
+
await ctx
|
1428
|
+
.expect(
|
1429
|
+
async () =>
|
1430
|
+
await ctx.db.query.usersTable.findFirst({
|
1431
|
+
columns: {},
|
1432
|
+
with: {
|
1433
|
+
posts: {
|
1434
|
+
columns: {}
|
1435
|
+
}
|
1436
|
+
}
|
1437
|
+
})
|
1438
|
+
)
|
1439
|
+
.rejects.toThrow(DrizzleError);
|
1555
1440
|
});
|
1556
1441
|
|
1557
1442
|
/*
|
@@ -4116,14 +4001,118 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
4116
4001
|
});
|
4117
4002
|
});
|
4118
4003
|
|
4004
|
+
test('Get user with posts and posts with comments and comments with owner where exists', async (ctx) => {
|
4005
|
+
await ctx.db.insert(usersTable).values([
|
4006
|
+
{ id: 1, name: 'Dan' },
|
4007
|
+
{ id: 2, name: 'Andrew' },
|
4008
|
+
{ id: 3, name: 'Alex' }
|
4009
|
+
]);
|
4010
|
+
|
4011
|
+
await ctx.db.insert(postsTable).values([
|
4012
|
+
{ id: 1, ownerId: 1, content: 'Post1' },
|
4013
|
+
{ id: 2, ownerId: 2, content: 'Post2' },
|
4014
|
+
{ id: 3, ownerId: 3, content: 'Post3' }
|
4015
|
+
]);
|
4016
|
+
|
4017
|
+
await ctx.db.insert(commentsTable).values([
|
4018
|
+
{ postId: 1, content: 'Comment1', creator: 2 },
|
4019
|
+
{ postId: 2, content: 'Comment2', creator: 2 },
|
4020
|
+
{ postId: 3, content: 'Comment3', creator: 3 }
|
4021
|
+
]);
|
4022
|
+
|
4023
|
+
const response = await ctx.db.query.usersTable.findMany({
|
4024
|
+
with: {
|
4025
|
+
posts: {
|
4026
|
+
with: {
|
4027
|
+
comments: {
|
4028
|
+
with: {
|
4029
|
+
author: true
|
4030
|
+
}
|
4031
|
+
}
|
4032
|
+
}
|
4033
|
+
}
|
4034
|
+
},
|
4035
|
+
where: (table, { exists, eq }) =>
|
4036
|
+
exists(
|
4037
|
+
ctx.db
|
4038
|
+
.select({ one: sql`1` })
|
4039
|
+
.from(usersTable)
|
4040
|
+
.where(eq(sql`1`, table.id))
|
4041
|
+
)
|
4042
|
+
});
|
4043
|
+
|
4044
|
+
expectTypeOf(response).toEqualTypeOf<
|
4045
|
+
{
|
4046
|
+
id: number;
|
4047
|
+
name: string;
|
4048
|
+
verified: boolean;
|
4049
|
+
invitedBy: number | null;
|
4050
|
+
posts: {
|
4051
|
+
id: number;
|
4052
|
+
content: string;
|
4053
|
+
ownerId: number | null;
|
4054
|
+
createdAt: Date;
|
4055
|
+
comments: {
|
4056
|
+
id: number;
|
4057
|
+
content: string;
|
4058
|
+
createdAt: Date;
|
4059
|
+
creator: number | null;
|
4060
|
+
postId: number | null;
|
4061
|
+
author: {
|
4062
|
+
id: number;
|
4063
|
+
name: string;
|
4064
|
+
verified: boolean;
|
4065
|
+
invitedBy: number | null;
|
4066
|
+
} | null;
|
4067
|
+
}[];
|
4068
|
+
}[];
|
4069
|
+
}[]
|
4070
|
+
>();
|
4071
|
+
|
4072
|
+
ctx.expect(response.length).eq(1);
|
4073
|
+
ctx.expect(response[0]?.posts.length).eq(1);
|
4074
|
+
|
4075
|
+
ctx.expect(response[0]?.posts[0]?.comments.length).eq(1);
|
4076
|
+
|
4077
|
+
ctx.expect(response[0]).toEqual({
|
4078
|
+
id: 1,
|
4079
|
+
name: 'Dan',
|
4080
|
+
verified: false,
|
4081
|
+
invitedBy: null,
|
4082
|
+
posts: [
|
4083
|
+
{
|
4084
|
+
id: 1,
|
4085
|
+
ownerId: 1,
|
4086
|
+
content: 'Post1',
|
4087
|
+
createdAt: response[0]?.posts[0]?.createdAt,
|
4088
|
+
comments: [
|
4089
|
+
{
|
4090
|
+
id: 1,
|
4091
|
+
content: 'Comment1',
|
4092
|
+
creator: 2,
|
4093
|
+
author: {
|
4094
|
+
id: 2,
|
4095
|
+
name: 'Andrew',
|
4096
|
+
verified: false,
|
4097
|
+
invitedBy: null
|
4098
|
+
},
|
4099
|
+
postId: 1,
|
4100
|
+
createdAt: response[0]?.posts[0]?.comments[0]?.createdAt
|
4101
|
+
}
|
4102
|
+
]
|
4103
|
+
}
|
4104
|
+
]
|
4105
|
+
});
|
4106
|
+
});
|
4107
|
+
|
4119
4108
|
/*
|
4120
|
-
One three-level relation + 1 first-level
|
4109
|
+
One three-level relation + 1 first-level relation
|
4121
4110
|
1. users+posts+comments+comment_owner
|
4122
4111
|
2. users+users
|
4123
4112
|
*/
|
4124
4113
|
|
4125
4114
|
/*
|
4126
|
-
One four-level relation users+posts+comments+
|
4115
|
+
One four-level relation users+posts+comments+comment_likes
|
4127
4116
|
*/
|
4128
4117
|
|
4129
4118
|
/*
|
@@ -4158,9 +4147,11 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
4158
4147
|
columns: {},
|
4159
4148
|
with: {
|
4160
4149
|
group: true
|
4161
|
-
}
|
4150
|
+
},
|
4151
|
+
orderBy: usersToGroupsTable.userId
|
4162
4152
|
}
|
4163
|
-
}
|
4153
|
+
},
|
4154
|
+
orderBy: usersTable.id
|
4164
4155
|
});
|
4165
4156
|
|
4166
4157
|
expectTypeOf(response).toEqualTypeOf<
|
@@ -4224,22 +4215,22 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
4224
4215
|
name: 'Alex',
|
4225
4216
|
verified: false,
|
4226
4217
|
invitedBy: null,
|
4227
|
-
usersToGroups: [
|
4218
|
+
usersToGroups: ctx.expect.arrayContaining([
|
4228
4219
|
{
|
4229
4220
|
group: {
|
4230
|
-
id:
|
4231
|
-
name: '
|
4221
|
+
id: 2,
|
4222
|
+
name: 'Group2',
|
4232
4223
|
description: null
|
4233
4224
|
}
|
4234
4225
|
},
|
4235
4226
|
{
|
4236
4227
|
group: {
|
4237
|
-
id:
|
4238
|
-
name: '
|
4228
|
+
id: 3,
|
4229
|
+
name: 'Group3',
|
4239
4230
|
description: null
|
4240
4231
|
}
|
4241
4232
|
}
|
4242
|
-
]
|
4233
|
+
])
|
4243
4234
|
});
|
4244
4235
|
});
|
4245
4236
|
|
@@ -6035,7 +6026,8 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
6035
6026
|
lower: sql<string>`lower(${groupsTable.name})`.as('lower_name')
|
6036
6027
|
}
|
6037
6028
|
}
|
6038
|
-
}
|
6029
|
+
},
|
6030
|
+
orderBy: usersToGroupsTable.groupId
|
6039
6031
|
}
|
6040
6032
|
}
|
6041
6033
|
});
|
@@ -6111,17 +6103,17 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
6111
6103
|
usersToGroups: [
|
6112
6104
|
{
|
6113
6105
|
group: {
|
6114
|
-
id:
|
6115
|
-
name: '
|
6116
|
-
lower: '
|
6106
|
+
id: 2,
|
6107
|
+
name: 'Group2',
|
6108
|
+
lower: 'group2',
|
6117
6109
|
description: null
|
6118
6110
|
}
|
6119
6111
|
},
|
6120
6112
|
{
|
6121
6113
|
group: {
|
6122
|
-
id:
|
6123
|
-
name: '
|
6124
|
-
lower: '
|
6114
|
+
id: 3,
|
6115
|
+
name: 'Group3',
|
6116
|
+
lower: 'group3',
|
6125
6117
|
description: null
|
6126
6118
|
}
|
6127
6119
|
}
|
@@ -6257,6 +6249,23 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
6257
6249
|
});
|
6258
6250
|
});
|
6259
6251
|
|
6252
|
+
test('Filter by columns not present in select', async (ctx) => {
|
6253
|
+
await ctx.db.insert(usersTable).values([
|
6254
|
+
{ id: 1, name: 'Dan' },
|
6255
|
+
{ id: 2, name: 'Andrew' },
|
6256
|
+
{ id: 3, name: 'Alex' }
|
6257
|
+
]);
|
6258
|
+
|
6259
|
+
const response = await ctx.db.query.usersTable.findFirst({
|
6260
|
+
columns: {
|
6261
|
+
id: true
|
6262
|
+
},
|
6263
|
+
where: eq(usersTable.name, 'Dan')
|
6264
|
+
});
|
6265
|
+
|
6266
|
+
ctx.expect(response).toEqual({ id: 1 });
|
6267
|
+
});
|
6268
|
+
|
6260
6269
|
test('.toSQL()', (ctx) => {
|
6261
6270
|
const query = ctx.db.query.usersTable.findFirst().toSQL();
|
6262
6271
|
|
@@ -6277,12 +6286,12 @@ describe.concurrent.each([{ type: 'pg' } /**{ type: 'http' }**/])('Drizzle $type
|
|
6277
6286
|
});
|
6278
6287
|
});
|
6279
6288
|
|
6280
|
-
async function waitForReplication(): Promise<void> {
|
6289
|
+
async function waitForReplication(dbName: string): Promise<void> {
|
6281
6290
|
try {
|
6282
|
-
await api.branches.getBranchList({ workspace, database, region });
|
6283
|
-
} catch (error) {
|
6284
|
-
console.log(`Waiting for create database replication to finish...`);
|
6285
6291
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
6286
|
-
|
6292
|
+
await api.branch.getBranchList({ pathParams: { workspace, dbName, region } });
|
6293
|
+
} catch (error) {
|
6294
|
+
console.log(`Replication not ready yet, retrying...`);
|
6295
|
+
return await waitForReplication(dbName);
|
6287
6296
|
}
|
6288
6297
|
}
|