fix(operators): Allow get from object to take an integer argument.

This commit is contained in:
SamTolmay 2021-02-12 11:58:02 +02:00
parent 8d92f5f71a
commit e8bdbd96a3
14 changed files with 87 additions and 46 deletions

View File

@ -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:

View File

@ -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: |

View File

@ -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.'
);
});

View File

@ -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;

View File

@ -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');

View File

@ -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

View File

@ -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,
});
}

View File

@ -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}.`
);

View File

@ -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.'
);
});

View File

@ -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', () => {

View File

@ -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', () => {

View File

@ -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.],
]
`);
});

View File

@ -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 []`);
});

View File

@ -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.],
]
`);
});