From 61f315256e147bbc17170a153dab4cd8c5e5858d Mon Sep 17 00:00:00 2001 From: tywalch Date: Thu, 15 Feb 2024 11:14:57 -0500 Subject: [PATCH 1/2] Corrects upsert typing Upsert should return the same type as Put and Create. This must have been an oversight in `2.7.0` when the response type was changed. This is considered non-breaking as the response type was a partial of the same type being returned now. Thank you, @eXamadeus for bringing forward this discussion! --- CHANGELOG.md | 10 +++++++--- index.d.ts | 14 +------------- index.test-d.ts | 14 ++++++++++++++ package.json | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddf10d0f..45ae057f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -398,7 +398,7 @@ All notable changes to this project will be documented in this file. Breaking ch ## [2.7.0] - 2023-07-01 ### Fixed -- Fixes return typing for `delete`, `remove`, `update` and `upsert` operations. These types were incorrect and did not reflect the real values returned. Instead of breaking the APIs, changing response types to `T | null`, the new response type is now the Entity's key composite values by default. You can also now use the Execution Option `response` to get back the item as it exists in the table. This is the closed I could get to a non-breaking change that also fixes the incorrect return typing for these methods. +- Fixes return typing for `delete`, `remove`, `update` and `upsert` operations. These types were incorrect and did not reflect the real values returned. Instead of breaking the APIs, changing response types to `T | null`, the new response type is now the Entity's key composite values by default. You can also now use the Execution Option `response` to get back the item as it exists in the table. This is the closest I could get to a non-breaking change that also fixes the incorrect return typing for these methods. - Fixes typing for `contains` where conditions to accept collection element values (e.g., `set` and `list` type attributes). - The exported type `UpdateEntityItem` was incorrectly typed, it now includes the correct typing as the values that can be passed to the `set` method @@ -513,6 +513,10 @@ All notable changes to this project will be documented in this file. Breaking ch ### Added - Adds new query execution option `count` which allows you to specify a specific item count to return from a query. This is useful for cases where you must return a specific/consistent number of items from a query, a deceptively difficult task with DynamoDB and Single Table Design. -## [2.13.1] - 2023-01-23 +## [2.13.1] - 2024-01-23 ### Fixed -- Fixes custom attribute type extraction for union types with RecordItem. Patch provided by GitHub user @wentsul via [PR #346](https://github.com/tywalch/electrodb/pull/346). Thank you for another great addition! \ No newline at end of file +- Fixes custom attribute type extraction for union types with RecordItem. Patch provided by GitHub user @wentsul via [PR #346](https://github.com/tywalch/electrodb/pull/346). Thank you for another great addition! + +## [2.13.2] - 2024-02-15 +### Fixed +- Addresses [Discussion #349](https://github.com/tywalch/electrodb/discussions/349), upsert should return the same type as Put and Create. This must have been an oversight in `2.7.0` when the response type was changed. This is considered non-breaking as the response type was a partial of the same type being returned now. Thank you, @eXamadeus for bringing forward this discussion! \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 345ecd35..e5676813 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2884,19 +2884,7 @@ export type UpsertRecordGo = < Options extends UpdateQueryOptions = UpdateQueryOptions, >( options?: Options, -) => Options extends infer O - ? "response" extends keyof O - ? O["response"] extends "all_new" - ? Promise<{ data: T }> - : O["response"] extends "all_old" - ? Promise<{ data: T }> - : O["response"] extends "default" - ? Promise<{ data: Keys }> - : O["response"] extends "none" - ? Promise<{ data: null }> - : Promise<{ data: Partial }> - : Promise<{ data: Keys }> - : never; +) => Promise<{ data: T }>; export type PutRecordGo = < T = ResponseType, diff --git a/index.test-d.ts b/index.test-d.ts index a0531669..f4f9f28c 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1504,6 +1504,20 @@ expectAssignable<"paramtest">( entityWithoutSK.create(putItemFull).params<"paramtest">(), ); +// upsert (responses) +expectAssignable>( + entityWithoutSK.upsert(putItemFull) + .go() + .then((res) => res.data), +) + +expectAssignable>( + entityWithSK + .upsert(putItemFull) + .go() + .then((res) => res.data), +); + // Update let setItemFull = { attr4: "abc", diff --git a/package.json b/package.json index d51c2b09..977ccaf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electrodb", - "version": "2.13.1", + "version": "2.13.2", "description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb", "main": "index.js", "scripts": { From aa88c1dd332e07af60afbe40ba4b2d2bec87bc6c Mon Sep 17 00:00:00 2001 From: tywalch Date: Sun, 25 Feb 2024 14:56:25 -0500 Subject: [PATCH 2/2] Fixes flakey test Test used first element in test array as heuristic to determine a list was not equal. This lead to test flake and was never really that useful. --- test/ts_connected.crud.spec.ts | 45 ++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/test/ts_connected.crud.spec.ts b/test/ts_connected.crud.spec.ts index 50960a52..a3aca4bb 100644 --- a/test/ts_connected.crud.spec.ts +++ b/test/ts_connected.crud.spec.ts @@ -735,13 +735,15 @@ describe("Entity", () => { const accountNumber1 = uuid(); const accountNumber2 = uuid(); + const accountNumber3 = uuid(); const transactionId = uuid(); const description = uuid(); const source = uuid(); const thing1 = createThing(); const thing2 = createThing(); - const thingService = new Service({thing1, thing2}); + const thing3 = createThing(); + const thingService = new Service({thing1, thing2, thing3}); const events: Array<{ method: string; params: any }> = []; const logger = (event: ElectroEvent) => { @@ -829,7 +831,7 @@ describe("Entity", () => { TableName: table, }); - await thingService.transaction.write(({ thing1 }) => [ + const upsertTxn = await thingService.transaction.write(({ thing1 }) => [ thing1.upsert({ transactionId, accountNumber: accountNumber1, @@ -838,7 +840,7 @@ describe("Entity", () => { }).commit(), ]).go({ logger }); - await thing2 + const put1 = await thing2 .put({ transactionId, accountNumber: accountNumber2, @@ -847,6 +849,32 @@ describe("Entity", () => { }) .go({ logger }); + const upsert1 = await thing3.upsert({ + transactionId, + accountNumber: accountNumber3, + description, + source, + }).go( { logger }); + + expect(Object.keys(put1.data).sort()) + expect({ + ...upsert1.data + }).to.deep.equal({ + ...put1.data, + accountNumber: accountNumber3, + updatedAt: updatedAt, + createdAt: 2, + }); + + expect({ + ...upsertTxn.data[0].item + }).to.deep.equal({ + ...put1.data, + accountNumber: accountNumber1, + updatedAt: updatedAt, + createdAt: 2, + }); + const item1 = await thing1 .get({ transactionId, @@ -4141,8 +4169,15 @@ describe("pagination order", () => { .get(batch) .go() .then((res) => [res.data, res.unprocessed] as const); - - expect(batch[0]).to.not.deep.equal(unOrderedRecords[0]); + const notExactlyEqual = batch.some((item, i) => { + try { + expect(item).not.to.deep.equal(unOrderedRecords[i]); + return true; + } catch(err) { + return false; + } + }); + expect(notExactlyEqual).to.be.true; expect(unOrderedRecords) .to.be.an("array") .with.length(batch.length - totalUnprocessed);