Skip to content

Commit

Permalink
ucast-prisma: laxer handling of empty OR/AND
Browse files Browse the repository at this point in the history
  • Loading branch information
srenatus committed Nov 1, 2024
1 parent da7c6c0 commit 3920db7
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
25 changes: 25 additions & 0 deletions .changeset/tiny-tools-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@styra/ucast-prisma": patch
---

Introduce laxer handling of empty compound conditions

This aligns better with common Rego patterns, like using multi-value
rules for generating conditions:

```rego
conditions.or contains {"tickets.resolved": false} if { ... }
```

If the RHS is not satisfied, the conditions would yield

```json
{
"conditions": {
"or": []
}
}
```

and with this change, this will be valid. The condition itself is
going to be dropped.
12 changes: 1 addition & 11 deletions packages/ucast-prisma/src/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,9 @@ function ensureIsArray(instruction: { name: string }, value: any) {
}
}

function ensureIsNonEmptyArray(instruction: { name: string }, value: any[]) {
ensureIsArray(instruction, value);

if (!value.length) {
throw new Error(
`"${instruction.name}" expects to have at least one element in array`
);
}
}

export const and = {
type: "compound",
validate: ensureIsNonEmptyArray,
validate: ensureIsArray,
parse(instruction: { name: string }, queries: any[], { parse }: any) {
const conditions = queries.map((query) => parse(query));
return new CompoundCondition(instruction.name, conditions);
Expand Down
35 changes: 27 additions & 8 deletions packages/ucast-prisma/tests/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,43 @@ import { describe, it, expect } from "vitest";
describe("ucastToPrisma", () => {
describe("field operators", () => {
it("converts (implicit) 'eq' to 'equals'", () => {
const p = ucastToPrisma({ "table.name": "test" });
expect(p).toStrictEqual({ table: { name: { equals: "test" } } });
const p = ucastToPrisma({ "table.name": "test" }, "table");
expect(p).toStrictEqual({ name: { equals: "test" } });
});

it("converts 'eq' to 'equals'", () => {
const p = ucastToPrisma({ "table.name": { eq: "test" } });
expect(p).toStrictEqual({ table: { name: { equals: "test" } } });
const p = ucastToPrisma({ "table.name": { eq: "test" } }, "table");
expect(p).toStrictEqual({ name: { equals: "test" } });
});

// NOTE(sr): interesting because the interpreter for `in` is `in_` (keyword clash)
it("converts 'in' to 'in'", () => {
const p = ucastToPrisma({ "table.name": { in: ["a", "b"] } });
expect(p).toStrictEqual({ table: { name: { in: ["a", "b"] } } });
const p = ucastToPrisma({ "table.name": { in: ["a", "b"] } }, "table");
expect(p).toStrictEqual({ name: { in: ["a", "b"] } });
});

it("converts 'notIn' to 'notIn'", () => {
const p = ucastToPrisma({ "table.name": { notIn: ["a", "b"] } });
expect(p).toStrictEqual({ table: { name: { notIn: ["a", "b"] } } });
const p = ucastToPrisma({ "table.name": { notIn: ["a", "b"] } }, "table");
expect(p).toStrictEqual({ name: { notIn: ["a", "b"] } });
});
});
describe("compound operators", () => {
it("allows empty 'or' (drops it)", () => {
const p = ucastToPrisma({ or: [] }, "table");
expect(p).toStrictEqual({});
});

it("projects 'or' by primary table", () => {
const p = ucastToPrisma(
{ or: [{ "tickets.resolved": false }, { "users.name": "ceasar" }] },
"tickets"
);
expect(p).toStrictEqual({
OR: [
{ resolved: { equals: false } },
{ users: { name: { equals: "ceasar" } } },
],
});
});
});
});
7 changes: 7 additions & 0 deletions packages/ucast-prisma/tests/interpreters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ describe("Condition interpreter", () => {
});
});

it("drops empty OR conditions", () => {
const condition = new CompoundCondition("or", []);
const f = interpret(condition);

expect(f).toStrictEqual({});
});

it('generates query with OR for "or" per table', () => {
const condition = new CompoundCondition("or", [
new FieldCondition("eq", "user.id", 12),
Expand Down

0 comments on commit 3920db7

Please sign in to comment.