Skip to content

Commit

Permalink
Fix typings for boolean operators
Browse files Browse the repository at this point in the history
  • Loading branch information
angrykoala committed Aug 20, 2024
1 parent 50ac09e commit d416ee6
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 22 deletions.
25 changes: 25 additions & 0 deletions .changeset/wise-peaches-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@neo4j/cypher-builder": major
---

Fix TypeScript typings for boolean operators when using array spread:

- `Cypher.and`
- `Cypher.or`
- `Cypher.xor`

The following:

```ts
const predicates: Cypher.Predicate[] = [];
const andPredicate = Cypher.and(...predicates);
```

Will now return the correct type `Cypher.Predicate | undefined`. This change means that additional checks may be needed when using boolean operators:

```ts
const predicates = [Cypher.true, Cypher.false];
const andPredicate = Cypher.and(...predicates); // type Cypher.Predicate | undefined
```

Passing parameters without spread
41 changes: 19 additions & 22 deletions src/expressions/operations/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
* limitations under the License.
*/

import { filterTruthy } from "../../utils/filter-truthy";
import { CypherASTNode } from "../../CypherASTNode";
import type { CypherEnvironment } from "../../Environment";
import type { Predicate } from "../../types";
import { filterTruthy } from "../../utils/filter-truthy";

type BooleanOperator = "AND" | "NOT" | "OR" | "XOR";

Expand All @@ -39,9 +39,9 @@ export abstract class BooleanOp extends CypherASTNode {
class BinaryOp extends BooleanOp {
private children: Predicate[];

constructor(operator: BooleanOperator, left: Predicate, right: Predicate, ...extra: Predicate[]) {
constructor(operator: BooleanOperator, predicates: Predicate[]) {
super(operator);
this.children = [left, right, ...extra];
this.children = predicates;
this.addChildren(...this.children);
}

Expand All @@ -52,7 +52,7 @@ class BinaryOp extends BooleanOp {
const childrenStrs = this.children.map((c) => c.getCypher(env)).filter(Boolean);

if (childrenStrs.length <= 1) {
return childrenStrs.join("");
throw new Error(`Boolean operation ${this.operator} does not have predicates`);
}

const operatorStr = ` ${this.operator} `;
Expand Down Expand Up @@ -103,16 +103,15 @@ class NotOp extends BooleanOp {
*/
export function and(): undefined;
export function and(left: Predicate, right: Predicate, ...extra: Array<Predicate | undefined>): BooleanOp;
export function and(...ops: Array<Predicate>): Predicate;
export function and(left: Predicate, ...extra: Array<Predicate | undefined>): Predicate;
export function and(...ops: Array<Predicate | undefined>): Predicate | undefined;
export function and(...ops: Array<Predicate | undefined>): Predicate | undefined {
const filteredPredicates = filterTruthy(ops);
const predicate1 = filteredPredicates.shift();
const predicate2 = filteredPredicates.shift();
if (predicate1 && predicate2) {
return new BinaryOp("AND", predicate1, predicate2, ...filteredPredicates);

if (filteredPredicates[0] && filteredPredicates[1]) {
return new BinaryOp("AND", filteredPredicates);
}
return predicate1;
return filteredPredicates[0];
}

/** Generates an `NOT` operator before the given predicate
Expand Down Expand Up @@ -154,16 +153,15 @@ export function not(child: Predicate): BooleanOp {
*/
export function or(): undefined;
export function or(left: Predicate, right: Predicate, ...extra: Array<Predicate | undefined>): BooleanOp;
export function or(...ops: Array<Predicate>): Predicate;
export function or(left: Predicate, ...extra: Array<Predicate | undefined>): Predicate;
export function or(...ops: Array<Predicate | undefined>): Predicate | undefined;
export function or(...ops: Array<Predicate | undefined>): Predicate | undefined {
const filteredPredicates = filterTruthy(ops);
const predicate1 = filteredPredicates.shift();
const predicate2 = filteredPredicates.shift();
if (predicate1 && predicate2) {
return new BinaryOp("OR", predicate1, predicate2, ...filteredPredicates);

if (filteredPredicates[0] && filteredPredicates[1]) {
return new BinaryOp("OR", filteredPredicates);
}
return predicate1;
return filteredPredicates[0];
}

/** Generates an `XOR` operator between the given predicates
Expand All @@ -185,14 +183,13 @@ export function or(...ops: Array<Predicate | undefined>): Predicate | undefined
*/
export function xor(): undefined;
export function xor(left: Predicate, right: Predicate, ...extra: Array<Predicate | undefined>): BooleanOp;
export function xor(...ops: Array<Predicate>): Predicate;
export function xor(left: Predicate, ...extra: Array<Predicate | undefined>): Predicate;
export function xor(...ops: Array<Predicate | undefined>): Predicate | undefined;
export function xor(...ops: Array<Predicate | undefined>): Predicate | undefined {
const filteredPredicates = filterTruthy(ops);
const predicate1 = filteredPredicates.shift();
const predicate2 = filteredPredicates.shift();
if (predicate1 && predicate2) {
return new BinaryOp("XOR", predicate1, predicate2, ...filteredPredicates);

if (filteredPredicates[0] && filteredPredicates[1]) {
return new BinaryOp("XOR", filteredPredicates);
}
return predicate1;
return filteredPredicates[0];
}

0 comments on commit d416ee6

Please sign in to comment.