Skip to content

Commit b89dd63

Browse files
authored
Merge branch 'master' into join
2 parents 2f3f643 + 1de39ec commit b89dd63

File tree

7 files changed

+319
-24
lines changed

7 files changed

+319
-24
lines changed

docs/array-functions.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ Returns the number of items in the `array` parameter. If the `array` parameter
1010

1111
If `array` is not specified, then the context value is used as the value of `array`.
1212

13-
__Examples__
14-
- `$count([1,2,3,1])` => `4`
13+
__Examples__
14+
- `$count([1,2,3,1])` => `4`
1515
- `$count("hello")` => 1
1616

1717
## `$append()`
1818
__Signature:__ `$append(array1, array2)`
1919

2020
Returns and array containing the values in `array1` followed by the values in `array2`. If either parameter is not an array, then it is treated as a singleton array containing that value.
2121

22-
__Examples__
23-
- `$append([1,2,3], [4,5,6])` => `[1,2,3,4,5,6]`
24-
- `$append([1,2,3], 4)` => `[1,2,3,4]`
22+
__Examples__
23+
- `$append([1,2,3], [4,5,6])` => `[1,2,3,4,5,6]`
24+
- `$append([1,2,3], 4)` => `[1,2,3,4]`
2525
- `$append("Hello", "World")` => `["Hello", "World"]`
2626

2727

@@ -52,19 +52,26 @@ __Signature:__ `$reverse(array)`
5252

5353
Returns an array containing all the values from the `array` parameter, but in reverse order.
5454

55-
__Examples__
56-
- `$reverse(["Hello", "World"])` => `["World", "Hello"]`
55+
__Examples__
56+
- `$reverse(["Hello", "World"])` => `["World", "Hello"]`
5757
- `[1..5] ~> $reverse()` => `[5, 4, 3, 2, 1]`
5858

5959
## `$shuffle()`
6060
__Signature:__ `$shuffle(array)`
6161

6262
Returns an array containing all the values from the `array` parameter, but shuffled into random order.
6363

64-
__Examples__
64+
__Examples__
6565
- `$shuffle([1..9])` => `[6, 8, 2, 3, 9, 5, 1, 4, 7]`
6666

67+
## `$distinct()`
68+
__Signature__ `$distinct(array)`
6769

