quickbase-js 0.1.0-beta.8 → 0.1.0-beta.9
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/CHANGELOG.md +29 -0
- package/README.md +46 -130
- package/dist/esm/quickbase.d.ts +822 -119
- package/dist/esm/quickbase.js +373 -236
- package/dist/esm/quickbase.js.map +1 -1
- package/dist/esm/quickbase.min.js +1 -1
- package/dist/esm/quickbase.min.js.map +1 -1
- package/dist/umd/quickbase.umd.js +373 -236
- package/dist/umd/quickbase.umd.js.map +1 -1
- package/dist/umd/quickbase.umd.min.js +1 -1
- package/dist/umd/quickbase.umd.min.js.map +1 -1
- package/open-api/generate-unified-interface.ts +97 -17
- package/open-api/utils/generateJsDoc.ts +96 -0
- package/package.json +3 -1
- package/src/ThrottleBucket.ts +17 -12
- package/src/authorizationStrategy.ts +246 -0
- package/src/generated-unified/QuickbaseClient.ts +809 -119
- package/src/invokeMethod.ts +150 -265
- package/src/quickbaseClient.ts +85 -58
- package/src/rateLimiter.ts +25 -0
- package/src/tokenCache.ts +10 -26
- package/tests/vitest/qb/auth/mockQuickbaseServer.ts +60 -0
- package/tests/vitest/qb/auth/retryUserToken401.test.ts +59 -42
- package/tests/vitest/qb/auth/ssoTokenIntegrationWithServer.test.ts +65 -0
- package/tests/vitest/qb/fields/getFieldUsage.test.ts +58 -150
- package/tests/vitest/qb/formulas/runFormula.test.ts +96 -0
- package/tests/vitest/qb/tables/createRelationship.test.ts +102 -0
- package/tests/vitest/qb/tables/deleteRelationship.test.ts +143 -0
- package/tests/vitest/qb/tables/updateRelationship.test.ts +118 -145
- package/tests/vitest/unit/ThrottleBucket.test.ts +95 -0
- package/tests/vitest/unit/apps/copyApp.test.ts +133 -40
- package/tests/vitest/unit/apps/updateApp.test.ts +42 -11
- package/tests/vitest/unit/auth/fetchTempToken401.test.ts +3 -2
- package/tests/vitest/unit/auth/getTempToken.test.ts +42 -18
- package/tests/vitest/unit/auth/retryTempToken401.test.ts +46 -64
- package/tests/vitest/unit/auth/retryTempTokenMaxRetries.test.ts +235 -0
- package/tests/vitest/unit/auth/retryUserToken401.test.ts +56 -43
- package/tests/vitest/unit/auth/ssoTokenRefresh.test.ts +325 -0
- package/tests/vitest/unit/fields/createField.test.ts +180 -116
- package/tests/vitest/unit/fields/getFieldUsage.test.ts +17 -3
- package/tests/vitest/unit/fields/updateField.test.ts +12 -7
- package/tests/vitest/unit/formulas/runFormula.test.ts +205 -0
- package/tests/vitest/unit/index.ts +2 -1
- package/tests/vitest/unit/inferHttpMethod.test.ts +131 -0
- package/tests/vitest/unit/rateLimit.test.ts +4 -2
- package/tests/vitest/unit/tables/createRelationship.test.ts +212 -0
- package/tests/vitest/unit/tables/deleteRelationship.test.ts +97 -0
- package/tests/vitest/unit/tables/updateRelationship.test.ts +12 -10
- package/tests/vitest/unit/tokenLifespan.test.ts +149 -83
- package/tools/log-gen.ts +14 -5
- package/tools/log-gen.yaml +710 -268
- package/tests/vitest/unit/auth/retryTempTokenTwo401.test.ts +0 -81
package/tools/log-gen.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
project: >-
|
|
2
2
|
quickbase-js
|
|
3
3
|
date: >-
|
|
4
|
-
3/
|
|
4
|
+
3/19/2025
|
|
5
5
|
root: >-
|
|
6
6
|
/home/drew/Projects/quickbase-js
|
|
7
7
|
goals:
|
|
@@ -888,6 +888,10 @@ tree:
|
|
|
888
888
|
type: >-
|
|
889
889
|
directory
|
|
890
890
|
children:
|
|
891
|
+
- name: >-
|
|
892
|
+
generateJsDoc.ts
|
|
893
|
+
type: >-
|
|
894
|
+
file
|
|
891
895
|
- name: >-
|
|
892
896
|
infer-schema.ts
|
|
893
897
|
type: >-
|
|
@@ -929,6 +933,10 @@ tree:
|
|
|
929
933
|
ThrottleBucket.ts
|
|
930
934
|
type: >-
|
|
931
935
|
file
|
|
936
|
+
- name: >-
|
|
937
|
+
authorizationStrategy.ts
|
|
938
|
+
type: >-
|
|
939
|
+
file
|
|
932
940
|
- name: >-
|
|
933
941
|
generated
|
|
934
942
|
type: >-
|
|
@@ -1642,6 +1650,10 @@ tree:
|
|
|
1642
1650
|
quickbaseClient.ts
|
|
1643
1651
|
type: >-
|
|
1644
1652
|
file
|
|
1653
|
+
- name: >-
|
|
1654
|
+
rateLimiter.ts
|
|
1655
|
+
type: >-
|
|
1656
|
+
file
|
|
1645
1657
|
- name: >-
|
|
1646
1658
|
tokenCache.ts
|
|
1647
1659
|
type: >-
|
|
@@ -1675,6 +1687,10 @@ tree:
|
|
|
1675
1687
|
test-umd.js
|
|
1676
1688
|
type: >-
|
|
1677
1689
|
file
|
|
1690
|
+
- name: >-
|
|
1691
|
+
test.log
|
|
1692
|
+
type: >-
|
|
1693
|
+
file
|
|
1678
1694
|
- name: >-
|
|
1679
1695
|
test.ts
|
|
1680
1696
|
type: >-
|
|
@@ -2276,13 +2292,6 @@ tree:
|
|
|
2276
2292
|
from
|
|
2277
2293
|
"../../../../src/quickbaseClient";
|
|
2278
2294
|
|
|
2279
|
-
import
|
|
2280
|
-
{
|
|
2281
|
-
ResponseError
|
|
2282
|
-
}
|
|
2283
|
-
from
|
|
2284
|
-
"../../../../src/generated/runtime";
|
|
2285
|
-
|
|
2286
2295
|
|
|
2287
2296
|
describe("QuickbaseClient
|
|
2288
2297
|
Integration
|
|
@@ -2296,55 +2305,73 @@ tree:
|
|
|
2296
2305
|
=>
|
|
2297
2306
|
{
|
|
2298
2307
|
let client: QuickbaseClient;
|
|
2299
|
-
const mockFetch = vi.fn();
|
|
2300
2308
|
|
|
2301
2309
|
beforeEach(() => {
|
|
2310
|
+
const userToken = process.env.QB_USER_TOKEN;
|
|
2311
|
+
const realm = process.env.QB_REALM;
|
|
2312
|
+
const tableId = process.env.QB_TABLE_ID_1; // Consistent env var name
|
|
2313
|
+
|
|
2314
|
+
if (!userToken) {
|
|
2315
|
+
throw new Error(
|
|
2316
|
+
"QB_USER_TOKEN environment variable is required for integration test"
|
|
2317
|
+
);
|
|
2318
|
+
}
|
|
2319
|
+
if (!tableId) {
|
|
2320
|
+
throw new Error(
|
|
2321
|
+
"QB_TABLE_ID_1 environment variable is required for integration test"
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2302
2325
|
const config = {
|
|
2303
|
-
realm
|
|
2304
|
-
userToken
|
|
2326
|
+
realm,
|
|
2327
|
+
userToken,
|
|
2305
2328
|
debug: true,
|
|
2306
|
-
fetchApi: mockFetch,
|
|
2307
2329
|
};
|
|
2308
|
-
console.log("[quickbaseTest] Config:",
|
|
2330
|
+
console.log("[quickbaseTest] Config:", {
|
|
2331
|
+
realm,
|
|
2332
|
+
userToken: userToken.substring(0, 10) + "...",
|
|
2333
|
+
tableId, // Log to confirm
|
|
2334
|
+
debug: true,
|
|
2335
|
+
});
|
|
2309
2336
|
client = quickbase(config);
|
|
2310
2337
|
});
|
|
2311
2338
|
|
|
2312
|
-
it(
|
|
2313
|
-
|
|
2339
|
+
it(
|
|
2340
|
+
"successfully retrieves fields with user token, retrying on transient 401 if needed",
|
|
2341
|
+
async () => {
|
|
2342
|
+
const consoleSpy = vi.spyOn(console, "log");
|
|
2314
2343
|
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
})
|
|
2324
|
-
.mockResolvedValueOnce({
|
|
2325
|
-
ok: true,
|
|
2326
|
-
status: 200,
|
|
2327
|
-
json: async () => [{ id: 1, label: "Mock Field", fieldType: "text" }],
|
|
2328
|
-
});
|
|
2344
|
+
const tableId = process.env.QB_TABLE_ID_1!; // Match beforeEach
|
|
2345
|
+
let fields;
|
|
2346
|
+
try {
|
|
2347
|
+
fields = await client.getFields({ tableId });
|
|
2348
|
+
} catch (error) {
|
|
2349
|
+
console.error("[integrationTest] Failed to retrieve fields:", error);
|
|
2350
|
+
throw error;
|
|
2351
|
+
}
|
|
2329
2352
|
|
|
2330
|
-
|
|
2353
|
+
expect(fields).toBeInstanceOf(Array);
|
|
2354
|
+
expect(fields.length).toBeGreaterThan(0);
|
|
2355
|
+
expect(fields[0]).toHaveProperty("id");
|
|
2356
|
+
expect(fields[0]).toHaveProperty("label");
|
|
2331
2357
|
|
|
2332
|
-
|
|
2333
|
-
expect(fields.length).toBeGreaterThan(0);
|
|
2334
|
-
expect(fields[0]).toHaveProperty("id");
|
|
2335
|
-
expect(fields[0]).toHaveProperty("label");
|
|
2358
|
+
console.log("[integrationTest] Fields retrieved:", fields.length);
|
|
2336
2359
|
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2360
|
+
const retryLog = consoleSpy.mock.calls.some((call) =>
|
|
2361
|
+
call[0].includes("Retrying getFields with existing user token")
|
|
2362
|
+
);
|
|
2363
|
+
if (retryLog) {
|
|
2364
|
+
console.log("[integrationTest] Retry on 401 detected");
|
|
2365
|
+
} else {
|
|
2366
|
+
console.log(
|
|
2367
|
+
"[integrationTest] No 401 retries observed (expected if no transient failure)"
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2345
2370
|
|
|
2346
|
-
|
|
2347
|
-
|
|
2371
|
+
consoleSpy.mockRestore();
|
|
2372
|
+
},
|
|
2373
|
+
{ timeout: 10000 }
|
|
2374
|
+
);
|
|
2348
2375
|
});
|
|
2349
2376
|
- name: >-
|
|
2350
2377
|
fields
|
|
@@ -3378,6 +3405,138 @@ tree:
|
|
|
3378
3405
|
}
|
|
3379
3406
|
});
|
|
3380
3407
|
});
|
|
3408
|
+
- name: >-
|
|
3409
|
+
formulas
|
|
3410
|
+
type: >-
|
|
3411
|
+
directory
|
|
3412
|
+
children:
|
|
3413
|
+
- name: >-
|
|
3414
|
+
runFormula.test.ts
|
|
3415
|
+
type: >-
|
|
3416
|
+
file
|
|
3417
|
+
contents: >
|
|
3418
|
+
//
|
|
3419
|
+
tests/vitest/qb/formulas/runFormula.test.ts
|
|
3420
|
+
|
|
3421
|
+
|
|
3422
|
+
import
|
|
3423
|
+
{
|
|
3424
|
+
describe,
|
|
3425
|
+
it,
|
|
3426
|
+
expect,
|
|
3427
|
+
beforeAll,
|
|
3428
|
+
afterAll
|
|
3429
|
+
}
|
|
3430
|
+
from
|
|
3431
|
+
"vitest";
|
|
3432
|
+
|
|
3433
|
+
import
|
|
3434
|
+
{
|
|
3435
|
+
createClient,
|
|
3436
|
+
QB_REALM,
|
|
3437
|
+
QB_USER_TOKEN,
|
|
3438
|
+
QB_TABLE_ID_1,
|
|
3439
|
+
}
|
|
3440
|
+
from
|
|
3441
|
+
"@tests/setup.ts";
|
|
3442
|
+
|
|
3443
|
+
import
|
|
3444
|
+
{
|
|
3445
|
+
RunFormulaRequest,
|
|
3446
|
+
RunFormula200Response,
|
|
3447
|
+
Upsert200Response,
|
|
3448
|
+
}
|
|
3449
|
+
from
|
|
3450
|
+
"@/generated/models";
|
|
3451
|
+
|
|
3452
|
+
|
|
3453
|
+
describe("QuickbaseClient
|
|
3454
|
+
Integration
|
|
3455
|
+
-
|
|
3456
|
+
runFormula",
|
|
3457
|
+
()
|
|
3458
|
+
=>
|
|
3459
|
+
{
|
|
3460
|
+
let client: ReturnType<typeof createClient>;
|
|
3461
|
+
let testRecordId: number;
|
|
3462
|
+
|
|
3463
|
+
beforeAll(async () => {
|
|
3464
|
+
// Validate environment variables
|
|
3465
|
+
if (!QB_REALM) throw new Error("QB_REALM is not defined in .env");
|
|
3466
|
+
if (!QB_USER_TOKEN) throw new Error("QB_USER_TOKEN is not defined in .env");
|
|
3467
|
+
if (!QB_TABLE_ID_1) throw new Error("QB_TABLE_ID_1 is not defined in .env");
|
|
3468
|
+
|
|
3469
|
+
// Initialize client with user token only
|
|
3470
|
+
client = createClient(undefined, {
|
|
3471
|
+
realm: QB_REALM,
|
|
3472
|
+
userToken: QB_USER_TOKEN,
|
|
3473
|
+
debug: true,
|
|
3474
|
+
});
|
|
3475
|
+
|
|
3476
|
+
// Upsert a test record to ensure we have a valid rid
|
|
3477
|
+
const upsertResponse: Upsert200Response = await client.upsert({
|
|
3478
|
+
body: {
|
|
3479
|
+
to: QB_TABLE_ID_1,
|
|
3480
|
+
data: [
|
|
3481
|
+
{
|
|
3482
|
+
"6": { value: `Test Record ${Date.now()}` }, // Assuming field 6 is a text field (e.g., "Task Name")
|
|
3483
|
+
},
|
|
3484
|
+
],
|
|
3485
|
+
fieldsToReturn: [3], // Return Record ID# (field ID 3)
|
|
3486
|
+
},
|
|
3487
|
+
});
|
|
3488
|
+
|
|
3489
|
+
// Extract the created record ID
|
|
3490
|
+
testRecordId = upsertResponse.data[0]["3"].value as number;
|
|
3491
|
+
console.log(`Upserted test record with ID: ${testRecordId}`);
|
|
3492
|
+
});
|
|
3493
|
+
|
|
3494
|
+
afterAll(async () => {
|
|
3495
|
+
// Clean up the test record
|
|
3496
|
+
if (testRecordId) {
|
|
3497
|
+
await client.deleteRecords({
|
|
3498
|
+
body: {
|
|
3499
|
+
from: QB_TABLE_ID_1,
|
|
3500
|
+
where: `{3.EX.${testRecordId}}`, // Delete by Record ID#
|
|
3501
|
+
},
|
|
3502
|
+
});
|
|
3503
|
+
console.log(`Cleaned up test record with ID: ${testRecordId}`);
|
|
3504
|
+
}
|
|
3505
|
+
});
|
|
3506
|
+
|
|
3507
|
+
it("runs simple formula without rid and returns correct result", async () => {
|
|
3508
|
+
const request: RunFormulaRequest = {
|
|
3509
|
+
from: QB_TABLE_ID_1,
|
|
3510
|
+
formula: "1 + 1", // Simple arithmetic to verify functionality
|
|
3511
|
+
};
|
|
3512
|
+
|
|
3513
|
+
const response: RunFormula200Response = await client.runFormula({
|
|
3514
|
+
body: request,
|
|
3515
|
+
});
|
|
3516
|
+
|
|
3517
|
+
console.log("Real API response (no rid):", response);
|
|
3518
|
+
|
|
3519
|
+
expect(response).toHaveProperty("result");
|
|
3520
|
+
expect(response.result).toBe("2"); // Expect "2" as a string
|
|
3521
|
+
}, 10000);
|
|
3522
|
+
|
|
3523
|
+
it("runs formula with rid and field ID 3, returns correct numeric result", async () => {
|
|
3524
|
+
const request: RunFormulaRequest = {
|
|
3525
|
+
from: QB_TABLE_ID_1,
|
|
3526
|
+
formula: "Sum([Record ID#], 20)", // Field ID 3 is "Record ID#"
|
|
3527
|
+
rid: testRecordId, // Use the upserted record ID
|
|
3528
|
+
};
|
|
3529
|
+
|
|
3530
|
+
const response: RunFormula200Response = await client.runFormula({
|
|
3531
|
+
body: request,
|
|
3532
|
+
});
|
|
3533
|
+
|
|
3534
|
+
console.log("Real API response (with rid):", response);
|
|
3535
|
+
|
|
3536
|
+
expect(response).toHaveProperty("result");
|
|
3537
|
+
expect(response.result).toBe(String(testRecordId + 20)); // Dynamic result based on the record ID
|
|
3538
|
+
}, 10000);
|
|
3539
|
+
});
|
|
3381
3540
|
- name: >-
|
|
3382
3541
|
index.ts
|
|
3383
3542
|
type: >-
|
|
@@ -4028,6 +4187,132 @@ tree:
|
|
|
4028
4187
|
type: >-
|
|
4029
4188
|
directory
|
|
4030
4189
|
children:
|
|
4190
|
+
- name: >-
|
|
4191
|
+
createRelationship.test.ts
|
|
4192
|
+
type: >-
|
|
4193
|
+
file
|
|
4194
|
+
contents: >
|
|
4195
|
+
//
|
|
4196
|
+
tests/vitest/qb/tables/createRelationship.test.ts
|
|
4197
|
+
|
|
4198
|
+
|
|
4199
|
+
import
|
|
4200
|
+
{
|
|
4201
|
+
test,
|
|
4202
|
+
expect
|
|
4203
|
+
}
|
|
4204
|
+
from
|
|
4205
|
+
"vitest";
|
|
4206
|
+
|
|
4207
|
+
import
|
|
4208
|
+
{
|
|
4209
|
+
quickbase
|
|
4210
|
+
}
|
|
4211
|
+
from
|
|
4212
|
+
"/home/drew/Projects/quickbase-js/src/quickbaseClient";
|
|
4213
|
+
|
|
4214
|
+
import
|
|
4215
|
+
{
|
|
4216
|
+
QB_REALM,
|
|
4217
|
+
QB_USER_TOKEN,
|
|
4218
|
+
QB_TABLE_ID_1,
|
|
4219
|
+
QB_TABLE_ID_2,
|
|
4220
|
+
}
|
|
4221
|
+
from
|
|
4222
|
+
"/home/drew/Projects/quickbase-js/tests/setup.ts";
|
|
4223
|
+
|
|
4224
|
+
|
|
4225
|
+
test(
|
|
4226
|
+
"QuickbaseClient Integration - createRelationship > creates a new relationship in QuickBase",
|
|
4227
|
+
{ timeout: 60000 }, // 60 seconds for create and delete
|
|
4228
|
+
async () => {
|
|
4229
|
+
// Validate environment variables
|
|
4230
|
+
if (!QB_REALM) throw new Error("QB_REALM is not defined in .env");
|
|
4231
|
+
if (!QB_USER_TOKEN) throw new Error("QB_USER_TOKEN is not defined in .env");
|
|
4232
|
+
if (!QB_TABLE_ID_1) throw new Error("QB_TABLE_ID_1 is not defined in .env");
|
|
4233
|
+
if (!QB_TABLE_ID_2) throw new Error("QB_TABLE_ID_2 is not defined in .env");
|
|
4234
|
+
|
|
4235
|
+
// Initialize client
|
|
4236
|
+
const client = quickbase({
|
|
4237
|
+
realm: QB_REALM,
|
|
4238
|
+
userToken: QB_USER_TOKEN,
|
|
4239
|
+
debug: true,
|
|
4240
|
+
});
|
|
4241
|
+
|
|
4242
|
+
// Define the relationship creation request
|
|
4243
|
+
const uniqueLabel = `TestRelationship_${Date.now()}`;
|
|
4244
|
+
const requestBody = {
|
|
4245
|
+
parentTableId: QB_TABLE_ID_1,
|
|
4246
|
+
foreignKeyField: { label: uniqueLabel },
|
|
4247
|
+
lookupFieldIds: [6], // Assuming field 6 exists in QB_TABLE_ID_1
|
|
4248
|
+
summaryFields: [
|
|
4249
|
+
{
|
|
4250
|
+
summaryFid: 6, // Assuming field 6 in QB_TABLE_ID_2 is numeric
|
|
4251
|
+
label: `Sum_${uniqueLabel}`,
|
|
4252
|
+
accumulationType: "SUM",
|
|
4253
|
+
},
|
|
4254
|
+
],
|
|
4255
|
+
};
|
|
4256
|
+
|
|
4257
|
+
console.log("Config used:", {
|
|
4258
|
+
realm: QB_REALM,
|
|
4259
|
+
userToken: "[REDACTED]",
|
|
4260
|
+
parentTableId: QB_TABLE_ID_1,
|
|
4261
|
+
childTableId: QB_TABLE_ID_2,
|
|
4262
|
+
});
|
|
4263
|
+
console.log("Creating relationship with:", requestBody);
|
|
4264
|
+
|
|
4265
|
+
// Create the relationship
|
|
4266
|
+
const response = await client.createRelationship({
|
|
4267
|
+
tableId: QB_TABLE_ID_2,
|
|
4268
|
+
body: requestBody,
|
|
4269
|
+
});
|
|
4270
|
+
|
|
4271
|
+
console.log("Real API response:", JSON.stringify(response, null, 2));
|
|
4272
|
+
|
|
4273
|
+
// Assertions for creation
|
|
4274
|
+
expect(response).toBeDefined();
|
|
4275
|
+
expect(response.id).toBeDefined();
|
|
4276
|
+
expect(response.parentTableId).toBe(QB_TABLE_ID_1);
|
|
4277
|
+
expect(response.childTableId).toBe(QB_TABLE_ID_2);
|
|
4278
|
+
expect(response.foreignKeyField).toBeDefined();
|
|
4279
|
+
expect(response.foreignKeyField?.label).toBe(uniqueLabel);
|
|
4280
|
+
expect(response.lookupFields).toHaveLength(1);
|
|
4281
|
+
expect(response.lookupFields[0].id).toBeGreaterThan(0);
|
|
4282
|
+
expect(response.summaryFields).toHaveLength(1);
|
|
4283
|
+
expect(response.summaryFields[0].label).toBe(`Sum_${uniqueLabel}`);
|
|
4284
|
+
|
|
4285
|
+
// Cleanup: Delete the relationship
|
|
4286
|
+
const relationshipId = response.id;
|
|
4287
|
+
console.log("Deleting relationship with ID:", relationshipId);
|
|
4288
|
+
const deleteResponse = await client.deleteRelationship({
|
|
4289
|
+
tableId: QB_TABLE_ID_2,
|
|
4290
|
+
relationshipId,
|
|
4291
|
+
});
|
|
4292
|
+
|
|
4293
|
+
console.log(
|
|
4294
|
+
"Delete relationship response:",
|
|
4295
|
+
JSON.stringify(deleteResponse, null, 2)
|
|
4296
|
+
);
|
|
4297
|
+
|
|
4298
|
+
// Verify deletion
|
|
4299
|
+
expect(deleteResponse).toBeDefined();
|
|
4300
|
+
expect(deleteResponse.relationshipId).toBe(relationshipId);
|
|
4301
|
+
|
|
4302
|
+
// Confirm relationship is gone
|
|
4303
|
+
const relationships = await client.getRelationships({
|
|
4304
|
+
tableId: QB_TABLE_ID_2,
|
|
4305
|
+
});
|
|
4306
|
+
console.log(
|
|
4307
|
+
"Relationships after deletion:",
|
|
4308
|
+
JSON.stringify(relationships, null, 2)
|
|
4309
|
+
);
|
|
4310
|
+
const deletedRelationship = relationships.relationships.find(
|
|
4311
|
+
(r) => r.id === relationshipId
|
|
4312
|
+
);
|
|
4313
|
+
expect(deletedRelationship).toBeUndefined(); // Should no longer exist
|
|
4314
|
+
}
|
|
4315
|
+
);
|
|
4031
4316
|
- name: >-
|
|
4032
4317
|
createTable.test.ts
|
|
4033
4318
|
type: >-
|
|
@@ -4101,6 +4386,173 @@ tree:
|
|
|
4101
4386
|
console.log("Cleanup - Deleted table:", deleteResponse);
|
|
4102
4387
|
}
|
|
4103
4388
|
);
|
|
4389
|
+
- name: >-
|
|
4390
|
+
deleteRelationship.test.ts
|
|
4391
|
+
type: >-
|
|
4392
|
+
file
|
|
4393
|
+
contents: >
|
|
4394
|
+
//
|
|
4395
|
+
tests/vitest/qb/tables/deleteRelationship.test.ts
|
|
4396
|
+
|
|
4397
|
+
|
|
4398
|
+
import
|
|
4399
|
+
{
|
|
4400
|
+
test,
|
|
4401
|
+
expect
|
|
4402
|
+
}
|
|
4403
|
+
from
|
|
4404
|
+
"vitest";
|
|
4405
|
+
|
|
4406
|
+
import
|
|
4407
|
+
{
|
|
4408
|
+
quickbase
|
|
4409
|
+
}
|
|
4410
|
+
from
|
|
4411
|
+
"/home/drew/Projects/quickbase-js/src/quickbaseClient";
|
|
4412
|
+
|
|
4413
|
+
import
|
|
4414
|
+
{
|
|
4415
|
+
QB_REALM,
|
|
4416
|
+
QB_USER_TOKEN,
|
|
4417
|
+
QB_TABLE_ID_1,
|
|
4418
|
+
QB_TABLE_ID_2,
|
|
4419
|
+
}
|
|
4420
|
+
from
|
|
4421
|
+
"/home/drew/Projects/quickbase-js/tests/setup.ts";
|
|
4422
|
+
|
|
4423
|
+
|
|
4424
|
+
test(
|
|
4425
|
+
"QuickbaseClient Integration - deleteRelationship > creates and deletes a relationship in QuickBase",
|
|
4426
|
+
{ timeout: 60000 }, // 60 seconds for two API calls
|
|
4427
|
+
async () => {
|
|
4428
|
+
// Validate environment variables
|
|
4429
|
+
if (!QB_REALM) throw new Error("QB_REALM is not defined in .env");
|
|
4430
|
+
if (!QB_USER_TOKEN) throw new Error("QB_USER_TOKEN is not defined in .env");
|
|
4431
|
+
if (!QB_TABLE_ID_1) throw new Error("QB_TABLE_ID_1 is not defined in .env");
|
|
4432
|
+
if (!QB_TABLE_ID_2) throw new Error("QB_TABLE_ID_2 is not defined in .env");
|
|
4433
|
+
|
|
4434
|
+
// Initialize client
|
|
4435
|
+
const client = quickbase({
|
|
4436
|
+
realm: QB_REALM,
|
|
4437
|
+
userToken: QB_USER_TOKEN,
|
|
4438
|
+
debug: true,
|
|
4439
|
+
});
|
|
4440
|
+
|
|
4441
|
+
// Step 1: Create a relationship
|
|
4442
|
+
const uniqueLabel = `TestRelationship_${Date.now()}`;
|
|
4443
|
+
const createRequestBody = {
|
|
4444
|
+
parentTableId: QB_TABLE_ID_1,
|
|
4445
|
+
foreignKeyField: { label: uniqueLabel },
|
|
4446
|
+
lookupFieldIds: [6], // Assuming field 6 exists in QB_TABLE_ID_1
|
|
4447
|
+
summaryFields: [
|
|
4448
|
+
{
|
|
4449
|
+
summaryFid: 6, // Assuming field 6 in QB_TABLE_ID_2 is numeric
|
|
4450
|
+
label: `Sum_${uniqueLabel}`,
|
|
4451
|
+
accumulationType: "SUM",
|
|
4452
|
+
},
|
|
4453
|
+
],
|
|
4454
|
+
};
|
|
4455
|
+
|
|
4456
|
+
console.log("Config used:", {
|
|
4457
|
+
realm: QB_REALM,
|
|
4458
|
+
userToken: "[REDACTED]",
|
|
4459
|
+
parentTableId: QB_TABLE_ID_1,
|
|
4460
|
+
childTableId: QB_TABLE_ID_2,
|
|
4461
|
+
});
|
|
4462
|
+
console.log("Creating relationship with:", createRequestBody);
|
|
4463
|
+
|
|
4464
|
+
const createResponse = await client.createRelationship({
|
|
4465
|
+
tableId: QB_TABLE_ID_2,
|
|
4466
|
+
body: createRequestBody,
|
|
4467
|
+
});
|
|
4468
|
+
|
|
4469
|
+
console.log(
|
|
4470
|
+
"Created relationship response:",
|
|
4471
|
+
JSON.stringify(createResponse, null, 2)
|
|
4472
|
+
);
|
|
4473
|
+
|
|
4474
|
+
// Verify creation
|
|
4475
|
+
expect(createResponse).toBeDefined();
|
|
4476
|
+
expect(createResponse.id).toBeDefined();
|
|
4477
|
+
expect(createResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
4478
|
+
expect(createResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
4479
|
+
expect(createResponse.foreignKeyField).toBeDefined();
|
|
4480
|
+
expect(createResponse.foreignKeyField?.label).toBe(uniqueLabel);
|
|
4481
|
+
|
|
4482
|
+
const relationshipId = createResponse.id;
|
|
4483
|
+
const foreignKeyFieldId = createResponse.foreignKeyField?.id;
|
|
4484
|
+
|
|
4485
|
+
// Step 2: Delete the relationship
|
|
4486
|
+
console.log("Deleting relationship with ID:", relationshipId);
|
|
4487
|
+
const deleteResponse = await client.deleteRelationship({
|
|
4488
|
+
tableId: QB_TABLE_ID_2,
|
|
4489
|
+
relationshipId,
|
|
4490
|
+
});
|
|
4491
|
+
|
|
4492
|
+
console.log(
|
|
4493
|
+
"Delete relationship response:",
|
|
4494
|
+
JSON.stringify(deleteResponse, null, 2)
|
|
4495
|
+
);
|
|
4496
|
+
|
|
4497
|
+
// Verify deletion (adjusted to match actual response)
|
|
4498
|
+
expect(deleteResponse).toBeDefined();
|
|
4499
|
+
expect(deleteResponse.relationshipId).toBe(relationshipId); // Updated to use "relationshipId"
|
|
4500
|
+
|
|
4501
|
+
// Step 3: Confirm relationship is gone (or non-functional)
|
|
4502
|
+
try {
|
|
4503
|
+
const relationships = await client.getRelationships({
|
|
4504
|
+
tableId: QB_TABLE_ID_2,
|
|
4505
|
+
});
|
|
4506
|
+
console.log(
|
|
4507
|
+
"Relationships after deletion:",
|
|
4508
|
+
JSON.stringify(relationships, null, 2)
|
|
4509
|
+
);
|
|
4510
|
+
// Check if the relationship is still listed (metadata might persist)
|
|
4511
|
+
const deletedRelationship = relationships.relationships.find(
|
|
4512
|
+
(r) => r.id === relationshipId
|
|
4513
|
+
);
|
|
4514
|
+
if (deletedRelationship) {
|
|
4515
|
+
console.log("Relationship metadata persists:", deletedRelationship);
|
|
4516
|
+
expect(deletedRelationship.foreignKeyField).toBeUndefined(); // Should lack fields
|
|
4517
|
+
}
|
|
4518
|
+
} catch (error) {
|
|
4519
|
+
console.error("Error fetching relationships post-deletion:", error);
|
|
4520
|
+
expect(error.message).toMatch(/404|not found/i); // Optional stricter check
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4523
|
+
// Cleanup remaining fields
|
|
4524
|
+
const lookupFieldId = createResponse.lookupFields[0]?.id;
|
|
4525
|
+
const summaryFieldId = createResponse.summaryFields[0]?.id;
|
|
4526
|
+
|
|
4527
|
+
if (foreignKeyFieldId) {
|
|
4528
|
+
await client.deleteFields({
|
|
4529
|
+
tableId: QB_TABLE_ID_2,
|
|
4530
|
+
body: { fieldIds: [foreignKeyFieldId] },
|
|
4531
|
+
});
|
|
4532
|
+
console.log(
|
|
4533
|
+
`Deleted foreign key field ${foreignKeyFieldId} from ${QB_TABLE_ID_2}`
|
|
4534
|
+
);
|
|
4535
|
+
}
|
|
4536
|
+
if (lookupFieldId) {
|
|
4537
|
+
await client.deleteFields({
|
|
4538
|
+
tableId: QB_TABLE_ID_2,
|
|
4539
|
+
body: { fieldIds: [lookupFieldId] },
|
|
4540
|
+
});
|
|
4541
|
+
console.log(
|
|
4542
|
+
`Deleted lookup field ${lookupFieldId} from ${QB_TABLE_ID_2}`
|
|
4543
|
+
);
|
|
4544
|
+
}
|
|
4545
|
+
if (summaryFieldId) {
|
|
4546
|
+
await client.deleteFields({
|
|
4547
|
+
tableId: QB_TABLE_ID_1,
|
|
4548
|
+
body: { fieldIds: [summaryFieldId] },
|
|
4549
|
+
});
|
|
4550
|
+
console.log(
|
|
4551
|
+
`Deleted summary field ${summaryFieldId} from ${QB_TABLE_ID_1}`
|
|
4552
|
+
);
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
);
|
|
4104
4556
|
- name: >-
|
|
4105
4557
|
deleteTable.test.ts
|
|
4106
4558
|
type: >-
|
|
@@ -4409,10 +4861,7 @@ tree:
|
|
|
4409
4861
|
{
|
|
4410
4862
|
describe,
|
|
4411
4863
|
it,
|
|
4412
|
-
expect
|
|
4413
|
-
beforeAll,
|
|
4414
|
-
afterAll,
|
|
4415
|
-
beforeEach
|
|
4864
|
+
expect
|
|
4416
4865
|
}
|
|
4417
4866
|
from
|
|
4418
4867
|
"vitest";
|
|
@@ -4446,38 +4895,30 @@ tree:
|
|
|
4446
4895
|
{
|
|
4447
4896
|
let client: ReturnType<typeof createClient>;
|
|
4448
4897
|
let relationshipId: number;
|
|
4449
|
-
let newLookupFieldId: number;
|
|
4450
|
-
let newChildFieldId: number;
|
|
4898
|
+
let newLookupFieldId: number | undefined;
|
|
4899
|
+
let newChildFieldId: number | undefined;
|
|
4900
|
+
let generatedLookupFieldId: number | undefined;
|
|
4901
|
+
let generatedSummaryFieldId: number | undefined;
|
|
4451
4902
|
|
|
4452
|
-
beforeAll
|
|
4453
|
-
client = createClient(fetch, {
|
|
4454
|
-
realm: QB_REALM,
|
|
4455
|
-
userToken: QB_USER_TOKEN,
|
|
4456
|
-
debug: true,
|
|
4457
|
-
});
|
|
4903
|
+
// No beforeAll/afterAll since we'll create and delete within the test
|
|
4458
4904
|
|
|
4905
|
+
it("creates, updates, deletes, and verifies a relationship", async () => {
|
|
4906
|
+
// Validate environment variables
|
|
4459
4907
|
if (!QB_REALM) throw new Error("QB_REALM is not defined in .env");
|
|
4460
4908
|
if (!QB_USER_TOKEN) throw new Error("QB_USER_TOKEN is not defined in .env");
|
|
4909
|
+
if (!QB_TABLE_ID_1) throw new Error("QB_TABLE_ID_1 is not defined in .env");
|
|
4910
|
+
if (!QB_TABLE_ID_2) throw new Error("QB_TABLE_ID_2 is not defined in .env");
|
|
4461
4911
|
|
|
4462
|
-
//
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4912
|
+
// Initialize client
|
|
4913
|
+
client = createClient(fetch, {
|
|
4914
|
+
realm: QB_REALM,
|
|
4915
|
+
userToken: QB_USER_TOKEN,
|
|
4916
|
+
debug: true,
|
|
4466
4917
|
});
|
|
4467
4918
|
|
|
4468
|
-
|
|
4469
|
-
(r) => r.parentTableId === QB_TABLE_ID_1
|
|
4470
|
-
);
|
|
4471
|
-
if (!relationship) {
|
|
4472
|
-
throw new Error(
|
|
4473
|
-
`No relationship found between parent ${QB_TABLE_ID_1} and child ${QB_TABLE_ID_2}`
|
|
4474
|
-
);
|
|
4475
|
-
}
|
|
4476
|
-
relationshipId = relationship.id;
|
|
4477
|
-
|
|
4478
|
-
// Create fields
|
|
4919
|
+
// Step 1: Create fields for the relationship update
|
|
4479
4920
|
const lookupFieldRequest: CreateFieldRequest = {
|
|
4480
|
-
label:
|
|
4921
|
+
label: `Test Lookup Field_${Date.now()}`,
|
|
4481
4922
|
fieldType: "text",
|
|
4482
4923
|
};
|
|
4483
4924
|
const lookupResponse = await client.createField({
|
|
@@ -4485,9 +4926,15 @@ tree:
|
|
|
4485
4926
|
body: lookupFieldRequest,
|
|
4486
4927
|
});
|
|
4487
4928
|
newLookupFieldId = lookupResponse.id;
|
|
4929
|
+
if (!newLookupFieldId) {
|
|
4930
|
+
throw new Error("Failed to retrieve ID for newly created lookup field");
|
|
4931
|
+
}
|
|
4932
|
+
console.log(
|
|
4933
|
+
`Created lookup field with ID ${newLookupFieldId} in parent table ${QB_TABLE_ID_1}`
|
|
4934
|
+
);
|
|
4488
4935
|
|
|
4489
4936
|
const childFieldRequest: CreateFieldRequest = {
|
|
4490
|
-
label:
|
|
4937
|
+
label: `Test Child Numeric_${Date.now()}`,
|
|
4491
4938
|
fieldType: "numeric",
|
|
4492
4939
|
};
|
|
4493
4940
|
const childResponse = await client.createField({
|
|
@@ -4495,224 +4942,190 @@ tree:
|
|
|
4495
4942
|
body: childFieldRequest,
|
|
4496
4943
|
});
|
|
4497
4944
|
newChildFieldId = childResponse.id;
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
);
|
|
4502
|
-
console.log(
|
|
4503
|
-
`Created child field ${newChildFieldId} in child ${QB_TABLE_ID_2}`
|
|
4504
|
-
);
|
|
4945
|
+
if (!newChildFieldId) {
|
|
4946
|
+
throw new Error("Failed to retrieve ID for newly created child field");
|
|
4947
|
+
}
|
|
4505
4948
|
console.log(
|
|
4506
|
-
`
|
|
4949
|
+
`Created child field with ID ${newChildFieldId} in child table ${QB_TABLE_ID_2}`
|
|
4507
4950
|
);
|
|
4508
|
-
}, 30000);
|
|
4509
4951
|
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
}
|
|
4525
|
-
}, 30000);
|
|
4952
|
+
// Step 2: Create a new relationship
|
|
4953
|
+
const uniqueLabel = `TestRelationship_${Date.now()}`;
|
|
4954
|
+
const createRequestBody = {
|
|
4955
|
+
parentTableId: QB_TABLE_ID_1,
|
|
4956
|
+
foreignKeyField: { label: uniqueLabel },
|
|
4957
|
+
lookupFieldIds: [6], // Assuming field 6 exists in QB_TABLE_ID_1
|
|
4958
|
+
summaryFields: [
|
|
4959
|
+
{
|
|
4960
|
+
summaryFid: 6, // Assuming field 6 in QB_TABLE_ID_2 is numeric
|
|
4961
|
+
label: `Sum_${uniqueLabel}`,
|
|
4962
|
+
accumulationType: "SUM",
|
|
4963
|
+
},
|
|
4964
|
+
],
|
|
4965
|
+
};
|
|
4526
4966
|
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
const relationshipsResponse = await client.getRelationships({
|
|
4967
|
+
console.log("Creating relationship with:", createRequestBody);
|
|
4968
|
+
const createResponse = await client.createRelationship({
|
|
4530
4969
|
tableId: QB_TABLE_ID_2,
|
|
4970
|
+
body: createRequestBody,
|
|
4531
4971
|
});
|
|
4532
|
-
|
|
4533
|
-
|
|
4972
|
+
console.log(
|
|
4973
|
+
"Created relationship response:",
|
|
4974
|
+
JSON.stringify(createResponse, null, 2)
|
|
4534
4975
|
);
|
|
4535
|
-
const cleanupRequest: UpdateRelationshipRequest = {
|
|
4536
|
-
lookupFieldIds: (relationship?.lookupFields || [])
|
|
4537
|
-
.map((f) => f.id)
|
|
4538
|
-
.filter((id) => id !== newLookupFieldId),
|
|
4539
|
-
summaryFields: (relationship?.summaryFields || []).map((f) => ({
|
|
4540
|
-
summaryFid: f.id,
|
|
4541
|
-
label: f.label,
|
|
4542
|
-
accumulationType: "COUNT", // Assuming COUNT for existing fields; adjust if needed
|
|
4543
|
-
})),
|
|
4544
|
-
};
|
|
4545
|
-
await client.updateRelationship({
|
|
4546
|
-
tableId: QB_TABLE_ID_2,
|
|
4547
|
-
relationshipId,
|
|
4548
|
-
body: cleanupRequest,
|
|
4549
|
-
});
|
|
4550
|
-
console.log(`Reset relationship ${relationshipId} before test`);
|
|
4551
|
-
});
|
|
4552
|
-
|
|
4553
|
-
it(
|
|
4554
|
-
"adds a lookup field to the relationship",
|
|
4555
|
-
async ({ expect }) => {
|
|
4556
|
-
const tableId = QB_TABLE_ID_2;
|
|
4557
4976
|
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
const currentLookupFields = (initialRelationship?.lookupFields || []).map(
|
|
4564
|
-
(f) => f.id
|
|
4565
|
-
);
|
|
4566
|
-
|
|
4567
|
-
const request: UpdateRelationshipRequest = {
|
|
4568
|
-
lookupFieldIds: [...currentLookupFields, newLookupFieldId],
|
|
4569
|
-
};
|
|
4570
|
-
|
|
4571
|
-
const updateResponse = await client.updateRelationship({
|
|
4572
|
-
tableId,
|
|
4573
|
-
relationshipId,
|
|
4574
|
-
body: request,
|
|
4575
|
-
});
|
|
4977
|
+
expect(createResponse).toBeDefined();
|
|
4978
|
+
expect(createResponse.id).toBeDefined();
|
|
4979
|
+
expect(createResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
4980
|
+
expect(createResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
4981
|
+
expect(createResponse.foreignKeyField?.label).toBe(uniqueLabel);
|
|
4576
4982
|
|
|
4577
|
-
|
|
4578
|
-
expect(updateResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
4579
|
-
expect(updateResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
4580
|
-
expect(
|
|
4581
|
-
updateResponse.lookupFields.some((f) => f.id === newLookupFieldId)
|
|
4582
|
-
).toBe(true);
|
|
4983
|
+
relationshipId = createResponse.id;
|
|
4583
4984
|
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4985
|
+
// Step 3: Update the relationship - Add a lookup field
|
|
4986
|
+
const tableId = QB_TABLE_ID_2;
|
|
4987
|
+
const initialResponse = await client.getRelationships({ tableId });
|
|
4988
|
+
const initialRelationship = initialResponse.relationships.find(
|
|
4989
|
+
(r) => r.id === relationshipId
|
|
4990
|
+
);
|
|
4991
|
+
const currentLookupFields = (initialRelationship?.lookupFields || []).map(
|
|
4992
|
+
(f) => f.id
|
|
4993
|
+
);
|
|
4994
|
+
console.log("Current lookupFields before update:", currentLookupFields);
|
|
4594
4995
|
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4996
|
+
const updateLookupRequest: UpdateRelationshipRequest = {
|
|
4997
|
+
lookupFieldIds: [newLookupFieldId!],
|
|
4998
|
+
};
|
|
4999
|
+
console.log(
|
|
5000
|
+
"Adding lookup field request:",
|
|
5001
|
+
JSON.stringify(updateLookupRequest, null, 2)
|
|
5002
|
+
);
|
|
4599
5003
|
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
label: f.label,
|
|
4610
|
-
accumulationType: "COUNT",
|
|
4611
|
-
}));
|
|
4612
|
-
|
|
4613
|
-
const request: UpdateRelationshipRequest = {
|
|
4614
|
-
summaryFields: [
|
|
4615
|
-
...currentSummaryFields,
|
|
4616
|
-
{
|
|
4617
|
-
summaryFid: newChildFieldId,
|
|
4618
|
-
label: "Test Summary Field",
|
|
4619
|
-
accumulationType: "SUM",
|
|
4620
|
-
},
|
|
4621
|
-
],
|
|
4622
|
-
};
|
|
5004
|
+
const updateLookupResponse = await client.updateRelationship({
|
|
5005
|
+
tableId,
|
|
5006
|
+
relationshipId,
|
|
5007
|
+
body: updateLookupRequest,
|
|
5008
|
+
});
|
|
5009
|
+
console.log(
|
|
5010
|
+
"Update lookup response:",
|
|
5011
|
+
JSON.stringify(updateLookupResponse, null, 2)
|
|
5012
|
+
);
|
|
4623
5013
|
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
5014
|
+
const newLookup = updateLookupResponse.lookupFields.find(
|
|
5015
|
+
(f) =>
|
|
5016
|
+
f.label.includes("Test Lookup Field") &&
|
|
5017
|
+
!currentLookupFields.includes(f.id)
|
|
5018
|
+
);
|
|
5019
|
+
generatedLookupFieldId = newLookup?.id;
|
|
5020
|
+
console.log(
|
|
5021
|
+
`Captured generated lookup field ID: ${generatedLookupFieldId}`
|
|
5022
|
+
);
|
|
4629
5023
|
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
5024
|
+
expect(updateLookupResponse.id).toBe(relationshipId);
|
|
5025
|
+
expect(updateLookupResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
5026
|
+
expect(updateLookupResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
5027
|
+
expect(
|
|
5028
|
+
updateLookupResponse.lookupFields.some((f) =>
|
|
5029
|
+
f.label.includes("Test Lookup Field")
|
|
5030
|
+
)
|
|
5031
|
+
).toBe(true);
|
|
5032
|
+
|
|
5033
|
+
// Step 4: Update the relationship - Add a summary field
|
|
5034
|
+
const currentSummaryFields = (updateLookupResponse.summaryFields || []).map(
|
|
5035
|
+
(f) => f.id
|
|
5036
|
+
);
|
|
5037
|
+
console.log("Current summaryFields before update:", currentSummaryFields);
|
|
4638
5038
|
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
5039
|
+
const updateSummaryRequest: UpdateRelationshipRequest = {
|
|
5040
|
+
summaryFields: [
|
|
5041
|
+
{
|
|
5042
|
+
summaryFid: newChildFieldId!,
|
|
5043
|
+
label: "Test Summary Field",
|
|
5044
|
+
accumulationType: "SUM",
|
|
5045
|
+
},
|
|
5046
|
+
],
|
|
5047
|
+
};
|
|
5048
|
+
console.log(
|
|
5049
|
+
"Adding summary field request:",
|
|
5050
|
+
JSON.stringify(updateSummaryRequest, null, 2)
|
|
5051
|
+
);
|
|
4651
5052
|
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
5053
|
+
const updateSummaryResponse = await client.updateRelationship({
|
|
5054
|
+
tableId,
|
|
5055
|
+
relationshipId,
|
|
5056
|
+
body: updateSummaryRequest,
|
|
5057
|
+
});
|
|
5058
|
+
console.log(
|
|
5059
|
+
"Update summary response:",
|
|
5060
|
+
JSON.stringify(updateSummaryResponse, null, 2)
|
|
5061
|
+
);
|
|
4656
5062
|
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
5063
|
+
const newSummary = updateSummaryResponse.summaryFields.find(
|
|
5064
|
+
(f) =>
|
|
5065
|
+
f.label.includes("Test Summary Field") &&
|
|
5066
|
+
!currentSummaryFields.includes(f.id)
|
|
5067
|
+
);
|
|
5068
|
+
generatedSummaryFieldId = newSummary?.id;
|
|
5069
|
+
console.log(
|
|
5070
|
+
`Captured generated summary field ID: ${generatedSummaryFieldId}`
|
|
5071
|
+
);
|
|
4660
5072
|
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
)
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
5073
|
+
expect(updateSummaryResponse.id).toBe(relationshipId);
|
|
5074
|
+
expect(updateSummaryResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
5075
|
+
expect(updateSummaryResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
5076
|
+
expect(
|
|
5077
|
+
updateSummaryResponse.summaryFields.some((f) =>
|
|
5078
|
+
f.label.includes("Test Summary Field")
|
|
5079
|
+
)
|
|
5080
|
+
).toBe(true);
|
|
5081
|
+
|
|
5082
|
+
// Step 5: Delete the relationship
|
|
5083
|
+
console.log("Deleting relationship with ID:", relationshipId);
|
|
5084
|
+
const deleteResponse = await client.deleteRelationship({
|
|
5085
|
+
tableId: QB_TABLE_ID_2,
|
|
5086
|
+
relationshipId,
|
|
5087
|
+
});
|
|
5088
|
+
console.log(
|
|
5089
|
+
"Delete relationship response:",
|
|
5090
|
+
JSON.stringify(deleteResponse, null, 2)
|
|
5091
|
+
);
|
|
4671
5092
|
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
async ({ expect }) => {
|
|
4675
|
-
const tableId = QB_TABLE_ID_2;
|
|
5093
|
+
expect(deleteResponse).toBeDefined();
|
|
5094
|
+
expect(deleteResponse.relationshipId).toBe(relationshipId);
|
|
4676
5095
|
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
label: f.label,
|
|
4690
|
-
accumulationType: "COUNT",
|
|
4691
|
-
}));
|
|
4692
|
-
|
|
4693
|
-
const request: UpdateRelationshipRequest = {
|
|
4694
|
-
lookupFieldIds: currentLookupFields,
|
|
4695
|
-
summaryFields: currentSummaryFields,
|
|
4696
|
-
};
|
|
5096
|
+
// Step 6: Verify deletion
|
|
5097
|
+
const relationships = await client.getRelationships({
|
|
5098
|
+
tableId: QB_TABLE_ID_2,
|
|
5099
|
+
});
|
|
5100
|
+
console.log(
|
|
5101
|
+
"Relationships after deletion:",
|
|
5102
|
+
JSON.stringify(relationships, null, 2)
|
|
5103
|
+
);
|
|
5104
|
+
const deletedRelationship = relationships.relationships.find(
|
|
5105
|
+
(r) => r.id === relationshipId
|
|
5106
|
+
);
|
|
5107
|
+
expect(deletedRelationship).toBeUndefined(); // Confirm relationship is gone
|
|
4697
5108
|
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
5109
|
+
// Cleanup remaining fields from setup
|
|
5110
|
+
if (newLookupFieldId) {
|
|
5111
|
+
await client.deleteFields({
|
|
5112
|
+
tableId: QB_TABLE_ID_1,
|
|
5113
|
+
body: { fieldIds: [newLookupFieldId] },
|
|
4702
5114
|
});
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
expect(updateResponse.childTableId).toBe(QB_TABLE_ID_2);
|
|
4706
|
-
expect(updateResponse.parentTableId).toBe(QB_TABLE_ID_1);
|
|
4707
|
-
expect(updateResponse.lookupFields.map((f) => f.id)).toEqual(
|
|
4708
|
-
currentLookupFields
|
|
5115
|
+
console.log(
|
|
5116
|
+
`Deleted lookup field ${newLookupFieldId} from ${QB_TABLE_ID_1}`
|
|
4709
5117
|
);
|
|
4710
|
-
|
|
4711
|
-
|
|
5118
|
+
}
|
|
5119
|
+
if (newChildFieldId) {
|
|
5120
|
+
await client.deleteFields({
|
|
5121
|
+
tableId: QB_TABLE_ID_2,
|
|
5122
|
+
body: { fieldIds: [newChildFieldId] },
|
|
5123
|
+
});
|
|
5124
|
+
console.log(
|
|
5125
|
+
`Deleted child field ${newChildFieldId} from ${QB_TABLE_ID_2}`
|
|
4712
5126
|
);
|
|
4713
|
-
}
|
|
4714
|
-
|
|
4715
|
-
);
|
|
5127
|
+
}
|
|
5128
|
+
}, 60000);
|
|
4716
5129
|
});
|
|
4717
5130
|
- name: >-
|
|
4718
5131
|
updateTable.test.ts
|
|
@@ -4785,6 +5198,10 @@ tree:
|
|
|
4785
5198
|
type: >-
|
|
4786
5199
|
directory
|
|
4787
5200
|
children:
|
|
5201
|
+
- name: >-
|
|
5202
|
+
ThrottleBucket.test.ts
|
|
5203
|
+
type: >-
|
|
5204
|
+
file
|
|
4788
5205
|
- name: >-
|
|
4789
5206
|
apps
|
|
4790
5207
|
type: >-
|
|
@@ -4832,13 +5249,17 @@ tree:
|
|
|
4832
5249
|
type: >-
|
|
4833
5250
|
file
|
|
4834
5251
|
- name: >-
|
|
4835
|
-
|
|
5252
|
+
retryTempTokenMaxRetries.test.ts
|
|
4836
5253
|
type: >-
|
|
4837
5254
|
file
|
|
4838
5255
|
- name: >-
|
|
4839
5256
|
retryUserToken401.test.ts
|
|
4840
5257
|
type: >-
|
|
4841
5258
|
file
|
|
5259
|
+
- name: >-
|
|
5260
|
+
ssoTokenRefresh.test.ts
|
|
5261
|
+
type: >-
|
|
5262
|
+
file
|
|
4842
5263
|
- name: >-
|
|
4843
5264
|
fields
|
|
4844
5265
|
type: >-
|
|
@@ -4872,10 +5293,23 @@ tree:
|
|
|
4872
5293
|
updateField.test.ts
|
|
4873
5294
|
type: >-
|
|
4874
5295
|
file
|
|
5296
|
+
- name: >-
|
|
5297
|
+
formulas
|
|
5298
|
+
type: >-
|
|
5299
|
+
directory
|
|
5300
|
+
children:
|
|
5301
|
+
- name: >-
|
|
5302
|
+
runFormula.test.ts
|
|
5303
|
+
type: >-
|
|
5304
|
+
file
|
|
4875
5305
|
- name: >-
|
|
4876
5306
|
index.ts
|
|
4877
5307
|
type: >-
|
|
4878
5308
|
file
|
|
5309
|
+
- name: >-
|
|
5310
|
+
inferHttpMethod.test.ts
|
|
5311
|
+
type: >-
|
|
5312
|
+
file
|
|
4879
5313
|
- name: >-
|
|
4880
5314
|
rateLimit.test.ts
|
|
4881
5315
|
type: >-
|
|
@@ -4902,10 +5336,18 @@ tree:
|
|
|
4902
5336
|
type: >-
|
|
4903
5337
|
directory
|
|
4904
5338
|
children:
|
|
5339
|
+
- name: >-
|
|
5340
|
+
createRelationship.test.ts
|
|
5341
|
+
type: >-
|
|
5342
|
+
file
|
|
4905
5343
|
- name: >-
|
|
4906
5344
|
createTable.test.ts
|
|
4907
5345
|
type: >-
|
|
4908
5346
|
file
|
|
5347
|
+
- name: >-
|
|
5348
|
+
deleteRelationship.test.ts
|
|
5349
|
+
type: >-
|
|
5350
|
+
file
|
|
4909
5351
|
- name: >-
|
|
4910
5352
|
deleteTable.test.ts
|
|
4911
5353
|
type: >-
|