@adobe-commerce/aio-toolkit 1.2.1 → 1.2.2
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 +93 -0
- package/README.md +29 -20
- package/dist/index.d.mts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +3315 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3309 -89
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,99 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.2] - 2026-04-01
|
|
9
|
+
|
|
10
|
+
### 🐛 Bug Fixes
|
|
11
|
+
|
|
12
|
+
- **fix(abdb): Fixed `AbdbRepository` update path — `_updated_at` was placed outside `$set`**
|
|
13
|
+
|
|
14
|
+
`save(payload, id)` delegated to `updateOne` with `{ $set: payload }` as the payload, but `updateOne` then spread that into `{ $set: payload, _updated_at: now }`. The `_updated_at` key landed at the top level alongside `$set`, making it an invalid MongoDB update document. The `$set` wrapping is now done inside `updateOne` and `update`, so timestamps are always nested correctly.
|
|
15
|
+
|
|
16
|
+
- **fix(abdb): Fixed `update` method passing an array to `updateMany`**
|
|
17
|
+
|
|
18
|
+
`update` (previously `updateAll`) accepted `Array<Partial<T>> | Partial<T>` and always converted the input to an array before passing it as the second argument to `updateMany`. MongoDB's `updateMany` expects a **single** update document, not an array — this caused silent failures at runtime. The method now accepts a single `Partial<T>` and wraps it in `{ $set: ... }`.
|
|
19
|
+
|
|
20
|
+
- **fix(abdb): Fixed full schema validation on partial update payloads**
|
|
21
|
+
|
|
22
|
+
`updateOne` and `update` were calling `this._collection.validate()` (full validation — all required fields must be present) on update payloads. This caused spurious validation errors when patching a subset of fields. Both methods now use `_validatePartial`, which only checks the columns present in the payload.
|
|
23
|
+
|
|
24
|
+
### ✨ Features
|
|
25
|
+
|
|
26
|
+
- **feat(abdb): Expanded `AbdbRepository` API with granular single- and bulk-operation methods**
|
|
27
|
+
|
|
28
|
+
Five new public methods covering the full MongoDB CRUD surface:
|
|
29
|
+
|
|
30
|
+
| New method | Description |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `findById(id)` | Shorthand for `findOne({ _id: new ObjectId(id) })` |
|
|
33
|
+
| `insertOne(payload)` | Single-document insert via `insertOne`; stamps timestamps and validates |
|
|
34
|
+
| `updateOne(payload, filter?, options?)` | Single-document update via `updateOne` with `$set` wrapping and partial validation |
|
|
35
|
+
| `deleteOne(filter?)` | Single-document delete via `deleteOne`; returns raw result |
|
|
36
|
+
| `deleteById(id)` | Shorthand for `deleteOne({ _id: new ObjectId(id) })` |
|
|
37
|
+
|
|
38
|
+
- **feat(abdb): `save` delegates to `insertOne` / `updateOne`** — eliminates duplicated timestamp-stamping and validation logic.
|
|
39
|
+
|
|
40
|
+
- **feat(abdb): Split `exists` into `isIdExists` and `exists(filter, options?)`**
|
|
41
|
+
|
|
42
|
+
The original `exists(id: string)` only supported lookup by `_id`. It has been renamed to `isIdExists(id)` (preserving the empty-id guard that returns `false` without hitting the DB), and a new general-purpose `exists(filter?, options?)` method has been added that accepts any filter and proxies to `count`.
|
|
43
|
+
|
|
44
|
+
- **feat(abdb): `count` now accepts an optional `options` parameter**
|
|
45
|
+
|
|
46
|
+
`count(filter?, options?)` now forwards `options` to the underlying `countDocuments` call, enabling fine-grained control such as `{ limit: 1 }` for fast existence probes.
|
|
47
|
+
|
|
48
|
+
### ⚠️ Breaking Changes
|
|
49
|
+
|
|
50
|
+
- **`exists(id: string)` renamed to `isIdExists(id: string)`**
|
|
51
|
+
|
|
52
|
+
`exists` now accepts a general-purpose filter object. Any caller using `repo.exists(someId)` must switch to `repo.isIdExists(someId)`.
|
|
53
|
+
|
|
54
|
+
- **`delete(id: string)` → `delete(filter: AbdbRepositoryFilter)`**
|
|
55
|
+
|
|
56
|
+
`delete` previously accepted a string `_id` and silently no-oped when the id was empty. It now accepts a filter object and uses `deleteMany` under the hood (consistent with `deleteAll`). Use `deleteById(id)` for the old single-by-id behaviour.
|
|
57
|
+
|
|
58
|
+
- **`insertAll` renamed to `insert`** — identical behaviour, new name aligns with `insertOne`.
|
|
59
|
+
|
|
60
|
+
- **`updateAll` renamed to `update`** — identical behaviour (plus bug fixes above), new name aligns with `updateOne`.
|
|
61
|
+
|
|
62
|
+
- **Return types of all mutation methods changed to `Promise<Record<string, any>>`**
|
|
63
|
+
|
|
64
|
+
`save`, `insert`, `insertOne`, `update`, `updateOne`, `delete`, `deleteOne`, `deleteById`, and `deleteAll` previously returned `Promise<string>`, `Promise<string[]>`, `Promise<number>`, or `Promise<void>`. All now return the raw MongoDB result document so callers have access to `acknowledged`, `insertedId`, `insertedIds`, `modifiedCount`, `deletedCount`, etc.
|
|
65
|
+
|
|
66
|
+
### 💡 Migration Guide
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// existence check by id — OLD
|
|
70
|
+
const found = await repo.exists(id);
|
|
71
|
+
// existence check by id — NEW
|
|
72
|
+
const found = await repo.isIdExists(id);
|
|
73
|
+
|
|
74
|
+
// general existence check (new) — by any filter
|
|
75
|
+
const active = await repo.exists({ status: 'active' });
|
|
76
|
+
|
|
77
|
+
// delete by id — OLD
|
|
78
|
+
await repo.delete(id);
|
|
79
|
+
// delete by id — NEW
|
|
80
|
+
await repo.deleteById(id);
|
|
81
|
+
|
|
82
|
+
// bulk insert — OLD
|
|
83
|
+
const ids = await repo.insertAll([...]);
|
|
84
|
+
// bulk insert — NEW
|
|
85
|
+
const result = await repo.insert([...]); // result.insertedIds contains the ids
|
|
86
|
+
|
|
87
|
+
// bulk update — OLD
|
|
88
|
+
await repo.updateAll({ active: false }, { email: 'bob@example.com' });
|
|
89
|
+
// bulk update — NEW
|
|
90
|
+
await repo.update({ active: false }, { email: 'bob@example.com' });
|
|
91
|
+
|
|
92
|
+
// return value of save (insert path) — OLD: string _id
|
|
93
|
+
const id = await repo.save({ name: 'Jane', email: 'jane@example.com' });
|
|
94
|
+
// return value of save (insert path) — NEW: raw insertOne result
|
|
95
|
+
const result = await repo.save({ name: 'Jane', email: 'jane@example.com' });
|
|
96
|
+
// result.insertedId contains the new _id
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
8
101
|
## [1.2.1] - 2026-03-31
|
|
9
102
|
|
|
10
103
|
### ✨ Features
|
package/README.md
CHANGED
|
@@ -848,7 +848,7 @@ A generic CRUD repository that wraps an `AbdbCollection` and holds the IMS token
|
|
|
848
848
|
##### Basic usage
|
|
849
849
|
|
|
850
850
|
```javascript
|
|
851
|
-
const { AbdbRepository
|
|
851
|
+
const { AbdbRepository } = require('@adobe-commerce/aio-toolkit');
|
|
852
852
|
const { generateAccessToken } = require('@adobe/aio-sdk').Core.AuthClient;
|
|
853
853
|
const UserCollection = require('@lib/UserCollection');
|
|
854
854
|
|
|
@@ -858,11 +858,12 @@ exports.main = async (params) => {
|
|
|
858
858
|
|
|
859
859
|
const repo = new AbdbRepository(new UserCollection(), accessToken);
|
|
860
860
|
|
|
861
|
-
// Insert — returns the new
|
|
862
|
-
const
|
|
861
|
+
// Insert — returns raw insertOne result (result.insertedId contains the new _id)
|
|
862
|
+
const insertResult = await repo.save({ first_name: 'Jane', last_name: 'Doe', email: 'jane@example.com' });
|
|
863
|
+
const id = insertResult.insertedId;
|
|
863
864
|
|
|
864
|
-
// Read
|
|
865
|
-
const doc = await repo.
|
|
865
|
+
// Read by _id (shorthand)
|
|
866
|
+
const doc = await repo.findById(id);
|
|
866
867
|
|
|
867
868
|
// Read one by any field
|
|
868
869
|
const byEmail = await repo.findOne({ email: 'jane@example.com' });
|
|
@@ -874,8 +875,8 @@ exports.main = async (params) => {
|
|
|
874
875
|
// Partial update — only provided fields are validated; required fields already in the DB are not re-checked
|
|
875
876
|
await repo.save({ first_name: 'Janet' }, id);
|
|
876
877
|
|
|
877
|
-
// Delete
|
|
878
|
-
await repo.
|
|
878
|
+
// Delete by _id
|
|
879
|
+
await repo.deleteById(id);
|
|
879
880
|
};
|
|
880
881
|
```
|
|
881
882
|
|
|
@@ -896,21 +897,26 @@ These are added once per collection instance, so re-using the same collection ac
|
|
|
896
897
|
|
|
897
898
|
| Method | Description | Returns |
|
|
898
899
|
|---|---|---|
|
|
899
|
-
| `save(payload)` | Insert
|
|
900
|
-
| `save(payload, id)` |
|
|
901
|
-
| `
|
|
900
|
+
| `save(payload)` | Insert via `insertOne` (full validation, stamps both timestamps) | `Promise<Record<string, any>>` — raw `insertOne` result |
|
|
901
|
+
| `save(payload, id)` | Update via `updateOne` with `upsert: true` (partial validation, stamps `_updated_at`) | `Promise<Record<string, any>>` — raw `updateOne` result |
|
|
902
|
+
| `insertOne(payload)` | Single-document insert (full validation, stamps both timestamps) | `Promise<Record<string, any>>` — raw `insertOne` result (e.g. `insertedId`) |
|
|
903
|
+
| `updateOne(payload, filter?, options?)` | Single-document update via `{ $set: payload }` (partial validation, stamps `_updated_at`) | `Promise<Record<string, any>>` — raw `updateOne` result (e.g. `modifiedCount`) |
|
|
904
|
+
| `findOne(filter)` | First document matching filter, e.g. `{ email: 'a@b.com' }` | `Promise<T \| null>` |
|
|
905
|
+
| `findById(id)` | Shorthand for `findOne({ _id: new ObjectId(id) })` | `Promise<T \| null>` |
|
|
902
906
|
| `find(filter?)` | All documents matching filter (default: all) | `Promise<T[]>` |
|
|
903
|
-
| `
|
|
904
|
-
| `
|
|
905
|
-
| `
|
|
907
|
+
| `isIdExists(id)` | Returns `true` if a document with the given `_id` exists (no-op for empty id) | `Promise<boolean>` |
|
|
908
|
+
| `exists(filter?, options?)` | Returns `true` if any document matching `filter` exists via `countDocuments` | `Promise<boolean>` |
|
|
909
|
+
| `deleteOne(filter?)` | Delete first matching document via `deleteOne` | `Promise<Record<string, any>>` — raw `deleteOne` result |
|
|
910
|
+
| `deleteById(id)` | Shorthand for `deleteOne({ _id: new ObjectId(id) })` | `Promise<Record<string, any>>` |
|
|
911
|
+
| `count(filter?, options?)` | Count matching documents via `countDocuments` (default: all) | `Promise<number>` |
|
|
906
912
|
|
|
907
913
|
**Bulk operations (single DB round-trip each):**
|
|
908
914
|
|
|
909
915
|
| Method | Description | Returns |
|
|
910
916
|
|---|---|---|
|
|
911
|
-
| `
|
|
912
|
-
| `
|
|
913
|
-
| `
|
|
917
|
+
| `insert(payloads[])` | Bulk insert via `insertMany` — each payload stamped and validated | `Promise<Record<string, any>>` — raw `insertMany` result (e.g. `insertedIds`) |
|
|
918
|
+
| `update(payload, filter?, options?)` | Bulk update via `updateMany` with `{ $set: payload }` — stamps `_updated_at`, partial validation | `Promise<Record<string, any>>` — raw `updateMany` result (e.g. `modifiedCount`) |
|
|
919
|
+
| `delete(filter?)` | Bulk delete via `deleteMany` (default: all documents) | `Promise<Record<string, any>>` — raw `deleteMany` result (e.g. `deletedCount`) |
|
|
914
920
|
|
|
915
921
|
**Accessors:**
|
|
916
922
|
|
|
@@ -930,19 +936,22 @@ const repo = new AbdbRepository(new UserCollection(), accessToken, 'emea');
|
|
|
930
936
|
|
|
931
937
|
```javascript
|
|
932
938
|
// Insert multiple documents in one DB call
|
|
933
|
-
const
|
|
939
|
+
const result = await repo.insert([
|
|
934
940
|
{ first_name: 'Alice', last_name: 'Smith', email: 'alice@example.com' },
|
|
935
941
|
{ first_name: 'Bob', last_name: 'Jones', email: 'bob@example.com' },
|
|
936
942
|
]);
|
|
943
|
+
console.log(result.insertedIds); // array of inserted _id values
|
|
937
944
|
|
|
938
945
|
// Update all matching documents in one DB call
|
|
939
|
-
await repo.
|
|
946
|
+
const updateResult = await repo.update({ active: false }, { email: 'bob@example.com' });
|
|
947
|
+
console.log(updateResult.modifiedCount); // number of documents updated
|
|
940
948
|
|
|
941
949
|
// Delete all matching documents in one DB call
|
|
942
|
-
await repo.
|
|
950
|
+
const deleteResult = await repo.delete({ active: false });
|
|
951
|
+
console.log(deleteResult.deletedCount); // number of documents deleted
|
|
943
952
|
|
|
944
953
|
// Delete everything in the collection
|
|
945
|
-
await repo.
|
|
954
|
+
await repo.delete();
|
|
946
955
|
```
|
|
947
956
|
|
|
948
957
|
### 🏪 Commerce Components
|
package/dist/index.d.mts
CHANGED
|
@@ -281,13 +281,18 @@ declare class AbdbRepository<T extends AbdbRecord = AbdbRecord> {
|
|
|
281
281
|
getCollection(): AbdbCollection;
|
|
282
282
|
find(filter?: AbdbRepositoryFilter): Promise<T[]>;
|
|
283
283
|
findOne(filter: AbdbRepositoryFilter): Promise<T | null>;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
284
|
+
findById(id: string): Promise<T | null>;
|
|
285
|
+
delete(filter?: AbdbRepositoryFilter): Promise<Record<string, any>>;
|
|
286
|
+
deleteOne(filter?: AbdbRepositoryFilter): Promise<Record<string, any>>;
|
|
287
|
+
deleteById(id: string): Promise<Record<string, any>>;
|
|
288
|
+
insert(payloads: Array<Partial<T>>): Promise<Record<string, any>>;
|
|
289
|
+
insertOne(payload: Partial<T>): Promise<Record<string, any>>;
|
|
290
|
+
update(payload: Partial<T>, filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<Record<string, any>>;
|
|
291
|
+
updateOne(payload: Partial<T>, filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<Record<string, any>>;
|
|
292
|
+
save(payload?: Partial<T>, id?: string): Promise<Record<string, any>>;
|
|
293
|
+
isIdExists(id: string): Promise<boolean>;
|
|
294
|
+
exists(filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<boolean>;
|
|
295
|
+
count(filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<number>;
|
|
291
296
|
private _validatePartial;
|
|
292
297
|
}
|
|
293
298
|
|
package/dist/index.d.ts
CHANGED
|
@@ -281,13 +281,18 @@ declare class AbdbRepository<T extends AbdbRecord = AbdbRecord> {
|
|
|
281
281
|
getCollection(): AbdbCollection;
|
|
282
282
|
find(filter?: AbdbRepositoryFilter): Promise<T[]>;
|
|
283
283
|
findOne(filter: AbdbRepositoryFilter): Promise<T | null>;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
284
|
+
findById(id: string): Promise<T | null>;
|
|
285
|
+
delete(filter?: AbdbRepositoryFilter): Promise<Record<string, any>>;
|
|
286
|
+
deleteOne(filter?: AbdbRepositoryFilter): Promise<Record<string, any>>;
|
|
287
|
+
deleteById(id: string): Promise<Record<string, any>>;
|
|
288
|
+
insert(payloads: Array<Partial<T>>): Promise<Record<string, any>>;
|
|
289
|
+
insertOne(payload: Partial<T>): Promise<Record<string, any>>;
|
|
290
|
+
update(payload: Partial<T>, filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<Record<string, any>>;
|
|
291
|
+
updateOne(payload: Partial<T>, filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<Record<string, any>>;
|
|
292
|
+
save(payload?: Partial<T>, id?: string): Promise<Record<string, any>>;
|
|
293
|
+
isIdExists(id: string): Promise<boolean>;
|
|
294
|
+
exists(filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<boolean>;
|
|
295
|
+
count(filter?: AbdbRepositoryFilter, options?: Record<string, any>): Promise<number>;
|
|
291
296
|
private _validatePartial;
|
|
292
297
|
}
|
|
293
298
|
|