Skip to content

Commit c121cfa

Browse files
committed
Merge remote-tracking branch 'origin/develop' into develop
2 parents 8e725fc + 27e5d24 commit c121cfa

File tree

3 files changed

+74
-128
lines changed

3 files changed

+74
-128
lines changed

src/compile.test.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ describe('error handling', () => {
9494
{ name: 'Joe', age: 32, scores: [6.1, 8.1] }
9595
]
9696
}
97-
const query = ['pipe', ['get', 'participants'], ['map', ['pipe', ['get', 'scores'], ['sum']]]]
97+
const query = [
98+
'pipe',
99+
['get', 'participants'],
100+
['map', ['pipe', ['get', 'scores'], ['map', ['round']], ['sum']]]
101+
]
98102

99103
let actualErr = undefined
100104
try {
@@ -103,15 +107,18 @@ describe('error handling', () => {
103107
actualErr = err
104108
}
105109

106-
expect(actualErr?.message).toBe('Array expected')
110+
expect(actualErr?.message).toBe("Cannot read properties of null (reading 'map')")
107111
expect(actualErr?.jsonquery).toEqual([
108112
{ data: scoreData, query },
109113
{
110114
data: scoreData.participants,
111-
query: ['map', ['pipe', ['get', 'scores'], ['sum']]]
115+
query: ['map', ['pipe', ['get', 'scores'], ['map', ['round']], ['sum']]]
112116
},
113-
{ data: { name: 'Emily', age: 19 }, query: ['pipe', ['get', 'scores'], ['sum']] },
114-
{ data: null, query: ['sum'] }
117+
{
118+
data: { name: 'Emily', age: 19 },
119+
query: ['pipe', ['get', 'scores'], ['map', ['round']], ['sum']]
120+
},
121+
{ data: null, query: ['map', ['round']] }
115122
])
116123
})
117124
})

src/functions.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,15 @@ export function buildFunction(fn: (...args: unknown[]) => unknown): FunctionBuil
3030
const sortableTypes = { boolean: 0, number: 1, string: 2 }
3131
const otherTypes = 3
3232

33-
const gt = (a: unknown, b: unknown) => {
34-
if (typeof a !== typeof b || !((typeof a) in sortableTypes)) {
35-
throwTypeError('Two numbers, strings, or booleans expected')
36-
}
37-
38-
return a > b
39-
}
33+
const gt = (a: unknown, b: unknown) =>
34+
typeof a === typeof b && (typeof a) in sortableTypes ? a > b : false
4035

4136
const gte = (a: unknown, b: unknown) => isEqual(a, b) || gt(a, b)
42-
const lt = (a: unknown, b: unknown) => gt(b, a)
43-
const lte = (a: unknown, b: unknown) => gte(b, a)
37+
38+
const lt = (a: unknown, b: unknown) =>
39+
typeof a === typeof b && (typeof a) in sortableTypes ? a < b : false
40+
41+
const lte = (a: unknown, b: unknown) => isEqual(a, b) || lt(a, b)
4442

