diff --git a/packages/docs/operators/_args.yaml b/packages/docs/operators/_args.yaml index be72f5999..186853414 100644 --- a/packages/docs/operators/_args.yaml +++ b/packages/docs/operators/_args.yaml @@ -22,10 +22,11 @@ _ref: types: | ``` (key: string): any + (key: integer): any (all: boolean): any (arguments: { all?: boolean, - key?: string, + key?: string | integer, default?: any }): any ``` @@ -35,12 +36,15 @@ _ref: ###### string If the `_args` operator is called with a string argument, the value of the key in the `arguments` array is returned. If the value is not found, `null` is returned. Dot notation and [block list indexes](/lists) are supported. + ###### integer + If the `_args` operator is called with a integer argument, the value at that index in the `arguments` array is returned. If the value is not found, `null` is returned. Dot notation and [block list indexes](/lists) are supported. + ###### boolean If the `_args` operator is called with boolean argument `true`, the entire `arguments` array is returned. ###### object - `all: boolean`: If `all` is set to `true`, the entire `arguments` array is returned. One of `all` or `key` are required. - - `key: string`: The value of the key in the `arguments` array is returned. If the value is not found, `null`, or the specified default value is returned. Dot notation and [block list indexes](/lists) are supported. One of `all` or `key` are required. + - `key: string | integer`: The value of the key or index in the `arguments` array is returned. If the value is not found, `null`, or the specified default value is returned. Dot notation and [block list indexes](/lists) are supported. One of `all` or `key` are required. - `default: any`: A value to return if the `key` is not found in `arguments`. By default, `null` is returned if a value is not found. examples: | ###### Map over an array: diff --git a/packages/docs/operators/_get.yaml b/packages/docs/operators/_get.yaml index fc78351d8..a7fdacd2a 100644 --- a/packages/docs/operators/_get.yaml +++ b/packages/docs/operators/_get.yaml @@ -23,7 +23,7 @@ _ref: ``` (arguments: { from: any[] | object, - key: string, + key: string | integer, default?: any, }): any ``` @@ -33,7 +33,7 @@ _ref: arguments: | ###### object - `from: any[] | object`: __Required__ - The object to get the value from. - - `key: string`: __Required__ - The value of the key in the `from` object is returned. If the value is not found, `null`, or the specified default value is returned. Dot notation and [block list indexes](/lists) are supported. + - `key: string`: __Required__ - The value of the key or array index to get from the `from` object or array. If the value is not found, `null`, or the specified default value is returned. Dot notation and [block list indexes](/lists) are supported. - `default: any`: A value to return if the `key` is not found in `from`. By default, `null` is returned if a value is not found. examples: | diff --git a/packages/graphql/src/controllers/requestController.test.js b/packages/graphql/src/controllers/requestController.test.js index 2d69358c7..982c907ed 100644 --- a/packages/graphql/src/controllers/requestController.test.js +++ b/packages/graphql/src/controllers/requestController.test.js @@ -556,7 +556,7 @@ test('request properties operator error', async () => { requestId: 'requestId', connectionId: 'testConnection', properties: { - willError: { _state: 0 }, + willError: { _state: [] }, }, }; } @@ -566,7 +566,7 @@ test('request properties operator error', async () => { const controller = createRequestController(context); await expect(controller.callRequest(defaultInput)).rejects.toThrow(RequestError); await expect(controller.callRequest(defaultInput)).rejects.toThrow( - 'Error: Operator Error: _state params must be of type string, boolean or object. Received: 0 at requestId.' + 'Error: Operator Error: _state params must be of type string, integer, boolean or object. Received: [] at requestId.' ); }); @@ -578,7 +578,7 @@ test('connection properties operator error', async () => { type: 'TestConnection', connectionId: 'testConnection', properties: { - willError: { _state: 0 }, + willError: { _state: [] }, }, }; } @@ -589,7 +589,7 @@ test('connection properties operator error', async () => { const controller = createRequestController(context); await expect(controller.callRequest(defaultInput)).rejects.toThrow(RequestError); await expect(controller.callRequest(defaultInput)).rejects.toThrow( - 'Error: Operator Error: _state params must be of type string, boolean or object. Received: 0 at testConnection.' + 'Error: Operator Error: _state params must be of type string, integer, boolean or object. Received: [] at testConnection.' ); }); diff --git a/packages/helpers/src/applyArrayIndices.js b/packages/helpers/src/applyArrayIndices.js index f04e6d6ef..54fe01b49 100644 --- a/packages/helpers/src/applyArrayIndices.js +++ b/packages/helpers/src/applyArrayIndices.js @@ -19,6 +19,7 @@ import type from './type'; const applyArrayIndices = (arrayIndices, name) => { if (!type.isArray(arrayIndices)) return name; if (arrayIndices.length === 0) return name; + if (type.isNumber(name)) return name; const copy = JSON.parse(JSON.stringify(arrayIndices)); const index = copy.shift(); let newName; diff --git a/packages/helpers/test/applyArrayIndices.test.js b/packages/helpers/test/applyArrayIndices.test.js index 5c0107f88..5e4a13ff4 100644 --- a/packages/helpers/test/applyArrayIndices.test.js +++ b/packages/helpers/test/applyArrayIndices.test.js @@ -56,6 +56,11 @@ test('arrayIndices with 1 index, more than 1 $', () => { expect(applyArrayIndices([1], 'a.$.a.$.b')).toEqual('a.1.a.$.b'); }); +test('name is a number', () => { + expect(applyArrayIndices([], 1)).toEqual(1); + expect(applyArrayIndices([], 3.14)).toEqual(3.14); +}); + test('does not modify arrayIndices', () => { const arrayIndices = [1]; expect(applyArrayIndices(arrayIndices, 'a.$')).toEqual('a.1'); diff --git a/packages/helpers/test/get.test.js b/packages/helpers/test/get.test.js index d7add5936..97435a81a 100644 --- a/packages/helpers/test/get.test.js +++ b/packages/helpers/test/get.test.js @@ -130,6 +130,11 @@ test('return arr', () => { expect(get(objOne, 'a.b')).toEqual([]); }); +test('get by array index', () => { + const arr = [0, 1, 2]; + expect(get(arr, 1)).toEqual(1); +}); + // tests from // https://github.com/jonschlinkert/get-value/blob/master/test/units.js diff --git a/packages/operators/src/common/get.js b/packages/operators/src/common/get.js index 36c89c663..261d8a9a3 100644 --- a/packages/operators/src/common/get.js +++ b/packages/operators/src/common/get.js @@ -14,9 +14,10 @@ limitations under the License. */ -import { applyArrayIndices, get, type } from '@lowdefy/helpers'; +import { type } from '@lowdefy/helpers'; +import getFromObject from '../getFromObject'; -function _get({ params, location, arrayIndices }) { +function _get({ arrayIndices, env, location, params }) { if (!type.isObject(params)) { throw new Error( `Operator Error: _get takes an object as params. Received: ${JSON.stringify( @@ -24,17 +25,20 @@ function _get({ params, location, arrayIndices }) { )} at ${location}.` ); } - - if (!type.isString(params.key)) { + if (!type.isObject(params.from) && !type.isArray(params.from)) { throw new Error( - `Operator Error: _get.key takes a string. Received ${JSON.stringify(params)} at ${location}.` + `Operator Error: _get.from is not an object or array. Received: ${JSON.stringify( + params + )} at ${location}.` ); } - if (!type.isObject(params.from) && !type.isArray(params.from)) { - return null; - } - return get(params.from, applyArrayIndices(arrayIndices, params.key), { - default: get(params, 'default', { default: null }), + return getFromObject({ + arrayIndices, + env, + location, + object: params.from, + operator: '_get', + params, }); } diff --git a/packages/operators/src/getFromObject.js b/packages/operators/src/getFromObject.js index 75d1e0b61..24701f581 100644 --- a/packages/operators/src/getFromObject.js +++ b/packages/operators/src/getFromObject.js @@ -29,10 +29,10 @@ function getFromObject({ env, }) { if (params === true) params = { all: true }; - if (type.isString(params)) params = { key: params }; + if (type.isString(params) || type.isInt(params)) params = { key: params }; if (!type.isObject(params)) { throw new Error( - `Operator Error: ${operator} params must be of type string, boolean or object. Received: ${JSON.stringify( + `Operator Error: ${operator} params must be of type string, integer, boolean or object. Received: ${JSON.stringify( params )} at ${location}.` ); @@ -56,9 +56,9 @@ function getFromObject({ }); } if (params.all === true) return serializer.copy(object); - if (!type.isString(params.key)) { + if (!type.isString(params.key) && !type.isInt(params.key)) { throw new Error( - `Operator Error: ${operator}.key must be of type string. Received: ${JSON.stringify( + `Operator Error: ${operator}.key must be of type string or integer. Received: ${JSON.stringify( params )} at ${location}.` ); diff --git a/packages/operators/test/common/function.test.js b/packages/operators/test/common/function.test.js index d171f48a4..66fcae079 100644 --- a/packages/operators/test/common/function.test.js +++ b/packages/operators/test/common/function.test.js @@ -52,7 +52,7 @@ test('NodeParser, _function throws on parser errors', () => { const params = { __state: [] }; const fn = _function({ location, params, parser }); expect(fn).toThrow( - 'Error: Operator Error: _state params must be of type string, boolean or object. Received: [] at location.' + 'Error: Operator Error: _state params must be of type string, integer, boolean or object. Received: [] at location.' ); }); @@ -78,6 +78,6 @@ test('WebParser, _function throws on parser errors', () => { const params = { __state: [] }; const fn = _function({ location, params, parser }); expect(fn).toThrow( - 'Error: Operator Error: _state params must be of type string, boolean or object. Received: [] at location.' + 'Error: Operator Error: _state params must be of type string, integer, boolean or object. Received: [] at location.' ); }); diff --git a/packages/operators/test/getFromObject.test.js b/packages/operators/test/getFromObject.test.js index 2f5087e2a..f354495dc 100644 --- a/packages/operators/test/getFromObject.test.js +++ b/packages/operators/test/getFromObject.test.js @@ -57,6 +57,36 @@ test('get a field from an object, key as param', () => { expect(res).toEqual('string'); }); +test('get a field from an array, integer index, shorthand', () => { + const params = 1; + const res = getFromObject({ + params, + object: [1, 2, 3], + context, + contexts, + arrayIndices: defaultArrayIndices, + operator, + location, + env: 'node', + }); + expect(res).toEqual(2); +}); + +test('get a field from an array, integer index', () => { + const params = { key: 1 }; + const res = getFromObject({ + params, + object: [1, 2, 3], + context, + contexts, + arrayIndices: defaultArrayIndices, + operator, + location, + env: 'node', + }); + expect(res).toEqual(2); +}); + test('get a field from an object, shorthand, not found returns null', () => { const params = 'not_there'; const res = getFromObject({ @@ -218,7 +248,7 @@ test('params not correct type', () => { location, env: 'node', }) - ).toThrow('Operator Error: _operator params must be of type string, boolean or object.'); + ).toThrow('Operator Error: _operator params must be of type string, integer, boolean or object.'); }); test('params key not a string', () => { @@ -233,7 +263,7 @@ test('params key not a string', () => { location, env: 'node', }) - ).toThrow('Operator Error: _operator.key must be of type string.'); + ).toThrow('Operator Error: _operator.key must be of type string or integer.'); }); test('replace arrayIndices', () => { diff --git a/packages/operators/test/node/get.test.js b/packages/operators/test/node/get.test.js index af5ceda17..0db926983 100644 --- a/packages/operators/test/node/get.test.js +++ b/packages/operators/test/node/get.test.js @@ -83,15 +83,11 @@ test('_get from: null', () => { }); test('_get key: int', () => { - const input = { _get: { from: object, key: 1 } }; + const input = { _get: { from: [1, 2, 3], key: 1 } }; const parser = new NodeParser(); const res = parser.parse({ input, location: 'locationId' }); - expect(res.output).toBe(null); - expect(res.errors).toMatchInlineSnapshot(` - Array [ - [Error: Operator Error: _get.key takes a string. Received {"from":{"string":"Some String","number":42,"arr":[{"a":"a1"},{"a":"a2"}]},"key":1} at locationId.], - ] - `); + expect(res.output).toBe(2); + expect(res.errors).toMatchInlineSnapshot(`Array []`); }); test('_get replace key arrayIndices', () => { diff --git a/packages/operators/test/web/event_log.test.js b/packages/operators/test/web/event_log.test.js index 1e5e97dc4..e789f2a30 100644 --- a/packages/operators/test/web/event_log.test.js +++ b/packages/operators/test/web/event_log.test.js @@ -120,7 +120,7 @@ test('_event_log null', () => { expect(res.output).toBe(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _event_log params must be of type string, boolean or object. Received: null at locationId.], + [Error: Operator Error: _event_log params must be of type string, integer, boolean or object. Received: null at locationId.], ] `); }); @@ -201,7 +201,7 @@ test('_event_log param object invalid', () => { expect(res.output).toEqual(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _event_log.key must be of type string. Received: {"other":true} at locationId.], + [Error: Operator Error: _event_log.key must be of type string or integer. Received: {"other":true} at locationId.], ] `); }); @@ -215,7 +215,7 @@ test('_event_log param array', () => { expect(res.output).toEqual(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _event_log params must be of type string, boolean or object. Received: ["string"] at locationId.], + [Error: Operator Error: _event_log params must be of type string, integer, boolean or object. Received: ["string"] at locationId.], ] `); }); diff --git a/packages/operators/test/web/get.test.js b/packages/operators/test/web/get.test.js index 2d2dd3979..c733292d6 100644 --- a/packages/operators/test/web/get.test.js +++ b/packages/operators/test/web/get.test.js @@ -130,13 +130,9 @@ test('_get from: null', () => { }); test('_get key: int', () => { - const input = { _get: { from: object, key: 1 } }; + const input = { _get: { from: [1, 2, 3], key: 1 } }; const parser = new WebParser({ context, contexts }); const res = parser.parse({ input, location: 'locationId', arrayIndices }); - expect(res.output).toBe(null); - expect(res.errors).toMatchInlineSnapshot(` - Array [ - [Error: Operator Error: _get.key takes a string. Received {"from":{"string":"Some String","number":42,"arr":[{"a":"a1"},{"a":"a2"}]},"key":1} at locationId.], - ] - `); + expect(res.output).toBe(2); + expect(res.errors).toMatchInlineSnapshot(`Array []`); }); diff --git a/packages/operators/test/web/request_details.test.js b/packages/operators/test/web/request_details.test.js index de982cfaa..fbfe3a0c0 100644 --- a/packages/operators/test/web/request_details.test.js +++ b/packages/operators/test/web/request_details.test.js @@ -95,7 +95,7 @@ test('_request_details null', () => { expect(res.output).toBe(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _request_details params must be of type string, boolean or object. Received: null at locationId.], + [Error: Operator Error: _request_details params must be of type string, integer, boolean or object. Received: null at locationId.], ] `); }); @@ -166,7 +166,7 @@ test('_request_details param object invalid', () => { expect(res.output).toEqual(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _request_details.key must be of type string. Received: {"other":true} at locationId.], + [Error: Operator Error: _request_details.key must be of type string or integer. Received: {"other":true} at locationId.], ] `); }); @@ -180,7 +180,7 @@ test('_request_details param array', () => { expect(res.output).toEqual(null); expect(res.errors).toMatchInlineSnapshot(` Array [ - [Error: Operator Error: _request_details params must be of type string, boolean or object. Received: ["string"] at locationId.], + [Error: Operator Error: _request_details params must be of type string, integer, boolean or object. Received: ["string"] at locationId.], ] `); });