70+
Returns an array containing all the values from the `array` parameter, but with any duplicates removed. Values are tested for deep equality as if by using the [equality operator](comparison-operators#equals).
71+
72+
__Examples__
73+
- `$distinct([1,2,3,3,4,3,5])` => `[1, 2, 3, 4, 5]`
74+
- `$distinct(Account.Order.Product.Description.Colour)` => `[ "Purple", "Orange", "Black" ]`
6875

6976
## `$zip()`
7077
__Signature:__ `$zip(array1, ...)`
@@ -73,6 +80,6 @@ Returns a convolved (zipped) array containing grouped arrays of values from the
7380

7481
This function accepts a variable number of arguments. The length of the returned array is equal to the length of the shortest array in the arguments.
7582

76-
__Examples__
77-
- `$zip([1,2,3], [4,5,6])` => `[[1,4] ,[2,5], [3,6]]`
83+
__Examples__
84+
- `$zip([1,2,3], [4,5,6])` => `[[1,4] ,[2,5], [3,6]]`
7885
- `$zip([1,2,3],[4,5],[7,8,9])` => `[[1,4,7], [2,5,8]]`

docs/comparison-operators.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ sidebar_label: Comparison Operators
66

77
## `=` (Equals)
88

9-
The equality operator returns Boolean `true` if both operands are the same (type and value). Otherwise it returns `false`.
9+
The equality operator returns Boolean `true` if both operands are the same (type and value). Arrays and objects are checked for deep equality. Arrays must have the same values in the same order. Objects must have the same key/value pairs (order is not relevant). Otherwise it returns `false`.
1010

1111
__Examples__
1212

13-
- `1+1 = 2` => `true`
13+
- `1+1 = 2` => `true`
1414
- `"Hello" = "World"` => `false`
1515

1616
## `!=` (Not equals)
1717

18-
The inequality operator returns Boolean `false` if both operands are the same (type and value). Otherwise it returns `true`.
18+
The inequality operator returns Boolean `false` if both operands are the same (type and value, deep equality). Otherwise it returns `true`.
1919

2020
__Examples__
2121

22-
- `1+1 != 3` => `true`
22+
- `1+1 != 3` => `true`
2323
- `"Hello" != "World"` => `true`
2424

2525
## `>` (Greater than)
@@ -28,7 +28,7 @@ The 'greater than' operator returns Boolean `true` if the LHS is numerically gre
2828

2929
__Examples__
3030

31-
- `22 / 7 > 3` => `true`
31+
- `22 / 7 > 3` => `true`
3232
- `5 > 5` => `false`
3333

3434
## `<` (Less than)
@@ -37,7 +37,7 @@ The 'less than' operator returns Boolean `true` if the LHS is numerically less t
3737

3838
__Examples__
3939

40-
- `22 / 7 < 3` => `false`
40+
- `22 / 7 < 3` => `false`
4141
- `5 < 5` => `false`
4242

4343

@@ -47,7 +47,7 @@ The 'greater than or equals' operator returns Boolean `true` if the LHS is numer
4747

4848
__Examples__
4949

50-
- `22 / 7 >= 3` => `true`
50+
- `22 / 7 >= 3` => `true`
5151
- `5 >= 5` => `true`
5252

5353

@@ -57,7 +57,7 @@ The 'less than or equals' operator returns Boolean `true` if the LHS is numerica
5757

5858
__Examples__
5959

60-
- `22 / 7 <= 3` => `false`
60+
- `22 / 7 <= 3` => `false`
6161
- `5 <= 5` => `true`
6262

6363
## `in` (Inclusion)
@@ -66,7 +66,7 @@ The array (sequence) inclusion operator returns Boolean `true` if the value of t
6666

6767
__Examples__
6868

69-
- `"world" in ["hello", "world"]` => `true`
70-
- `"hello" in "hello"` => `true`
69+
- `"world" in ["hello", "world"]` => `true`
70+
- `"hello" in "hello"` => `true`
7171
- `library.books["Aho" in authors].title`
7272

src/functions.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ const functions = (() => {
1313
var isArrayOfStrings = utils.isArrayOfStrings;
1414
var isArrayOfNumbers = utils.isArrayOfNumbers;
1515
var createSequence = utils.createSequence;
16+
var isSequence = utils.isSequence;
1617
var isFunction = utils.isFunction;
1718
var isLambda = utils.isLambda;
1819
var isIterable = utils.isIterable;
1920
var getFunctionArity = utils.getFunctionArity;
21+
var deepEquals = utils.isDeepEqual;
2022

2123
/**
2224
* Sum function
@@ -1923,6 +1925,40 @@ const functions = (() => {
19231925
return result;
19241926
}
19251927

1928+
/**
1929+
* Returns the values that appear in a sequence, with duplicates eliminated.
1930+
* @param {Array} arr - An array or sequence of values
1931+
* @returns {Array} - sequence of distinct values
1932+
*/
1933+
function distinct(arr) {
1934+
// undefined inputs always return undefined
1935+
if (typeof arr === 'undefined') {
1936+
return undefined;
1937+
}
1938+
1939+
if(!Array.isArray(arr) || arr.length <= 1) {
1940+
return arr;
1941+
}
1942+
1943+
var results = isSequence(arr) ? createSequence() : [];
1944+
1945+
for(var ii = 0; ii < arr.length; ii++) {
1946+
var value = arr[ii];
1947+
// is this value already in the result sequence?
1948+
var includes = false;
1949+
for(var jj = 0; jj < results.length; jj++) {
1950+
if (deepEquals(value, results[jj])) {
1951+
includes = true;
1952+
break;
1953+
}
1954+
}
1955+
if(!includes) {
1956+
results.push(value);
1957+
}
1958+
}
1959+
return results;
1960+
}
1961+
19261962
/**
19271963
* Applies a predicate function to each key/value pair in an object, and returns an object containing
19281964
* only the key/value pairs that passed the predicate
@@ -1959,7 +1995,7 @@ const functions = (() => {
19591995
formatNumber, formatBase, number, floor, ceil, round, abs, sqrt, power, random,
19601996
boolean, not,
19611997
map, zip, filter, single, foldLeft, sift,
1962-
keys, lookup, append, exists, spread, merge, reverse, each, error, sort, shuffle,
1998+
keys, lookup, append, exists, spread, merge, reverse, each, error, sort, shuffle, distinct,
19631999
base64encode, base64decode, encodeUrlComponent, encodeUrl, decodeUrlComponent, decodeUrl
19642000
};
19652001
})();

src/jsonata.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var jsonata = (function() {
3333
var isLambda = utils.isLambda;
3434
var isIterable = utils.isIterable;
3535
var getFunctionArity = utils.getFunctionArity;
36+
var isDeepEqual = utils.isDeepEqual;
3637

3738
// Start of Evaluator code
3839

@@ -720,10 +721,10 @@ var jsonata = (function() {
720721

721722
switch (op) {
722723
case '=':
723-
result = lhs === rhs;
724+
result = isDeepEqual(lhs, rhs);
724725
break;
725726
case '!=':
726-
result = (lhs !== rhs);
727+
result = !isDeepEqual(lhs, rhs);
727728
break;
728729
}
729730
return result;
@@ -1859,6 +1860,7 @@ var jsonata = (function() {
18591860
staticFrame.bind('error', defineFunction(fn.error, '<s?:x>'));
18601861
staticFrame.bind('sort', defineFunction(fn.sort, '<af?:a>'));
18611862
staticFrame.bind('shuffle', defineFunction(fn.shuffle, '<a:a>'));
1863+
staticFrame.bind('distinct', defineFunction(fn.distinct, '<x:x>'));
18621864
staticFrame.bind('base64encode', defineFunction(fn.base64encode, '<s-:s>'));
18631865
staticFrame.bind('base64decode', defineFunction(fn.base64decode, '<s-:s>'));
18641866
staticFrame.bind('encodeUrlComponent', defineFunction(fn.encodeUrlComponent, '<s-:s>'));

src/utils.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,57 @@ const utils = (() => {
125125
);
126126
}
127127

128+
/**
129+
* Compares two values for equality
130+
* @param {*} lhs first value
131+
* @param {*} rhs second value
132+
* @returns {boolean} true if they are deep equal
133+
*/
134+
function isDeepEqual(lhs, rhs) {
135+
if (lhs === rhs) {
136+
return true;
137+
}
138+
if(typeof lhs === 'object' && typeof rhs === 'object' && lhs !== null && rhs !== null) {
139+
if(Array.isArray(lhs) && Array.isArray(rhs)) {
140+
// both arrays (or sequences)
141+
// must be the same length
142+
if(lhs.length !== rhs.length) {
143+
return false;
144+
}
145+
// must contain same values in same order
146+
for(var ii = 0; ii < lhs.length; ii++) {
147+
if(!isDeepEqual(lhs[ii], rhs[ii])) {
148+
return false;
149+
}
150+
}
151+
return true;
152+
}
153+
// both objects
154+
// must have the same set of keys (in any order)
155+
var lkeys = Object.getOwnPropertyNames(lhs);
156+
var rkeys = Object.getOwnPropertyNames(rhs);
157+
if(lkeys.length !== rkeys.length) {
158+
return false;
159+
}
160+
lkeys = lkeys.sort();
161+
rkeys = rkeys.sort();
162+
for(ii=0; ii < lkeys.length; ii++) {
163+
if(lkeys[ii] !== rkeys[ii]) {
164+
return false;
165+
}
166+
}
167+
// must have the same values
168+
for(ii=0; ii < lkeys.length; ii++) {
169+
var key = lkeys[ii];
170+
if(!isDeepEqual(lhs[key], rhs[key])) {
171+
return false;
172+
}
173+
}
174+
return true;
175+
}
176+
return false;
177+
}
178+
128179
return {
129180
isNumeric,
130181
isArrayOfStrings,
@@ -134,7 +185,8 @@ const utils = (() => {
134185
isFunction,
135186
isLambda,
136187
isIterable,
137-
getFunctionArity
188+
getFunctionArity,
189+
isDeepEqual
138190
};
139191
})();
140192

0 commit comments

Comments
 (0)