Skip to content

Commit

Permalink
Use given cardinality in select expression (#1043)
Browse files Browse the repository at this point in the history
Previously, if you made a select expression with a constant or coalescing
expression, we always calculated the cardinality of a object key based on the
pointer's cardinality, rather than allowing you to return something assignable
to that cardinality. This change will check if the assignment is possible, and
override the cardinality when converting the query builder expression to a TS
type.
  • Loading branch information
scotttrinh authored Jun 17, 2024
1 parent c1672f7 commit c63404d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 4 deletions.
7 changes: 7 additions & 0 deletions integration-tests/lts/bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,13 @@ bench("select: with offset", () => {
return {} as typeof query;
}).types([8891, "instantiations"]);

bench("select: with pointer override", () => {
const query = e.select(e.Hero, (h) => ({
height: e.decimal("10.0"),
}));
return {} as typeof query;
}).types([2160, "instantiations"]);

bench("params select", () => {
const query = e.params({ name: e.str }, (params) =>
e.select(e.Hero, (hero) => ({
Expand Down
55 changes: 55 additions & 0 deletions integration-tests/lts/select.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,61 @@ SELECT __scope_0_defaultPerson {
assert.equal(res4, 1);
});

test("overriding pointers", async () => {
const q = e.select(e.Hero, () => ({
height: e.decimal("10.0"),
}));
type Height = $infer<typeof q.__element__.__shape__.height>;
type Q = $infer<typeof q>;
tc.assert<
tc.IsExact<
Q,
{
height: Height;
}[]
>
>(true);

await assert.rejects(
async () =>
e
// @ts-expect-error cannot assign multi cardinality if point is single
.select(e.Hero, () => ({
height: e.set(e.decimal("10.0"), e.decimal("11.0")),
}))
.run(client),
(err) => {
if (
err &&
typeof err === "object" &&
"message" in err &&
typeof err.message === "string"
) {
assert.match(err.message, /possibly more than one element returned/);
return true;
} else {
assert.fail("Expected error to be an object with a message");
}
},
);
});

test("coalescing pointers", () => {
const q = e.select(e.Hero, (h) => ({
height: e.op(h.height, "??", e.decimal("10.0")),
}));
type Height = $infer<typeof q.__element__.__shape__.height>;
type Q = $infer<typeof q>;
tc.assert<
tc.IsExact<
Q,
{
height: Height;
}[]
>
>(true);
});

test("nested matching scopes", async () => {
const q = e.select(e.Hero, (h) => ({
name: h.name,
Expand Down
14 changes: 10 additions & 4 deletions packages/generate/src/syntax/typesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,16 @@ export type computeObjectShape<
ShapeEl
> | null
: never
: [k] extends [keyof Pointers]
? shapeElementToTs<Pointers[k], Shape[k]>
: Shape[k] extends TypeSet
? setToTsType<Shape[k]>
: Shape[k] extends TypeSet
? [k] extends [keyof Pointers]
? Shape[k]["__cardinality__"] extends cardutil.assignable<
Pointers[k]["cardinality"]
>
? setToTsType<Shape[k]>
: never
: setToTsType<Shape[k]>
: [k] extends [keyof Pointers]
? shapeElementToTs<Pointers[k], Shape[k]>
: never;
}
>;
Expand Down

0 comments on commit c63404d

Please sign in to comment.