Skip to content

Commit

Permalink
feat(rstream-query): add path query, multi-joins, pattern query reuse
Browse files Browse the repository at this point in the history
- add addPathQuery()
- add addMultiJoin()
- rename addQueryJoin() => addJoin()
- update query ID arg order
- add type aliases
- add pattern query cache
- add patternVars() helper
  • Loading branch information
postspectacular committed Apr 26, 2018
1 parent 9b5c58a commit 679c4e0
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 114 deletions.
11 changes: 4 additions & 7 deletions packages/rstream-query/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { IObjectOf } from "@thi.ng/api/api";
import { ISubscribable } from "@thi.ng/rstream/api";

export type Pattern = [any, any, any];

export type PathPattern = [any, any[], any];

export type Triple = Pattern;

export type Triples = Set<Pattern>;
Expand All @@ -10,13 +13,7 @@ export type TripleIds = Set<number>;

export type Solutions = Set<IObjectOf<any>>;

export const CHOICES = Symbol("CHOICES");

export enum EditOp {
ADD,
DELETE,
UPDATE
}
export type QuerySolution = ISubscribable<Solutions>;

export interface Edit {
index: Set<number>;
Expand Down
63 changes: 16 additions & 47 deletions packages/rstream-query/src/pattern.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { repeatedly } from "@thi.ng/transducers/iter/repeatedly";

import { Triple, Pattern } from "./api";
import { Pattern, PathPattern } from "./api";
import { isQVar, autoQVar, qvarName } from "./qvar";

export const patternVarCount = (p: Pattern) => {
Expand All @@ -11,11 +11,20 @@ export const patternVarCount = (p: Pattern) => {
return n;
};

export const patternVars = ([s, p, o]: Pattern) => {
const vars = [];
isQVar(s) && vars.push(qvarName(s));
isQVar(p) && vars.push(qvarName(p));
isQVar(o) && vars.push(qvarName(o));
return vars;
};

/**
* Takes a path triple pattern and max depth. The pattern's predicate
* must be a seq of preds. Returns a 2-elem vector [patterns vars],
* where `patterns` is a seq of query patterns with injected temp qvars
* for in between patterns and`vars` the autogenerated qvars themselves.
* where `patterns` is a list of generated sub-query patterns with
* injected temp qvars for in between patterns and `vars` are the temp
* qvars themselves.
*
* Example:
*
Expand All @@ -28,12 +37,12 @@ export const patternVarCount = (p: Pattern) => {
* ```
*
* @param pattern
* @param maxd
* @param maxLen
*/
export const resolvePathPattern = ([s, p, o], maxd = p.length) => {
export const resolvePathPattern = ([s, p, o]: PathPattern, maxLen = p.length): [Pattern[], string[]] => {
const res = [];
const avars = [...repeatedly(autoQVar, maxd - 1)];
for (let i = 0; i < maxd; i++) {
const avars = [...repeatedly(autoQVar, maxLen - 1)];
for (let i = 0; i < maxLen; i++) {
res.push([s, p[i % p.length], s = avars[i]]);
}
res[res.length - 1][2] = o;
Expand All @@ -42,43 +51,3 @@ export const resolvePathPattern = ([s, p, o], maxd = p.length) => {

export const sortPatterns = (patterns: Pattern[]) =>
patterns.sort((a, b) => patternVarCount(a) - patternVarCount(b));

/**
* Returns an optimized query variable solution extractor function based
* on given pattern type. `vs`, `vp`, `vo` are flags to indicate if `s`,
* `p` and/or `o` pattern items are query variables. The returned fn
* will be optimized to 1 of the 8 possible case and accepts a single
* fact to extract the respective variables from.
*
* @param vs
* @param vp
* @param vo
* @param s
* @param p
* @param o
*/
export const qvarResolver = (vs: boolean, vp: boolean, vo: boolean, s, p, o) => {
const type = ((<any>vs) << 2) | ((<any>vp) << 1) | (<any>vo);
let ss: any = vs && qvarName(s);
let pp: any = vp && qvarName(p);
let oo: any = vo && qvarName(o);
switch (type) {
case 0:
default:
return;
case 1:
return (f: Triple) => ({ [oo]: f[2] });
case 2:
return (f: Triple) => ({ [pp]: f[1] });
case 3:
return (f: Triple) => ({ [pp]: f[1], [oo]: f[2] });
case 4:
return (f: Triple) => ({ [ss]: f[0] });
case 5:
return (f: Triple) => ({ [ss]: f[0], [oo]: f[2] });
case 6:
return (f: Triple) => ({ [ss]: f[0], [pp]: f[1] });
case 7:
return (f: Triple) => ({ [ss]: f[0], [pp]: f[1], [oo]: f[2] });
}
};
42 changes: 42 additions & 0 deletions packages/rstream-query/src/qvar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { isString } from "@thi.ng/checks/is-string";

import { Triple } from "./api";

const AUTO_QVAR_PREFIX = "?__q";
let AUTO_QVAR_ID = 0;

Expand All @@ -14,3 +16,43 @@ export const autoQVar = () =>

export const qvarName = (x: string) =>
x.substr(1);

/**
* Returns an optimized query variable solution extractor function based
* on given pattern type. `vs`, `vp`, `vo` are flags to indicate if `s`,
* `p` and/or `o` pattern items are query variables. The returned fn
* will be optimized to 1 of the 8 possible case and accepts a single
* fact to extract the respective variables from.
*
* @param vs
* @param vp
* @param vo
* @param s
* @param p
* @param o
*/
export const qvarResolver = (vs: boolean, vp: boolean, vo: boolean, s, p, o) => {
const type = ((<any>vs) << 2) | ((<any>vp) << 1) | (<any>vo);
let ss: any = vs && qvarName(s);
let pp: any = vp && qvarName(p);
let oo: any = vo && qvarName(o);
switch (type) {
case 0:
default:
return;
case 1:
return (f: Triple) => ({ [oo]: f[2] });
case 2:
return (f: Triple) => ({ [pp]: f[1] });
case 3:
return (f: Triple) => ({ [pp]: f[1], [oo]: f[2] });
case 4:
return (f: Triple) => ({ [ss]: f[0] });
case 5:
return (f: Triple) => ({ [ss]: f[0], [oo]: f[2] });
case 6:
return (f: Triple) => ({ [ss]: f[0], [pp]: f[1] });
case 7:
return (f: Triple) => ({ [ss]: f[0], [pp]: f[1], [oo]: f[2] });
}
};
Loading

0 comments on commit 679c4e0

Please sign in to comment.