Skip to content

Commit

Permalink
types: allow EntityQuery to select from many tables (#62)
Browse files Browse the repository at this point in the history
Doing `join` will bring in more tables that can be selected against. Thus, `EntityQuery.select` needs to be able pull from more than a single schema.

To do that, `EntityQuery` now takes a `FromSet` rather than `EntitySchema`.

```ts
type FromSet = {
  [table: string]: EntitySchema
};

const q = new EntityQuery<{issue: Issue}>();
const q2 = new EntityQuery<{user: User}>();

q.join(q2, 'owner', 'issue.ownerId', 'owner.id').select(...);
```

`join` requires us to support aliasing ambiguous columns so this adds that as well.
  • Loading branch information
tantaman authored Apr 9, 2024
1 parent 12607f1 commit 22c5252
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 221 deletions.
14 changes: 9 additions & 5 deletions src/zql/ast-to-ivm/pipeline-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type E1 = z.infer<typeof e1>;
const context = makeTestContext();
const comparator = (l: E1, r: E1) => compareUTF8(l.id, r.id);
test('A simple select', () => {
const q = new EntityQuery<E1>(context, 'e1');
const q = new EntityQuery<{e1: E1}>(context, 'e1');
const m = new Materialite();
let s = m.newSetSource<E1>(comparator);
let pipeline = buildPipeline(
Expand Down Expand Up @@ -69,7 +69,7 @@ test('A simple select', () => {
});

test('Count', () => {
const q = new EntityQuery<E1>(context, 'e1');
const q = new EntityQuery<{e1: E1}>(context, 'e1');
const m = new Materialite();
const s = m.newSetSource<E1>(comparator);
const pipeline = buildPipeline(
Expand Down Expand Up @@ -99,7 +99,7 @@ test('Count', () => {
});

test('Where', () => {
const q = new EntityQuery<E1>(context, 'e1');
const q = new EntityQuery<{e1: E1}>(context, 'e1');
const m = new Materialite();
const s = m.newSetSource<E1>(comparator);
const pipeline = buildPipeline(
Expand Down Expand Up @@ -133,7 +133,7 @@ describe('OR', () => {

type Case = {
name?: string | undefined;
where: WhereCondition<E>;
where: WhereCondition<{e1: E}>;
values?: (E | DeleteE)[] | undefined;
expected: (E | [v: E, multiplicity: number])[];
};
Expand Down Expand Up @@ -377,7 +377,11 @@ describe('OR', () => {

const ast: AST = {
table: 'items',
select: ['id', 'a', 'b'],
select: [
['id', 'id'],
['a', 'a'],
['b', 'b'],
],
where: c.where as Condition,
orderBy: [['id'], 'asc'],
};
Expand Down
12 changes: 6 additions & 6 deletions src/zql/ast-to-ivm/pipeline-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function buildPipeline(

export function applySelect(
stream: DifferenceStream<Entity>,
select: string[],
select: [column: string, alias: string][],
orderBy: Ordering | undefined,
) {
return stream.map(x => {
Expand All @@ -71,8 +71,8 @@ export function applySelect(
ret = {...x};
} else {
ret = {};
for (const field of select) {
ret[field] = (x as Record<string, unknown>)[field];
for (const selector of select) {
ret[selector[1]] = (x as Record<string, unknown>)[selector[0]];
}
}

Expand Down Expand Up @@ -168,7 +168,7 @@ function applyGroupBy<T extends Entity>(
stream: DifferenceStream<T>,
columns: string[],
aggregations: Aggregation[],
select: string[],
select: [string, string][],
orderBy: Ordering | undefined,
) {
const keyFunction = makeKeyFunction(columns);
Expand All @@ -178,8 +178,8 @@ function applyGroupBy<T extends Entity>(
values => {
const first = values[Symbol.iterator]().next().value;
const ret: Record<string, unknown> = {};
for (const column of select) {
ret[column] = first[column];
for (const selector of select) {
ret[selector[1]] = first[selector[0]];
}
addOrdering(ret, first, orderBy);

Expand Down
2 changes: 1 addition & 1 deletion src/zql/ast/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type Aggregation = {
export type AST = {
readonly table?: string | undefined;
readonly alias?: number | undefined;
readonly select?: string[] | undefined;
readonly select?: [string, string][] | undefined;
readonly aggregate?: Aggregation[];
// readonly subQueries?: {
// readonly alias: string;
Expand Down
2 changes: 1 addition & 1 deletion src/zql/context/replicache-context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ test('ZQL query with Replicache', async () => {
const r = newRep();
const context = makeReplicacheContext(r);

const q = new EntityQuery<E1>(context, 'e1');
const q = new EntityQuery<{e1: E1}>(context, 'e1');

const view = q.select('id').where('str', '>', 'm').prepare().view();

Expand Down
2 changes: 1 addition & 1 deletion src/zql/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function sampleTenUniqueIssues() {
function setup() {
const r = newRep();
const c = makeReplicacheContext(r);
const q = new EntityQuery<Issue>(c, 'issue');
const q = new EntityQuery<{issue: Issue}>(c, 'issue');
return {r, c, q};
}

Expand Down
4 changes: 2 additions & 2 deletions src/zql/ivm/view/tree-view.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test('asc and descComparator on Entities', () => {

const updatedStream = applySelect(
s.stream,
['id'],
[['id', 'id']],
[['n', 'id'], 'asc'],
) as unknown as DifferenceStream<Selected>;

Expand All @@ -29,7 +29,7 @@ test('asc and descComparator on Entities', () => {
m,
applySelect(
s.stream as unknown as DifferenceStream<Entity>,
['id'],
[['id', 'id']],
[['n', 'id'], 'desc'],
) as unknown as DifferenceStream<Selected>,
descComparator,
Expand Down
7 changes: 3 additions & 4 deletions src/zql/query/condition-to-string.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {EntitySchema} from '../schema/entity-schema.js';
import {WhereCondition} from './entity-query.js';
import {FromSet, WhereCondition} from './entity-query.js';

export function conditionToString<S extends EntitySchema>(
c: WhereCondition<S>,
export function conditionToString<From extends FromSet>(
c: WhereCondition<From>,
paren = false,
): string {
if (c.op === 'AND' || c.op === 'OR') {
Expand Down
Loading

0 comments on commit 22c5252

Please sign in to comment.