api.ts
1 import { ByteView } from 'multiformats' 2 import { Task, Invocation } from './task.js' 3 4 export type { ByteView, Task } 5 6 /** 7 * Generic reader interface that can be used to read `O` value form the 8 * input `I` value. Reader may fail and error is denoted by `X` type. 9 * 10 * @template O - The output type of this reader 11 * @template I - The input type of this reader. 12 * @template X - The error type denotes failure reader may produce. 13 */ 14 export interface TryFrom< 15 Type extends { 16 Self: unknown 17 Input: unknown 18 }, 19 > { 20 tryFrom: (input: Type['Input']) => Result<Type['Self'], Error> 21 } 22 23 /** 24 * Defines result type as per invocation spec 25 * 26 * @see https://github.com/ucan-wg/invocation/#6-result 27 */ 28 29 export type Result<T = unknown, X extends {} = {}> = Variant<{ 30 ok: T 31 error: X 32 }> 33 34 /** 35 * Utility type for defining a [keyed union] type as in IPLD Schema. In practice 36 * this just works around typescript limitation that requires discriminant field 37 * on all variants. 38 * 39 * ```ts 40 * type Result<T, X> = 41 * | { ok: T } 42 * | { error: X } 43 * 44 * const demo = (result: Result<string, Error>) => { 45 * if (result.ok) { 46 * // ^^^^^^^^^ Property 'ok' does not exist on type '{ error: Error; }` 47 * } 48 * } 49 * ``` 50 * 51 * Using `Variant` type we can define same union type that works as expected: 52 * 53 * ```ts 54 * type Result<T, X> = Variant<{ 55 * ok: T 56 * error: X 57 * }> 58 * 59 * const demo = (result: Result<string, Error>) => { 60 * if (result.ok) { 61 * result.ok.toUpperCase() 62 * } 63 * } 64 * ``` 65 * 66 * [keyed union]:https://ipld.io/docs/schemas/features/representation-strategies/#union-keyed-representation 67 */ 68 export type Variant<U extends Record<string, unknown>> = { 69 [Key in keyof U]: { [K in Exclude<keyof U, Key>]?: never } & { 70 [K in Key]: U[Key] 71 } 72 }[keyof U] 73 74 export type Tagged<T> = { 75 [Case in keyof T]: Exclude<keyof T, Case> extends never ? T 76 : InferenceError<'It may only contain one key'> 77 }[keyof T] 78 79 /** 80 * Utility type for including type errors in the typescript checking. It 81 * defines impossible type (object with non-existent unique symbol field). 82 * This type can be used in cases where typically `never` is used, but 83 * where some error message would be useful. 84 */ 85 interface InferenceError<message> { 86 [Marker]: never & message 87 } 88 89 export declare const Marker: unique symbol 90 91 /** 92 * A utility type to retain an unused type parameter `T`. 93 * Similar to [phantom type parameters in Rust](https://doc.rust-lang.org/rust-by-example/generics/phantom.html). 94 * 95 * Capturing unused type parameters allows us to define "nominal types," which 96 * TypeScript does not natively support. Nominal types in turn allow us to capture 97 * semantics not represented in the actual type structure, without requiring us to define 98 * new classes or pay additional runtime costs. 99 * 100 * For a concrete example, see {@link ByteView}, which extends the `Uint8Array` type to capture 101 * type information about the structure of the data encoded into the array. 102 */ 103 export interface Phantom<T> { 104 // This field can not be represented because field name is non-existent 105 // unique symbol. But given that field is optional any object will valid 106 // type constraint. 107 [Marker]?: T 108 } 109 110 export type New<T, Type = Tagged<T>> = Tagged<T>[keyof Tagged<T>] & 111 Phantom<Type> 112 113 /** 114 * Type representing a unit value. 115 */ 116 export interface Unit {} 117 118 /** 119 * Variable integer. 120 */ 121 export type Integer = New<{ Integer: number }> 122 123 export type Float = New<{ Float: number }> 124 125 /** 126 * Type representing a raw bytes. 127 */ 128 export type Bytes = Uint8Array 129 130 export type Null = null 131 132 export type Reference = New<{ Reference: string }> 133 134 export type Name = New<{ Name: string }> 135 136 export type Position = New<{ Position: string }> 137 138 /** 139 * Type representing an IPLD link. 140 */ 141 export interface Link< 142 Data extends {} | null = {} | null, 143 Format extends number = number, 144 Alg extends number = number, 145 > { 146 ['/']: ByteView<this> 147 } 148 149 /** 150 * All the constants in the system represented as a union of the following types. 151 * 152 * We are likely to introduce uint32, int8, uint8 and etc but for now we have 153 * chosen to keep things simple. 154 */ 155 export type Scalar = 156 | null 157 | boolean 158 | bigint 159 | Integer 160 | Float 161 | string 162 | Bytes 163 | Link 164 165 /** 166 * @deprecated Use `Scalar` instead. 167 */ 168 export type Constant = Scalar 169 170 /** 171 * Supported primitive types. Definition utilizes `Phantom` type to describe 172 * the type for compile type inference and `Variant` type to describe it for 173 * the runtime inference. 174 * 175 * Note we denote lexical order between types via `order` field. This is used 176 * when comparing data across types. 177 */ 178 export type Type<T extends Scalar = Scalar> = Phantom<T> & 179 Variant<{ 180 Null: {} 181 Boolean: {} 182 Integer: {} 183 Float: {} 184 String: {} 185 Bytes: {} 186 Entity: {} 187 Name: {} 188 Position: {} 189 Reference: {} 190 Unknown: {} 191 }> 192 193 // /** 194 // * Variable is placeholder for a value that will be ed against by the 195 // * query engine. It is represented as an abstract `Reader` that will attempt 196 // * to read arbitrary {@type Data} and return result with either `ok` of the 197 // * `Type` or an `error`. 198 // * 199 // * Variables will be assigned unique `bindingKey` by a query engine that will 200 // * be used as unique identifier for the variable. 201 // */ 202 // export interface Variable<T extends Constant = Constant> 203 // extends TryFrom<{ Self: T; Input: Constant }> { 204 // type: RowType 205 // [VARIABLE_ID]?: VariableID 206 // } 207 208 /** 209 * Variable is placeholder for a value that will be matched against by the 210 * query engine. 211 */ 212 export interface Variable<T extends Scalar = Scalar> { 213 ['?']: { 214 type?: Type<T> 215 id: VariableID 216 } 217 218 // is(term: Term): Conjunct 219 // not(term: Term): Conjunct 220 } 221 222 export type VariableID = number 223 224 /** 225 * Term is either a constant or a {@link Variable}. Terms are used to describe 226 * predicates of the query. 227 */ 228 export type Term<T extends Scalar = Scalar> = T | Variable<T> 229 230 /** 231 * Describes association between `entity`, `attribute`, `value` of the 232 * {@link Fact}. Each component of the {@link _Relation} is a {@link Term} 233 * that is either a constant or a {@link Variable}. 234 * 235 * Query engine during execution will attempt to match {@link _Relation} against 236 * all facts in the database and unify {@link Variable}s across them to identify 237 * all possible solutions. 238 */ 239 export type Pattern = readonly [ 240 entity: Term<Entity>, 241 attribute: Term<Attribute>, 242 value: Term<Scalar>, 243 ] 244 245 export type Is = readonly [binding: Term<Scalar>, value: Term<Scalar>] 246 247 export type Clause = Variant<{ 248 // and clause 249 And: Clause[] 250 // or clause 251 Or: Clause[] 252 // negation 253 Not: Clause 254 // pattern match a fact 255 Case: Pattern 256 257 // rule application 258 Rule: RuleApplication 259 // assign bindings 260 Is: Is 261 262 Match: Formula 263 }> 264 265 export type InferCase< 266 Methods extends Record<string, (input: any, context: any) => any> = {}, 267 > = { 268 [Case in keyof Methods]: { 269 Case: Case 270 Input: Parameters<Methods[Case]>[0] 271 Context: Parameters<Methods[Case]>[1] 272 Output: ReturnType<Methods[Case]> 273 } 274 } 275 276 export type DispatchCase< 277 Methods extends Record<string, (input: {}, context: {}) => {}> = {}, 278 > = { 279 <Case extends keyof Methods>( 280 input: InferCase<Methods>[Case]['Input'], 281 context: InferCase<Methods>[Case]['Context'] 282 ): InferCase<Methods>[Case]['Output'] 283 } 284 export type Dispatch< 285 Methods extends Record<string, (input: any, context: any) => any> = {}, 286 > = DispatchCase<Methods> & { 287 with<Extension extends Record<string, (input: any, context: any) => any>>( 288 extension: Extension 289 ): Dispatch<Methods & Extension> 290 } 291 292 export type Terms = Record<string, Term> | [Term, ...Term[]] | Term 293 294 /** 295 * Row is a named set of values which by default are {@link Term}s. It is meant 296 * to represent a non-nested tuple with named members as opposed to indexed 297 * members. 298 */ 299 export interface Row<T = Term> { 300 [Key: string]: T 301 } 302 303 export type Numeric = Integer | Float 304 305 /** 306 * Describes operand of the operator. 307 */ 308 export type Operand = Scalar | Record<string, Scalar> | [Scalar, ...Scalar[]] 309 310 type EphemeralEntity = 311 | Term<Entity> 312 | Record<string, Term> 313 | [Term<Entity>, ...Term<Entity>[]] 314 315 export type InferOperand<T, K = T> = K extends Scalar ? Term<T & Scalar> 316 : K extends Array<infer U extends Scalar> ? Term<U>[] 317 : { 318 [Key in keyof K]: T[Key & keyof T] & K[Key] extends infer U extends Scalar ? 319 Term<U> 320 : never 321 } 322 323 export type TypeName = 324 | 'null' 325 | 'boolean' 326 | 'string' 327 | 'bigint' 328 | 'integer' 329 | 'float' 330 | 'bytes' 331 | 'reference' 332 333 export type Tuple<T> = [T, ...T[]] 334 335 export type InferYield<T> = T extends Iterable<infer U> ? U : never 336 337 export type InferFormula< 338 Operator extends string, 339 Formula extends (input: In) => Iterable<Out>, 340 In extends Operand = Parameters<Formula>[0], 341 Out extends Operand = InferYield<ReturnType<Formula>>, 342 > = readonly [ 343 input: InferOperand<In>, 344 operator: Operator, 345 output?: InferOperand<Out>, 346 ] 347 348 import * as DataOperators from './formula/data.js' 349 import * as TextOperators from './formula/text.js' 350 import * as UTF8Operators from './formula/utf8.js' 351 import * as MathOperators from './formula/math.js' 352 353 export type Formula = 354 | InferFormula<'==', typeof DataOperators.is> 355 | InferFormula<'>', typeof DataOperators.greater> 356 | InferFormula<'>=', typeof DataOperators.greaterOrEqual> 357 | InferFormula<'<', typeof DataOperators.less> 358 | InferFormula<'<=', typeof DataOperators.lessOrEqual> 359 | InferFormula<'data/type', typeof DataOperators.type> 360 | InferFormula<'data/refer', typeof DataOperators.refer> 361 | InferFormula<'text/like', typeof TextOperators.like> 362 | InferFormula<'text/length', typeof TextOperators.length> 363 | InferFormula<'text/words', typeof TextOperators.words> 364 | InferFormula<'text/lines', typeof TextOperators.lines> 365 | InferFormula<'text/case/upper', typeof TextOperators.toUpperCase> 366 | InferFormula<'text/case/lower', typeof TextOperators.toUpperCase> 367 | InferFormula<'text/trim', typeof TextOperators.trim> 368 | InferFormula<'text/trim/start', typeof TextOperators.trimStart> 369 | InferFormula<'text/trim/end', typeof TextOperators.trimEnd> 370 | InferFormula<'utf8/to/text', typeof UTF8Operators.fromUTF8> 371 | InferFormula<'text/to/utf8', typeof UTF8Operators.toUTF8> 372 | InferFormula<'text/includes', typeof TextOperators.includes> 373 | InferFormula<'text/slice', typeof TextOperators.slice> 374 | InferFormula<'text/concat', typeof TextOperators.concat> 375 | InferFormula<'+', typeof MathOperators.addition> 376 | InferFormula<'-', typeof MathOperators.subtraction> 377 | InferFormula<'*', typeof MathOperators.multiplication> 378 | InferFormula<'/', typeof MathOperators.division> 379 | InferFormula<'%', typeof MathOperators.modulo> 380 | InferFormula<'**', typeof MathOperators.power> 381 | InferFormula<'math/absolute', typeof MathOperators.absolute> 382 383 export type InferTerms<T extends Terms> = 384 T extends Term<infer U> ? U 385 : { [Key in keyof T]: T[Key] extends Term<infer U> ? U : never } 386 387 export type Frame = Record<PropertyKey, Term> 388 389 export type Entity = Link 390 export type Attribute = string 391 392 /** 393 * An atomic fact in the database, associating an `entity` , `attribute` , 394 * `value`. 395 * 396 * - `entity` - The first component is `entity` that specifies who or what the fact is about. 397 * - `attribute` - Something that can be said about an `entity` . An attribute has a name, 398 * e.g. "firstName" and a value type, e.g. string, and a cardinality. 399 * - `value` - Something that does not change e.g. 42, "John", true. Fact relates 400 * an `entity` to a particular `value` through an `attribute`.ich 401 */ 402 export interface Fact< 403 T extends The = The, 404 Of extends Entity = Entity, 405 Is extends Scalar = Scalar, 406 > { 407 the: The 408 of: Of 409 is: Is 410 } 411 412 /** 413 * An atomic {@link Fact} with a `cause` field providing a causal relationship 414 * that acts like timestamp. 415 */ 416 export interface Datum< 417 T extends The = The, 418 Of extends Entity = Entity, 419 Is extends Scalar = Scalar, 420 > extends Fact<T, Of, Is> { 421 cause: Entity 422 } 423 424 /** 425 * Set of {@link Fact}s associating several attributes with the same new entity. 426 * Each key represents an `attribute` and corresponding value represents it's 427 * `value`. 428 * 429 * If value is an array of {@link Scalar}s then entity is associated each 430 * value with a same attribute. 431 * 432 * If value is an `Instantiation` then entity is associated with a new entity 433 * that is described by that `Instantiation`. 434 * 435 * If value is an array of `Instantiation`s then entity is associated with a 436 * each `Instantiation` in the array with an attribute corresponding to the 437 * key. 438 */ 439 export interface DataImport { 440 [Key: string]: Scalar | Scalar[] | DataImport | DataImport[] 441 } 442 443 export interface FactsSelector { 444 the?: Attribute 445 of?: Entity 446 is?: Scalar 447 } 448 449 export type Instruction = Variant<{ 450 assert: Fact 451 retract: Fact 452 }> 453 454 export interface Transaction extends Iterable<Instruction> {} 455 456 export interface Transactor<Ok extends {} = {}> { 457 transact(transaction: Transaction): Task<Ok, Error> 458 } 459 460 export interface Querier { 461 select(selector?: FactsSelector): Task<Datum[], Error> 462 } 463 464 export type Proposition = Row<Variable> & { 465 this?: Variable 466 } 467 468 export type Rule<Match extends Proposition = Proposition> = DeductiveRule<Match> 469 470 export interface DeductiveRule<Match extends Proposition = Proposition> { 471 readonly match: Match 472 readonly when?: When<Conjunct | Recur> 473 } 474 475 export type Constraint = SelectForm | MatchRule | SystemOperator 476 477 export interface Negation { 478 not: Constraint 479 480 operator?: undefined 481 fact?: undefined 482 rule?: undefined 483 match?: undefined 484 recur?: undefined 485 } 486 487 export type Conjunct = Constraint | Negation 488 export type Recur<Match extends Proposition = Proposition> = { 489 recur: RuleBindings<Match> 490 491 operator?: undefined 492 fact?: undefined 493 rule?: undefined 494 match?: undefined 495 not?: undefined 496 } 497 498 export type Every<T extends Conjunct | Recur = Conjunct> = Iterable<T> 499 export interface Some<T extends Conjunct | Recur = Conjunct> { 500 readonly [Case: string]: Every<T> 501 } 502 503 export type When<T extends Conjunct | Recur = Conjunct> = Some<T> 504 505 export type WhenBuilder<T extends RuleDescriptor> = 506 | SomeBuilder<T> 507 | EveryBuilder<T> 508 509 export type SomeBuilder<T extends RuleDescriptor> = ( 510 variables: InferSchemaAttributes<T> & { _: Variable<any> } 511 ) => SomeView 512 export type EveryBuilder<T extends RuleDescriptor> = ( 513 variables: InferSchemaAttributes<T> & { _: Variable<any> } 514 ) => EveryView 515 516 export type ProjectionBuilder< 517 T extends RuleDescriptor, 518 Projection extends Selector, 519 > = (variables: InferSchemaAttributes<T>) => Projection 520 521 export type WhenView = EveryView | SomeView 522 export type EveryView = ConjunctView[] 523 export type ConjunctView = Conjunct | MatchView<unknown> | void 524 525 export interface SomeView { 526 [Case: string]: EveryView 527 } 528 529 export interface MatchRule<Match extends Proposition = Proposition> { 530 readonly match: Partial<RuleBindings<Match>> 531 readonly rule: Rule<Match> 532 533 operator?: undefined 534 fact?: undefined 535 536 not?: undefined 537 538 recur?: undefined 539 } 540 541 export interface Syntax { 542 toJSON(): object 543 toDebugString(): string 544 545 plan(scope: Scope): EvaluationPlan 546 } 547 548 export interface SelectSyntax extends Syntax, SelectForm {} 549 550 export interface RuleSyntax<Match extends Proposition = Proposition> 551 extends Syntax, 552 DeductiveRule<Match> { 553 plan(scope: Scope): RulePlan 554 } 555 556 export interface RuleApplicationSyntax<Match extends Proposition = Proposition> 557 extends Syntax, 558 MatchRule<Match> { 559 negate(): NegationSyntax 560 plan(scope: Scope): RuleApplicationPlan<Match> 561 prepare(): RuleApplicationPlan<Match> 562 } 563 564 export interface DeductiveRuleSyntax<Match extends Proposition = Proposition> 565 extends Syntax, 566 DeductiveRule<Match> { 567 apply(terms?: RuleBindings<Match>): RuleApplicationSyntax<Match> 568 } 569 570 export interface RuleRecursionSyntax<Match extends Proposition = Proposition> 571 extends Recur<Match> {} 572 573 export interface NegationSyntax extends Syntax, Negation {} 574 575 export interface SelectForm { 576 match: Select 577 578 /** 579 * The `fact` field is reserved for the future use where it could be used to 580 * specify data source or 581 */ 582 fact?: {} 583 584 /** 585 * The `rule` field can not be defined in order to be distinguishable 586 * from the {@link RuleApplication} type. 587 */ 588 rule?: undefined 589 590 /** 591 * The `not` field can not be defined in order to be distinguishable 592 * from the {@link Negation} type. 593 */ 594 not?: undefined 595 596 operator?: undefined 597 598 recur?: undefined 599 } 600 601 export type Select = SelectByAttribute | SelectByEntity | SelectByValue 602 603 type SelectBy = { 604 /** 605 * {@link Term} representing a relation an entity `of` has with the value 606 * `is`. In RDF notation this will correspond to a predicate. 607 */ 608 the?: Term<Attribute> 609 610 /** 611 * {@link Term} representing the entity / subject. 612 */ 613 of?: Term<Entity> 614 615 /** 616 * {@link Term} representing the value of the attribute on the entity (denoted 617 * by `of`). In RDF notation this will correspond to an object. 618 */ 619 is?: Term<Scalar> 620 621 /** 622 * The `this` field is reserved for the future use where it could be used to 623 * bind the merkle reference for this fact. 624 */ 625 this?: never 626 } 627 628 interface SelectByAttribute extends SelectBy { 629 // Selection by attribute requires an attribute to be specified. 630 the: Term<Attribute> 631 } 632 633 interface SelectByEntity extends SelectBy { 634 // Selection by entity requires an entity to be specified. 635 of: Term<Entity> 636 } 637 638 interface SelectByValue extends SelectBy { 639 // Selection by value requires a value to be specified. 640 is: Term<Scalar> 641 } 642 643 export interface FactSelection { 644 select: Pattern 645 rule?: undefined 646 } 647 648 export interface FormulaApplication { 649 compute: string 650 from: Pattern 651 } 652 653 export type InferFormulaApplication< 654 Operator extends string, 655 Formula extends (input: In) => Iterable<Out>, 656 In extends Operand = Parameters<Formula>[0], 657 Out extends Operand = InferYield<ReturnType<Formula>>, 658 > = { 659 compute: Operator 660 from: InferOperand<In> 661 to?: InferOperand<Out> 662 } 663 664 // export interface InductiveRule< 665 // Match extends Conclusion = Conclusion, 666 // Repeat extends Match = Match, 667 // > { 668 // match: Match 669 // when: Conjuncts 670 // repeat: Repeat 671 // while: When 672 // } 673 674 export type SystemOperator = { 675 [Operator in keyof SystemOperators]: MatchOperator< 676 SystemOperators[Operator], 677 Operator 678 > 679 }[keyof SystemOperators] 680 681 export type MatchOperator<Formula = unknown, Identifier = Formula> = { 682 readonly match: InferFormulaMatch<Formula> 683 readonly operator: Identifier 684 685 formula?: Formula 686 687 fact?: undefined 688 rule?: undefined 689 not?: undefined 690 recur?: undefined 691 } 692 693 export type InferFormulaMatch<F> = 694 F extends (input: infer In) => Iterable<infer Out> ? FormulaMatch<In, Out> 695 : never 696 697 export type FormulaMatch<In, Out> = InferCells<In, 'of'> & 698 Partial<InferCells<Out, 'is'>> 699 700 export type InferCells<In, DefaultName extends string> = In extends Scalar ? 701 { [key in DefaultName]: Term<In> } 702 : In extends any[] ? 703 { 704 [key in DefaultName]: { 705 [Key in keyof In]: In[Key] extends Scalar ? Term<In[Key]> : never 706 } 707 } 708 : { 709 [Key in keyof In]: In[Key] extends Scalar ? Term<In[Key]> : never 710 } 711 712 type SystemOperators = { 713 '==': typeof DataOperators.is 714 '>=': typeof DataOperators.greaterOrEqual 715 '>': typeof DataOperators.greater 716 '<': typeof DataOperators.less 717 '<=': typeof DataOperators.lessOrEqual 718 '!': typeof DataOperators.not 719 'data/type': typeof DataOperators.type 720 'data/refer': typeof DataOperators.refer 721 'text/like': typeof TextOperators.like 722 'text/length': typeof TextOperators.length 723 'text/words': typeof TextOperators.words 724 'text/lines': typeof TextOperators.lines 725 'text/case/upper': typeof TextOperators.toUpperCase 726 'text/case/lower': typeof TextOperators.toUpperCase 727 'text/trim': typeof TextOperators.trim 728 'text/trim/start': typeof TextOperators.trimStart 729 'text/trim/end': typeof TextOperators.trimEnd 730 'utf8/to/text': typeof UTF8Operators.fromUTF8 731 'text/to/utf8': typeof UTF8Operators.toUTF8 732 'text/includes': typeof TextOperators.includes 733 'text/slice': typeof TextOperators.slice 734 'text/concat': typeof TextOperators.concat 735 '+': typeof MathOperators.addition 736 '-': typeof MathOperators.subtraction 737 '*': typeof MathOperators.multiplication 738 '/': typeof MathOperators.division 739 '%': typeof MathOperators.modulo 740 '**': typeof MathOperators.power 741 'math/absolute': typeof MathOperators.absolute 742 } 743 744 export type RuleBindings<Case extends Proposition = Proposition> = { 745 [Key in keyof Case]: Term<Scalar> 746 } 747 748 export interface RuleApplication<Match extends Proposition = Proposition> { 749 // ⚠️ This is actually Partial<RuleBindings<Match>> but we still type it 750 // without `Partial` because at the type level we have no good way of 751 // omitting variables that could be ignored 752 match: RuleBindings<Match> 753 rule: Rule<Match> 754 } 755 756 export type InferRuleMatch<Case extends Proposition> = { 757 [Key in keyof Case]: Case[Key] extends Variable<infer U> ? 758 U extends any ? 759 Term<Scalar> 760 : Term<U> 761 : never 762 } 763 764 export interface Variables extends Record<PropertyKey, Variable> {} 765 766 export interface Bindings extends Record<PropertyKey, Term> {} 767 768 /** 769 * Selection describes set of (named) variables that query engine will attempt 770 * to find values for that satisfy the query. 771 */ 772 // export interface Selector 773 // extends Record<PropertyKey, Term | Term[] | Selector | Selector[]> {} 774 export type Selector = AggregateSelector | NamedSelector 775 776 /** 777 * Where clause describes the conditions that must be satisfied for the query 778 * to return a result. 779 */ 780 export type Where = Iterable<Clause> 781 782 /** 783 * Query that can be evaluated against the database. 784 */ 785 export type Query<Select extends Selector = Selector> = { 786 select: Select 787 where: Where 788 } 789 790 export type AggregateSelector = [Selector | Term] 791 792 export interface NamedSelector extends Record<string, Selector | Term> {} 793 794 export interface Variables extends Record<string, Term> {} 795 796 export type Selection = Selector | Variable<Link<Bindings>> 797 798 export interface Not { 799 not: Constraint 800 match?: void 801 rule?: void 802 } 803 804 export type Combinator = Variant<{}> 805 806 export type Confirmation = Variant<{ 807 ok: Unit 808 error: Error 809 }> 810 811 export type InferBindings<Selection extends Selector> = { 812 [Key in keyof Selection]: Selection[Key] extends Term<infer T> ? T 813 : Selection[Key] extends Term<infer T>[] ? T[] 814 : Selection[Key] extends Selector[] ? InferBindings<Selection[Key][0]>[] 815 : Selection[Key] extends Selector ? InferBindings<Selection[Key]> 816 : never 817 } 818 819 export type InferTerm<T extends Term> = T extends Term<infer U> ? U : never 820 821 export interface Analysis { 822 dependencies: Set<VariableID> 823 binds: Set<VariableID> 824 cost: number 825 } 826 827 export interface Unplannable extends Error { 828 error: this 829 } 830 831 export interface EvaluationPlan { 832 evaluate(context: EvaluationContext): Task<MatchFrame[], EvaluationError> 833 } 834 835 /** 836 * Represents a local variable references to a remote variables. This is n:1 837 * relation meaning multiple local variables may point to the same remote one 838 * but local variable can point to at most one remote variable. 839 */ 840 export type Cursor = Map<Variable, Set<Variable>> 841 842 /** 843 * Represents set of bound variables. 844 */ 845 export type QueryBindings = Map<Variable, Scalar> 846 847 export interface Scope { 848 references: Cursor 849 bindings: QueryBindings 850 } 851 852 export type Plan = Unplannable | EvaluationPlan 853 854 export interface RulePlan extends EvaluationPlan { 855 cost: number 856 match: Proposition 857 } 858 859 export interface RuleApplicationPlan<Match extends Proposition> 860 extends EvaluationPlan { 861 cost: number 862 toJSON(): object 863 query(source: { from: Querier }): Task<MatchFrame[], Error> 864 } 865 866 export interface EvaluationContext { 867 selection: MatchFrame[] 868 source: Querier 869 self: RulePlan 870 recur: [MatchFrame, MatchFrame][] // Array of pairs [nextBindings, originalContext] for recursive processing 871 } 872 873 export interface Evaluator extends EvaluationContext { 874 evaluate(context: EvaluationContext): Task<Bindings[], EvaluationError> 875 } 876 877 export interface EvaluationError extends Error {} 878 879 export type $ = Variable<any> & 880 Record<PropertyKey, Variable<any>> & { 881 new (): $ 882 (): $ 883 884 name: Variable<string> 885 length: Variable<number> 886 prototype: Variable 887 } 888 889 export interface MatchFrame extends Map<Variable, Scalar> { 890 parent?: MatchFrame 891 } 892 893 /** 894 * Describes the effects that clause performs when evaluated. 895 */ 896 export interface Effects { 897 /** 898 * Query an underlying data source for facts. 899 */ 900 readonly query: readonly QueryEffect[] 901 /** 902 * Evaluate underlying clause in a loop potentially many times. 903 */ 904 readonly loop: readonly LoopEffect[] 905 } 906 907 /** 908 * Describes looping effect, meaning that that clause with this effect 909 * may be evaluated multiple times. In a future we may capture more details 910 * about the loop. 911 */ 912 export interface LoopEffect {} 913 914 export interface QueryEffect { 915 select: Pattern 916 } 917 918 export type ObjectDescriptor = { 919 [Key: string]: TypeDescriptor 920 } 921 922 export type ArrayDescriptor = [TypeDescriptor] & { 923 Object?: undefined 924 Rule?: undefined 925 } 926 927 export type UnknownDescriptor = { 928 Unknown: {} 929 } 930 931 export type TypeDescriptor = 932 | Scalar 933 | ScalarConstructor 934 | Type 935 | ObjectDescriptor 936 | ArrayDescriptor 937 938 export type InferDescriptorType<T> = 939 T extends null ? null 940 : T extends { Null: {} } ? null 941 : T extends BooleanConstructor ? boolean 942 : T extends { Boolean: {} } ? boolean 943 : T extends boolean ? T 944 : T extends StringConstructor ? string 945 : T extends { String: {} } ? string 946 : T extends string ? T 947 : T extends NumberConstructor ? Integer 948 : T extends { Integer: {} } ? Integer 949 : T extends { Float: {} } ? Float 950 : T extends number ? T 951 : T extends BigIntConstructor ? bigint 952 : T extends bigint ? T 953 : T extends Uint8ArrayConstructor ? Bytes 954 : T extends { Bytes: {} } ? Bytes 955 : T extends Uint8Array ? T 956 : T extends ObjectConstructor ? Entity 957 : T extends UnknownDescriptor ? Scalar 958 : never 959 960 export type ScalarConstructor = 961 | BooleanConstructor 962 | StringConstructor 963 | NumberConstructor 964 | BigIntConstructor 965 | Uint8ArrayConstructor 966 | ObjectConstructor 967 968 export type ScalarDescriptor = Variant<{ 969 Null: {} 970 Boolean: {} 971 String: {} 972 Int32: {} 973 Float32: {} 974 Int64: {} 975 Bytes: {} 976 Reference: {} 977 Entity: {} 978 Unknown: {} 979 }> & { Object?: undefined; Fact?: undefined; Scalar?: undefined } 980 981 export type ModelDescriptor< 982 Descriptor extends ObjectDescriptor = ObjectDescriptor, 983 > = { 984 Object: Descriptor 985 } 986 987 export type InferTypeTerms<T, U = T> = T extends Scalar ? 988 Term<U extends Scalar ? U : never> 989 : unknown extends T ? Term 990 : InferEntityTerms<T> 991 992 export type TypeTest<T> = T extends Scalar ? Box<T> : never 993 994 export type Box<T> = { 995 t: T 996 } 997 export type InferEntityTerms<T> = Partial< 998 { this: Term<Entity> } & { [Key in keyof T]: InferTypeTerms<T[Key]> } 999 > 1000 1001 export type InferTypeVariables<T, U = T> = T extends Scalar ? 1002 Variable<U extends Scalar ? U : never> 1003 : unknown extends T ? Variable<any> 1004 : { this: Term<Entity> } & { 1005 [Key in keyof T]: InferTypeVariables<T[Key]> 1006 } 1007 1008 export interface RuleDescriptor { 1009 [key: string]: ScalarConstructor | Type | Scalar 1010 } 1011 1012 export interface FactSchema extends RuleDescriptor { 1013 this: ObjectConstructor 1014 } 1015 1016 export type InferSchemaAttributes<Schema> = { 1017 [Key in keyof Schema]: Variable<InferDescriptorType<Schema[Key]>> 1018 } 1019 1020 export type InferSchemaTerms<T> = { 1021 [Key in keyof T]: Term<InferDescriptorType<T[Key]>> 1022 } 1023 1024 export type InferFact<Schema extends RuleDescriptor> = { 1025 [Key in keyof Schema]: InferDescriptorType<Schema[Key]> 1026 } 1027 1028 export type InferRuleAssert<T extends RuleDescriptor> = { 1029 [Key in keyof T as T[Key] extends Scalar ? never : Key]: T[Key] extends ( 1030 Scalar 1031 ) ? 1032 undefined 1033 : InferDescriptorType<T[Key]> 1034 } 1035 1036 export type ScalarTerms<T extends Scalar> = Term<T> | { this: Term<T> } 1037 1038 export interface MatchView<Model = unknown> 1039 extends Iterable<Recur | Conjunct> {} 1040 1041 export interface QueryView<Model> extends Iterable<Conjunct> { 1042 select(source: { from: Querier }): Invocation<Model[], Error> 1043 } 1044 1045 export type EntityModel<T extends {} = {}> = { 1046 this: Entity 1047 } & T 1048 1049 export type FactModel = { 1050 the?: The 1051 of?: EntityModel 1052 is?: Scalar | {} 1053 } 1054 1055 export interface RuleApplicationView<View> 1056 extends RuleApplication, 1057 MatchView<View> { 1058 select(source: { from: Querier }): Invocation<View[], Error> 1059 } 1060 1061 export type EntityView<Model> = Model & { 1062 this: Entity 1063 } 1064 1065 export type TermTree = { 1066 [Key: string]: Term | TermTree 1067 } 1068 1069 export type The = `${string}/${string}` 1070 1071 export interface FactCells { 1072 the: Variable<string> 1073 of: Variable<Entity> 1074 is: Variable<Scalar> 1075 } 1076 1077 export type Descriptor = null | boolean 1078 1079 interface TextVariable extends Variable<string> { 1080 like(pattern: Term<string>): Constraint 1081 toUpperCase(is: Term<string>): Constraint 1082 toLowerCase(is: Term<string>): Constraint 1083 } 1084 1085 export type InferFactTerms<T extends FactSchema> = { 1086 [Key in keyof Omit<T, 'this'>]: Term<InferDescriptorType<T[Key]>> 1087 } & { 1088 this?: Term<Entity> 1089 } 1090 1091 export type InferAssert<Schema extends FactSchema> = InferFact< 1092 Omit<Schema, 'this'> 1093 > & { this?: Entity } 1094 1095 export type InferClaimTerms<Schema extends FactSchema> = InferFactTerms<Schema> 1096 1097 export type InferAttributes<Schema> = { 1098 [Key in keyof Schema]: Variable<InferDescriptorType<Schema[Key]>> 1099 } 1100 1101 export interface Premise<The extends string, Schema extends FactSchema> { 1102 readonly the: The 1103 readonly attributes: InferAttributes<Schema & { this: ObjectDescriptor }> 1104 readonly schema: Schema 1105 } 1106 1107 export interface Conclusion< 1108 Fact, 1109 The extends string, 1110 Schema extends FactSchema, 1111 > { 1112 assert(fact: InferAssert<Schema>): Fact 1113 } 1114 1115 export interface Claim< 1116 Fact, 1117 The extends string, 1118 Schema extends FactSchema, 1119 Context extends RuleDescriptor, 1120 > extends Relation<Fact, The, Schema> { 1121 the: The 1122 attributes: InferSchemaAttributes<Schema> 1123 schema: Schema 1124 1125 /** 1126 * Defines temporary variables made available in the {@link when} / 1127 * {@link where} builder methods so they can be used inside the rule body. 1128 */ 1129 with<Extension extends Exclude<RuleDescriptor, Schema & Context>>( 1130 extension: Extension 1131 ): Claim<Fact, The, Schema, Context & Extension> 1132 1133 /** 1134 * Defines a rule that concludes fact corresponding to this premise whenever 1135 * all of the predicates returne by `derive` method are true. This is a 1136 * shortuct for {@link when} which is convinient in cases with a single 1137 * branch. 1138 */ 1139 where( 1140 derive: EveryBuilder<Schema & Context> 1141 ): Deduction<Fact, The, Schema, {}> 1142 1143 /** 1144 * Defines a rule that deduces this fact whenever any of the branches are true. 1145 * Takes a `build` function that will be given set of variables corresponding 1146 * to the fact members which must return object where keys represent disjuncts 1147 * and values are arrays representing conjuncts for those disjuncts. In other 1148 * works each member of the returned object represent OR branches where each 1149 * branch is an AND joined predicates by passed variables. 1150 */ 1151 when(derive: SomeBuilder<Schema & Context>): Deduction<Fact, The, Schema, {}> 1152 1153 map<View>(mapper: (fact: Fact) => View): Claim<View, The, Schema, Context> 1154 1155 aggregate<State, View>( 1156 compressor: Aggregator<View, Fact, State> 1157 ): Aggregation<View, Fact, The, Schema> 1158 } 1159 1160 export interface Aggregator<Output, Input, State> { 1161 open(): State 1162 merge(state: State, input: Input): State 1163 close(state: State): Output 1164 } 1165 1166 export interface Aggregation<View, Fact, The, Schema extends FactSchema> { 1167 /** 1168 * Creates a predicate that matches this premise. This is just like 1169 * {@link match} except it requires passing all members explicitly, 1170 * this allows type checker to ensure that no members are left out by 1171 * accident. 1172 */ 1173 (terms?: InferFactTerms<Schema>): Aggregate<View> 1174 1175 /** 1176 * Creates predicate that matches this premise. It may be passed terms for 1177 * the subset of the fact members. Omitted members are treated as `_` meaning 1178 * any value would satisfy them. 1179 */ 1180 match(terms?: Partial<InferFactTerms<Schema>>): Aggregate<View> 1181 1182 /** 1183 * Creates negation (anti-join) that will omit all the facts that match 1184 * the premise with the given terms. 1185 */ 1186 not(terms: Partial<InferSchemaTerms<Schema>>): NegationPredicate 1187 1188 /** 1189 * Creates an assertion for this the fact denoted by this premise, which can 1190 * be transacted in the DB. 1191 */ 1192 assert(fact: InferAssert<Schema>): Fact 1193 1194 the: The 1195 schema: Schema 1196 } 1197 1198 export interface Aggregate<View> extends Iterable<Recur | Conjunct> { 1199 query(source: { from: Querier }): Invocation<View, Error> 1200 } 1201 1202 export interface NegationPredicate extends Iterable<Negation> {} 1203 1204 /** 1205 * 1206 */ 1207 export interface Predicate<Fact, The extends string, Schema extends FactSchema> 1208 extends Iterable<Recur | Conjunct> { 1209 query(source: { from: Querier }): Invocation<Fact[], Error> 1210 } 1211 1212 export interface Assertion extends Iterable<{ assert: Fact }> {} 1213 1214 export type FactView< 1215 The extends string, 1216 Schema extends FactSchema, 1217 > = InferFact<Schema> & { 1218 the: The 1219 toJSON(): InferFact<Schema> & { the: The } 1220 } & Assertion & 1221 Retractable 1222 1223 export interface Retractable { 1224 retract(): Iterable<{ retract: Fact }> 1225 } 1226 1227 export interface Relation<Fact, The extends string, Schema extends FactSchema> { 1228 /** 1229 * Creates a predicate that matches this premise. This is just like 1230 * {@link match} except it requires passing all members explicitly, 1231 * this allows type checker to ensure that no members are left out by 1232 * accident. 1233 */ 1234 (terms?: InferFactTerms<Schema>): Predicate<Fact, The, Schema> 1235 1236 /** 1237 * Creates predicate that matches this premise. It may be passed terms for 1238 * the subset of the fact members. Omitted members are treated as `_` meaning 1239 * any value would satisfy them. 1240 */ 1241 match(terms?: Partial<InferFactTerms<Schema>>): Predicate<Fact, The, Schema> 1242 1243 /** 1244 * Creates negation (anti-join) that will omit all the facts that match 1245 * the premise with the given terms. 1246 */ 1247 not(terms: Partial<InferSchemaTerms<Schema>>): NegationPredicate 1248 1249 /** 1250 * Creates an assertion for this the fact denoted by this premise, which can 1251 * be transacted in the DB. 1252 */ 1253 assert(fact: InferAssert<Schema>): Fact 1254 } 1255 1256 export interface Deduction< 1257 Fact, 1258 The extends string, 1259 Schema extends FactSchema, 1260 Context extends RuleDescriptor, 1261 > extends Claim<Fact, The, Schema, Context> { 1262 inductive: Relation<Fact, The, Schema> 1263 /** 1264 * Creates an assertion for this the fact denoted by this premise, which can 1265 * be transacted in the DB. 1266 */ 1267 claim(fact: InferFactTerms<Schema>): Iterable<Conjunct> 1268 1269 select<Terms extends Selector>( 1270 derive: ProjectionBuilder<Schema & Context, Terms> 1271 ): Projection<Schema, Terms> 1272 1273 map<View>(mapper: (fact: Fact) => View): Deduction<View, The, Schema, Context> 1274 } 1275 1276 export interface Projection<Schema extends FactSchema, Terms extends Selector> { 1277 (terms?: InferSchemaTerms<Schema>): SelectionPredicate<Terms> 1278 match(terms?: Partial<InferSchemaTerms<Schema>>): SelectionPredicate<Terms> 1279 } 1280 1281 export interface SelectionPredicate<Terms extends Selector> 1282 extends Iterable<Recur | Conjunct> { 1283 query(source: { from: Querier }): Invocation<InferBindings<Terms>[], Error> 1284 }