@dialog-db/query
Version:
Datalog query engine inspired by Datomic
521 lines • 20.6 kB
TypeScript
export { $ };
export function select(selector: API.Select): Select;
export function rule<Match extends API.Proposition>(source: API.DeductiveRule<Match>): DeductiveRule<Match>;
export function formula<Operator extends API.SystemOperator["operator"]>(operator: Operator): Formula<API.SystemOperator & {
operator: Operator;
}>;
export function recur<Match extends API.Proposition = API.Proposition>(terms: API.RuleBindings<Match>): RuleRecursion<Match>;
export function from(source: API.Conjunct | API.Recur): Select | FormulaApplication | Negation | RuleApplication<any> | RuleRecursion<any>;
/**
* @template {API.Proposition} [Match=API.Proposition]
* @implements {API.MatchRule<Match>}
* @implements {API.RuleApplicationSyntax<Match>}
*/
export class RuleApplication<Match extends API.Proposition = API.Proposition> implements API.MatchRule<Match>, API.RuleApplicationSyntax<Match> {
/**
* @template {API.Proposition} [Match=API.Proposition]
* @param {API.MatchRule<Match>} source
* @returns {RuleApplication<Match>}
*/
static from<Match_1 extends API.Proposition = API.Proposition>(source: API.MatchRule<Match_1>): RuleApplication<Match_1>;
/**
* Creates a rule application with a given `rule` and set of `terms`.
*
* @template {API.Proposition} Match
* @param {DeductiveRule<Match>} rule
* @param {Partial<API.RuleBindings<Match>>} terms
*/
static "new"<Match_1 extends API.Proposition>(rule: DeductiveRule<Match_1>, terms: Partial<API.RuleBindings<Match_1>>): RuleApplication<Match_1>;
/**
* @param {Partial<API.RuleBindings<Match>> & {}} match
* @param {DeductiveRule<Match>} rule
* @param {API.Cursor} references
* @param {API.MatchFrame} bindings
* @param {Map<API.Variable, number>} cells
*/
constructor(match: Partial<API.RuleBindings<Match>> & {}, rule: DeductiveRule<Match>, references?: API.Cursor, bindings?: API.MatchFrame, cells?: Map<API.Variable, number>);
match: Partial<API.RuleBindings<Match>>;
rule: DeductiveRule<Match>;
/**
* Mapping between variables inside the rule and variables that they were
* bound to via rule application. Given below example we will have mapping
* `$.name → $.q`.
*
* ```js
* {
* match: { name: $.q },
* rule: {
* match: { name: $.name },
* when: {
* where: [{ match: { the: "person/name", is: $.name } }]
* }
* }
* }
* ```
*/
references: API.Cursor;
/**
* Mapping between variables inside the rule and constants that they were
* bound to via rule application. Given below example we will have a mapping
* `$.name → "Irakli"`.
*
* ```js
* {
* match: { name: "Irakli", address: $.q },
* rule: {
* match: { name: $.name, $.address },
* when: {
* where: [
* { match: { the: "person/name", of: $.person, is: $.name } },
* { match: { the: "person/address", of: $.person, is: $.address } }
* ]
* }
* }
* }
* ```
*/
bindings: API.MatchFrame;
/**
* Mapping between variables that were bound in the application and the
* cost estimate for them staying unbound.
*/
cells: Map<API.Variable<API.Scalar>, number>;
get recurs(): null;
/**
* Base cost of the rule application is the base cost of the rule itself.
*/
get cost(): number;
/**
* Plans the rule execution in the given scope. `RuleApplication` links rule
* variables (`this.rule.match`) to the variables passed in an application
* (`this.match`). However rule application itself may be nested inside some
* rule where terms (`this.match`) gets linked in this planning phase.
*
* @param {API.Scope} scope
*/
plan(scope: API.Scope): Plan.RuleApplication<Match>;
prepare(): API.RuleApplicationPlan<Match>;
/**
* Runs this rule application as a query in on a given `input`.
*
* @param {object} input
* @param {API.Querier} input.from
*/
query(input: {
from: API.Querier;
}): API.Task<API.MatchFrame[], Error, typeof import("./task.js").SUSPEND | import("./task.js").Join | import("./task.js").Throw<Error>>;
toDebugString(): string;
toJSON(): {
match: object | API.Scalar;
rule: {
match: object | API.Scalar;
when: {
[k: string]: Conjunct[];
};
};
};
negate(): Negation;
#private;
}
/**
* @template {API.Proposition} [Match=API.Proposition]
* @implements {API.DeductiveRuleSyntax<Match>}
*/
export class DeductiveRule<Match extends API.Proposition = API.Proposition> implements API.DeductiveRuleSyntax<Match> {
/**
* @template {API.Proposition} Case
* @param {API.DeductiveRule<Case>} source
*/
static from<Case extends API.Proposition>(source: API.DeductiveRule<Case>): DeductiveRule<Case>;
/**
* @param {Match} match - Pattern to match against
* @param {Map<API.Variable, number>} cells - Cost per variable when not bound
* @param {number} cost - Base execution cost
* @param {boolean} recurs
* @param {Record<string, Join>} when - Named deductive branches that must be evaluated
*/
constructor(match: Match, cells: Map<API.Variable, number>, cost: number, recurs: boolean, when: Record<string, Join>);
match: Match;
cells: Map<API.Variable<API.Scalar>, number>;
cost: number;
recurs: boolean;
when: Record<string, Join>;
/**
* @param {API.RuleBindings<Match>} terms
* @returns {RuleApplication<Match>}
*/
apply(terms?: API.RuleBindings<Match>): RuleApplication<Match>;
/**
* @param {API.Scope} application
*/
plan(application: API.Scope): Plan.DeductiveRule<Match>;
toDebugString(): string;
toJSON(): {
match: object | API.Scalar;
when: {
[k: string]: Conjunct[];
};
};
}
/**
* @template {API.Proposition} [Match=API.Proposition]
* @implements {API.RuleRecursionSyntax<Match>}
*/
export class RuleRecursion<Match extends API.Proposition = API.Proposition> implements API.RuleRecursionSyntax<Match> {
/**
* @template {API.Proposition} [Match=API.Proposition]
* @param {API.Recur<Match>} source
*/
static from<Match_1 extends API.Proposition = API.Proposition>({ recur: terms }: API.Recur<Match_1>): RuleRecursion<Match_1>;
/**
* @param {API.RuleBindings<Match>} terms
* @param {Map<API.Variable, number>} cells
*/
constructor(terms: API.RuleBindings<Match>, cells: Map<API.Variable, number>);
get recurs(): this;
get references(): Map<any, any>;
terms: API.RuleBindings<Match>;
cells: Map<API.Variable<API.Scalar>, number>;
get recur(): API.RuleBindings<Match>;
get cost(): number;
/**
* @param {API.Scope} scope
*/
plan(scope: API.Scope): this;
toJSON(): {
recur: API.RuleBindings<Match>;
};
toDebugString(): string;
/**
* Instead of direct recursion, we collect bindings to be processed later
* in a breadth-first fixed-point iteration.
*
* @param {API.EvaluationContext} context
*/
evaluate({ self, selection, recur }: API.EvaluationContext): Generator<never, never[], unknown>;
}
/**
* @implements {API.Every<API.Conjunct|API.Recur>}
*/
export class Join implements API.Every<API.Conjunct | API.Recur> {
/**
* @param {object} source
* @param {Map<string, API.Variable>} source.bindings
* @param {string} source.name
* @param {API.Every<API.Conjunct|API.Recur>} source.conjuncts
* @param {Set<API.Variable>} [source.variables]
*/
static from({ bindings, name, conjuncts: forms, variables, }: {
bindings: Map<string, API.Variable>;
name: string;
conjuncts: API.Every<API.Conjunct | API.Recur>;
variables?: Set<API.Variable<API.Scalar>> | undefined;
}): Join;
/**
* Ensures that given bindings are referenced from inside this join. Throws
* a `ReferenceError` if there is a binding that is not referenced. The reason
* if rule contains binding that is not used is in it's body it will either
* not get bound or will not contribute to the rule in both cases rule is
* likely not captures intended logic. Note that it theory rule may use some
* variables only in some logic branches in which case those variables could
* be considered as required input, but even then it is indicative of bad rule
* design which could be broken apart into multiple rules which is why we
* choose to error on side of caution. It is also always possible to consume
* variable in cases where it really isn't needed.
*
* @param {Map<API.Variable, number>} cells
* @param {Map<string, API.Variable>} bindings
* @param {string} name
*/
static ensureBindings(cells: Map<API.Variable, number>, bindings: Map<string, API.Variable>, name: string): typeof Join;
/**
* @param {Conjunct[]} conjuncts
* @param {Map<API.Variable, number>} cells
* @param {number} cost
* @param {boolean} recurs
* @param {string} name
*/
constructor(conjuncts: Conjunct[], cells: Map<API.Variable, number>, cost: number, recurs: boolean, name: string);
conjuncts: Conjunct[];
cells: Map<API.Variable<API.Scalar>, number>;
cost: number;
name: string;
recurs: boolean;
/**
* @param {API.Scope} scope
* @returns {Plan.Join}
*/
plan(scope: API.Scope): Plan.Join;
toJSON(): Conjunct[];
toDebugString(): string;
/**
* @returns {IterableIterator<API.Conjunct|API.Recur>}
*/
[Symbol.iterator](): IterableIterator<API.Conjunct | API.Recur>;
}
/**
* @typedef {Select|FormulaApplication|RuleApplication} Constraint
* @typedef {Select|FormulaApplication|RuleApplication|Negation|RuleRecursion} Conjunct
* @implements {API.NegationSyntax}
*/
export class Negation implements API.NegationSyntax {
/**
* @param {API.Negation} source
* @returns {Negation}
*/
static from({ not: constraint }: API.Negation): Negation;
/**
* @param {Constraint} constraint
*/
static "new"(constraint: Constraint): Negation;
/**
* @param {Constraint} constraint
* @param {Map<API.Variable, number>} cells
*/
constructor(constraint: Constraint, cells: Map<API.Variable, number>);
get recurs(): null;
constraint: Constraint;
cells: Map<API.Variable<API.Scalar>, number>;
get references(): API.Cursor | Map<any, any>;
get not(): API.Constraint;
get cost(): number;
/**
* @param {API.Scope} scope
* @returns {Plan.Negation}
*/
plan(scope: API.Scope): Plan.Negation;
toJSON(): {
not: {
match: API.Select;
} | {
match: API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
with: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<boolean, boolean> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<API.Scalar, API.TypeName> | API.FormulaMatch<Record<string, API.Scalar>, API.Link<Record<string, API.Scalar>, 113, 30>> | API.FormulaMatch<{
text: string;
pattern: string;
}, string> | API.FormulaMatch<string, number> | API.FormulaMatch<string, string> | API.FormulaMatch<Uint8Array<ArrayBufferLike>, string> | API.FormulaMatch<string, Uint8Array<ArrayBufferLike>> | API.FormulaMatch<{
this: string;
slice: string;
}, true> | API.FormulaMatch<{
of: string;
start: string;
end: string;
}, string> | API.FormulaMatch<{
of: string;
with: string;
}, string> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, number> | API.FormulaMatch<number, number> | API.FormulaMatch<API.Scalar, API.Scalar>;
operator: "/" | "*" | "%" | "+" | "<" | "!" | "==" | ">" | ">=" | "<=" | "data/type" | "data/refer" | "text/like" | "text/length" | "text/words" | "text/lines" | "text/case/upper" | "text/case/lower" | "text/trim" | "text/trim/start" | "text/trim/end" | "utf8/to/text" | "text/to/utf8" | "text/includes" | "text/slice" | "text/concat" | "-" | "**" | "math/absolute";
} | {
match: object | API.Scalar;
rule: {
match: object | API.Scalar;
when: {
[k: string]: Conjunct[];
};
};
};
};
toDebugString(): string;
}
export type Constraint = Select | FormulaApplication | RuleApplication;
export type Conjunct = Select | FormulaApplication | RuleApplication | Negation | RuleRecursion;
import { $ } from './$.js';
import * as API from './api.js';
/**
* @implements {API.SelectForm}
* @implements {API.SelectSyntax}
*/
declare class Select implements API.SelectForm, API.SelectSyntax {
/**
* @param {API.SelectForm} source
*/
static from({ match }: API.SelectForm): Select;
/**
* @param {API.Select} selector
* @param {Map<API.Variable, number>} cells
*/
constructor(selector: API.Select, cells: Map<API.Variable, number>);
cells: Map<API.Variable<API.Scalar>, number>;
selector: API.Select;
get references(): Map<any, any>;
get recurs(): null;
get match(): API.Select;
/**
* Base execution cost of the select operation.
*/
get cost(): number;
/**
*
* @param {API.Scope} scope
*/
plan({ references, bindings }: API.Scope): Plan.Select;
toJSON(): {
match: API.Select;
};
toDebugString(): string;
}
/**
* @template {API.SystemOperator} Operator
*/
declare class Formula<Operator extends API.SystemOperator> {
/**
*
* @param {Operator['operator']} operator
*/
constructor(operator: Operator["operator"]);
operator: Operator["operator"];
/**
* @param {Operator['match']} terms
*/
apply(terms: Operator["match"]): FormulaApplication;
}
declare class FormulaApplication {
/**
* @param {API.SystemOperator} source
*/
static from(source: API.SystemOperator): FormulaApplication;
/**
* @param {API.SystemOperator} source
* @param {Map<API.Variable, number>} cells
* @param {Record<string, API.Term>|API.Term} from
* @param {Record<string, API.Term>} to
*/
constructor(source: API.SystemOperator, cells: Map<API.Variable, number>, from: Record<string, API.Term> | API.Term, to: Record<string, API.Term>);
cells: Map<API.Variable<API.Scalar>, number>;
source: API.SystemOperator;
from: API.Term<API.Scalar> | Record<string, API.Term<API.Scalar>>;
to: Record<string, API.Term<API.Scalar>>;
get references(): Map<any, any>;
get match(): API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
with: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<boolean, boolean> | API.FormulaMatch<API.Scalar, API.Scalar> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<API.Scalar, API.TypeName> | API.FormulaMatch<Record<string, API.Scalar>, API.Link<Record<string, API.Scalar>, 113, 30>> | API.FormulaMatch<{
text: string;
pattern: string;
}, string> | API.FormulaMatch<string, number> | API.FormulaMatch<string, string> | API.FormulaMatch<Uint8Array<ArrayBufferLike>, string> | API.FormulaMatch<string, Uint8Array<ArrayBufferLike>> | API.FormulaMatch<{
this: string;
slice: string;
}, true> | API.FormulaMatch<{
of: string;
start: string;
end: string;
}, string> | API.FormulaMatch<{
of: string;
with: string;
}, string> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, number> | API.FormulaMatch<number, number>;
get operator(): "/" | "*" | "%" | "+" | "<" | "!" | "==" | ">" | ">=" | "<=" | "data/type" | "data/refer" | "text/like" | "text/length" | "text/words" | "text/lines" | "text/case/upper" | "text/case/lower" | "text/trim" | "text/trim/start" | "text/trim/end" | "utf8/to/text" | "text/to/utf8" | "text/includes" | "text/slice" | "text/concat" | "-" | "**" | "math/absolute";
get recurs(): null;
/**
* Base execution cost of the formula application operation.
*/
get cost(): number;
/**
* @param {API.Scope} scope
*/
plan(scope: API.Scope): Plan.FormulaApplication;
toJSON(): {
match: API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
with: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<boolean, boolean> | API.FormulaMatch<API.Scalar, API.Scalar> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<{
this: string | number;
than: string | number;
}, {}> | API.FormulaMatch<API.Scalar, API.TypeName> | API.FormulaMatch<Record<string, API.Scalar>, API.Link<Record<string, API.Scalar>, 113, 30>> | API.FormulaMatch<{
text: string;
pattern: string;
}, string> | API.FormulaMatch<string, number> | API.FormulaMatch<string, string> | API.FormulaMatch<Uint8Array<ArrayBufferLike>, string> | API.FormulaMatch<string, Uint8Array<ArrayBufferLike>> | API.FormulaMatch<{
this: string;
slice: string;
}, true> | API.FormulaMatch<{
of: string;
start: string;
end: string;
}, string> | API.FormulaMatch<{
of: string;
with: string;
}, string> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, API.Numeric> | API.FormulaMatch<{
of: API.Numeric;
by: API.Numeric;
}, number> | API.FormulaMatch<number, number>;
operator: "/" | "*" | "%" | "+" | "<" | "!" | "==" | ">" | ">=" | "<=" | "data/type" | "data/refer" | "text/like" | "text/length" | "text/words" | "text/lines" | "text/case/upper" | "text/case/lower" | "text/trim" | "text/trim/start" | "text/trim/end" | "utf8/to/text" | "text/to/utf8" | "text/includes" | "text/slice" | "text/concat" | "-" | "**" | "math/absolute";
};
toDebugString(): string;
}
import * as Plan from './plan.js';
//# sourceMappingURL=syntax.d.ts.map