4543
export const functions: FunctionBuildersMap = {
4644
pipe: (...entries: JSONQuery[]) => {
@@ -277,13 +275,22 @@ export const functions: FunctionBuildersMap = {
277275
values: () => Object.values,
278276

279277
prod: () => (data: number[]) => reduce(data, (a, b) => a * b),
280-
sum: () => (data: number[]) => reduce(data, (a, b) => a + b, 0),
281-
average: () => (data: number[]) => reduce(data, (a, b) => a + b) / data.length,
282-
min: () => (data: number[]) => reduce(data, (a, b) => Math.min(a, b), null),
283-
max: () => (data: number[]) => reduce(data, (a, b) => Math.max(a, b), null),
284278

285-
and: buildFunction((...args: unknown[]) => reduce(args, (a, b) => !!(a && b))),
286-
or: buildFunction((...args: unknown[]) => reduce(args, (a, b) => !!(a || b))),
279+
sum: () => (data: number[]) =>
280+
isArray(data) ? data.reduce((a, b) => a + b, 0) : throwArrayExpected(),
281+
282+
average: () => (data: number[]) =>
283+
isArray(data)
284+
? data.length > 0
285+
? data.reduce((a, b) => a + b) / data.length
286+
: null
287+
: throwArrayExpected(),
288+
289+
min: () => (data: number[]) => reduce(data, (a, b) => Math.min(a, b)),
290+
max: () => (data: number[]) => reduce(data, (a, b) => Math.max(a, b)),
291+
292+
and: buildFunction((...data: unknown[]) => reduce(data, (a, b) => !!(a && b))),
293+
or: buildFunction((...data: unknown[]) => reduce(data, (a, b) => !!(a || b))),
287294
not: buildFunction((a: unknown) => !a),
288295

289296
exists: (queryGet: JSONQueryFunction) => {
@@ -355,26 +362,22 @@ export const functions: FunctionBuildersMap = {
355362

356363
const truthy = (x: unknown) => x !== null && x !== 0 && x !== false
357364

358-
const reduce = <T>(
359-
data: T[],
360-
callback: (previousValue: T, currentValue: T) => T,
361-
initialValue?: T
362-
): T => {
365+
const reduce = <T>(data: T[], callback: (previousValue: T, currentValue: T) => T): T => {
363366
if (!isArray(data)) {
364-
throwTypeError('Array expected')
365-
}
366-
367-
if (initialValue !== undefined) {
368-
return data.reduce(callback, initialValue)
367+
throwArrayExpected()
369368
}
370369

371370
if (data.length === 0) {
372-
throwTypeError('Non-empty array expected')
371+
return null
373372
}
374373

375374
return data.reduce(callback)
376375
}
377376

377+
const throwArrayExpected = () => {
378+
throwTypeError('Array expected')
379+
}
380+
378381
export const throwTypeError = (message: string) => {
379382
throw new TypeError(message)
380383
}

test-suite/compile.test.json

Lines changed: 33 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,12 +1127,12 @@
11271127
},
11281128
{
11291129
"category": "prod",
1130-
"description": "should throw an error when calculating the prod of an empty array",
1130+
"description": "should return null when calculating the prod of an empty array",
11311131
"tests": [
11321132
{
11331133
"input": [],
11341134
"query": ["prod"],
1135-
"throws": "Non-empty array expected"
1135+
"output": null
11361136
}
11371137
]
11381138
},
@@ -1157,18 +1157,18 @@
11571157
},
11581158
{
11591159
"category": "average",
1160-
"description": "should throw an error when calculating the average of an empty array",
1160+
"description": "should return null when calculating the average of an empty array",
11611161
"tests": [
11621162
{
11631163
"input": [],
11641164
"query": ["average"],
1165-
"throws": "Non-empty array expected"
1165+
"output": null
11661166
}
11671167
]
11681168
},
11691169
{
11701170
"category": "average",
1171-
"description": "should throw an error when calculating the average a string",
1171+
"description": "should throw an error when calculating the average of a string",
11721172
"tests": [
11731173
{
11741174
"input": "abc",
@@ -1331,34 +1331,16 @@
13311331
},
13321332
{
13331333
"category": "gt",
1334-
"description": "should throw when calculating greater than with mixed data types",
1335-
"tests": [
1336-
{
1337-
"input": null,
1338-
"query": ["gt", "3", 2],
1339-
"throws": "Two numbers, strings, or booleans expected"
1340-
}
1341-
]
1334+
"description": "should return false when calculating greater than with mixed data types",
1335+
"tests": [{ "input": null, "query": ["gt", "3", 2], "output": false }]
13421336
},
13431337
{
13441338
"category": "gt",
1345-
"description": "should throw when calculating greater than with an unsupported data type",
1339+
"description": "should return false when calculating greater than with an unsupported data type",
13461340
"tests": [
1347-
{
1348-
"input": null,
1349-
"query": ["gt", 2, ["array", 1, 2, 3]],
1350-
"throws": "Two numbers, strings, or booleans expected"
1351-
},
1352-
{
1353-
"input": null,
1354-
"query": ["gt", ["array", 1, 2, 4], ["array", 1, 2, 3]],
1355-
"throws": "Two numbers, strings, or booleans expected"
1356-
},
1357-
{
1358-
"input": null,
1359-
"query": ["gt", 2, ["object", { "a": 1 }]],
1360-
"throws": "Two numbers, strings, or booleans expected"
1361-
}
1341+
{ "input": null, "query": ["gt", 2, ["array", 1, 2, 3]], "output": false },
1342+
{ "input": null, "query": ["gt", ["array", 1, 2, 4], ["array", 1, 2, 3]], "output": false },
1343+
{ "input": null, "query": ["gt", 2, ["object", { "a": 1 }]], "output": false }
13621344
]
13631345
},
13641346
{
@@ -1406,34 +1388,20 @@
14061388
},
14071389
{
14081390
"category": "gte",
1409-
"description": "should throw when calculating greater than or equal to with mixed data types",
1410-
"tests": [
1411-
{
1412-
"input": null,
1413-
"query": ["gte", "3", 2],
1414-
"throws": "Two numbers, strings, or booleans expected"
1415-
}
1416-
]
1391+
"description": "should return false when calculating greater than or equal to with mixed data types",
1392+
"tests": [{ "input": null, "query": ["gte", "3", 2], "output": false }]
14171393
},
14181394
{
14191395
"category": "gte",
1420-
"description": "should throw when calculating greater than or equal to with an unsupported data type",
1396+
"description": "should return false when calculating greater than or equal to with an unsupported data type",
14211397
"tests": [
1422-
{
1423-
"input": null,
1424-
"query": ["gte", 2, ["array", 1, 2, 3]],
1425-
"throws": "Two numbers, strings, or booleans expected"
1426-
},
1398+
{ "input": null, "query": ["gte", 2, ["array", 1, 2, 3]], "output": false },
14271399
{
14281400
"input": null,
14291401
"query": ["gte", ["array", 1, 2, 4], ["array", 1, 2, 3]],
1430-
"throws": "Two numbers, strings, or booleans expected"
1402+
"output": false
14311403
},
1432-
{
1433-
"input": null,
1434-
"query": ["gte", 2, ["object", { "a": 1 }]],
1435-
"throws": "Two numbers, strings, or booleans expected"
1436-
}
1404+
{ "input": null, "query": ["gte", 2, ["object", { "a": 1 }]], "output": false }
14371405
]
14381406
},
14391407
{
@@ -1481,34 +1449,16 @@
14811449
},
14821450
{
14831451
"category": "lt",
1484-
"description": "should throw when calculating less than with mixed data types",
1485-
"tests": [
1486-
{
1487-
"input": null,
1488-
"query": ["lt", 2, "3"],
1489-
"throws": "Two numbers, strings, or booleans expected"
1490-
}
1491-
]
1452+
"description": "should return false when calculating less than with mixed data types",
1453+
"tests": [{ "input": null, "query": ["lt", 2, "3"], "output": false }]
14921454
},
14931455
{
14941456
"category": "lt",
1495-
"description": "should throw when calculating less than with an unsupported data type",
1457+
"description": "should return false when calculating less than with an unsupported data type",
14961458
"tests": [
1497-
{
1498-
"input": null,
1499-
"query": ["lt", 2, ["array", 1, 2, 3]],
1500-
"throws": "Two numbers, strings, or booleans expected"
1501-
},
1502-
{
1503-
"input": null,
1504-
"query": ["lt", ["array", 1, 2, 4], ["array", 1, 2, 3]],
1505-
"throws": "Two numbers, strings, or booleans expected"
1506-
},
1507-
{
1508-
"input": null,
1509-
"query": ["lt", 2, ["object", { "a": 1 }]],
1510-
"throws": "Two numbers, strings, or booleans expected"
1511-
}
1459+
{ "input": null, "query": ["lt", 2, ["array", 1, 2, 3]], "output": false },
1460+
{ "input": null, "query": ["lt", ["array", 1, 2, 4], ["array", 1, 2, 3]], "output": false },
1461+
{ "input": null, "query": ["lt", 2, ["object", { "a": 1 }]], "output": false }
15121462
]
15131463
},
15141464
{
@@ -1560,34 +1510,20 @@
15601510
},
15611511
{
15621512
"category": "lte",
1563-
"description": "should throw when calculating less than or equal to with mixed data types",
1564-
"tests": [
1565-
{
1566-
"input": null,
1567-
"query": ["lte", "3", 2],
1568-
"throws": "Two numbers, strings, or booleans expected"
1569-
}
1570-
]
1513+
"description": "should return false when calculating less than or equal to with mixed data types",
1514+
"tests": [{ "input": null, "query": ["lte", "3", 2], "output": false }]
15711515
},
15721516
{
15731517
"category": "lte",
1574-
"description": "should throw when calculating less than or equal to with an unsupported data type",
1518+
"description": "should return false when calculating less than or equal to with an unsupported data type",
15751519
"tests": [
1576-
{
1577-
"input": null,
1578-
"query": ["lte", 2, ["array", 1, 2, 3]],
1579-
"throws": "Two numbers, strings, or booleans expected"
1580-
},
1520+
{ "input": null, "query": ["lte", 2, ["array", 1, 2, 3]], "output": false },
15811521
{
15821522
"input": null,
15831523
"query": ["lte", ["array", 1, 2, 4], ["array", 1, 2, 3]],
1584-
"throws": "Two numbers, strings, or booleans expected"
1524+
"output": false
15851525
},
1586-
{
1587-
"input": null,
1588-
"query": ["lte", 2, ["object", { "a": 1 }]],
1589-
"throws": "Two numbers, strings, or booleans expected"
1590-
}
1526+
{ "input": null, "query": ["lte", 2, ["object", { "a": 1 }]], "output": false }
15911527
]
15921528
},
15931529
{
@@ -1750,12 +1686,12 @@
17501686
},
17511687
{
17521688
"category": "and",
1753-
"description": "should throw when calculating and with no arguments",
1689+
"description": "should return null calculating and with no arguments",
17541690
"tests": [
17551691
{
17561692
"input": null,
17571693
"query": ["and"],
1758-
"throws": "Non-empty array expected"
1694+
"output": null
17591695
}
17601696
]
17611697
},
@@ -1821,12 +1757,12 @@
18211757
},
18221758
{
18231759
"category": "or",
1824-
"description": "should throw when calculating or with no arguments",
1760+
"description": "should return null when calculating or with no arguments",
18251761
"tests": [
18261762
{
18271763
"input": null,
18281764
"query": ["or"],
1829-
"throws": "Non-empty array expected"
1765+
"output": null
18301766
}
18311767
]
18321768
},

0 commit comments

Comments
 (0)