Skip to content

Commit

Permalink
Collections: pass state into keygen (#864)
Browse files Browse the repository at this point in the history
* collections: better error handling on keygen function

* collections: pass state into keygen function

* version: [email protected]
  • Loading branch information
josephjclark authored Dec 11, 2024
1 parent 78d2064 commit aa9315c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 5 deletions.
15 changes: 15 additions & 0 deletions packages/collections/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# @openfn/language-collections

## 0.7.0

### Minor Changes

- c95ccba: BREAKING: Pass state into the keygen function on `set()`. This allows
state to be used to calculate keys.

When calling `collections.set(collection, keygen, values)`, the keygen
function signature has changed from `(value, index) => key` to
`(value, state, index) => key`.

### Patch Changes

- cdb01db: Better error handling if the keygen function is invalid

## 0.6.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/collections/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openfn/language-collections",
"version": "0.6.2",
"version": "0.7.0",
"description": "OpenFn collections adaptor",
"type": "module",
"exports": {
Expand Down
18 changes: 14 additions & 4 deletions packages/collections/src/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,20 @@ export function set(name, keyGen, values) {
// Otherwise we convert the incoming values into an array of key/value pairs
// Note that we may need to serialize json to string
// the hardest bit is knowing when to deserialize
kvPairs = dataArray.map((value, index) => ({
key: keyGenFn(value, index),
value: JSON.stringify(value),
}));
kvPairs = dataArray.map((value, index) => {
const key = keyGenFn(value, state, index);
if (typeof key !== 'string') {
const e = new Error('KEYGEN_ERROR');
e.description =
'The key generator function returned a non-string value which is not a valid key';
e.fix = `The second argument to set() is a key or key-generator function. If you pass a function, make sure the function returns a string (a key). Note that this function is NOT a state reference and does not support lazy state ($)`;
throw e;
}
return {
key,
value: JSON.stringify(value),
};
});
}

while (kvPairs.length) {
Expand Down
38 changes: 38 additions & 0 deletions packages/collections/test/Adaptor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,32 @@ describe('set', () => {
expect(err.message).to.eql('ILLEGAL_ARGUMENTS');
});

it("should throw keygen doesn't return a string", async () => {
const { state } = init();
state.configuration = {};

let err;
try {
await collections.set(COLLECTION, () => true, { x: 1 })(state);
} catch (e) {
err = e;
}
expect(err.message).to.eql('KEYGEN_ERROR');
});

it('should throw keygen looks like a state reference', async () => {
const { state } = init();
state.configuration = {};

let err;
try {
await collections.set(COLLECTION, state => state, { x: 1 })(state);
} catch (e) {
err = e;
}
expect(err.message).to.eql('KEYGEN_ERROR');
});

it('should set a single item', async () => {
const { state } = init();

Expand Down Expand Up @@ -463,6 +489,18 @@ describe('set', () => {
expect(result).to.eql(item);
});

it('should pass state to the keygen function', async () => {
const { state } = init();
state.key = 'x';

const item = { id: 'x' };

await collections.set(COLLECTION, (_key, state) => state.key, item)(state);

const result = api.asJSON(COLLECTION, 'x');
expect(result).to.eql(item);
});

it('should set a single array-type item with a reference', async () => {
const { state } = init();

Expand Down

0 comments on commit aa9315c

Please sign in to comment.