@bjornpagen/bumbledb 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,6 +100,8 @@ type RowOf<T> = InferredOf<T> extends { readonly row: infer R } ? R : never
100
100
 
101
101
  type HeadShape = Readonly<Record<string, ClassedField>> | undefined
102
102
 
103
+ type HeadOf<T> = InferredOf<T> extends { readonly head: infer H extends HeadShape } ? H : HeadShape
104
+
103
105
  interface RuleValue<Row, P extends ParamsRecord, Head extends HeadShape = undefined> {
104
106
  readonly rule: RuleData
105
107
  readonly [inferred]?: { readonly row: Row; readonly params: P; readonly head: Head }
@@ -225,7 +227,12 @@ interface QueryRuleChain<
225
227
  bindings: B & CheckInteriorBindings<B>
226
228
  ): QueryRuleChain<Rels, P, Classes>
227
229
 
228
- find<const F extends FindShape>(entries: F & CheckFind<F>): RuleValue<RowOfFind<F>, P>
230
+ /** A record of variables is already a valid projection, including v(rel)
231
+ * for a generic relation. Aggregate judgments remain on the general form. */
232
+ find<const F extends Readonly<Record<string, AnyVar>>>(
233
+ entries: F
234
+ ): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
235
+ find<const F extends FindShape>(entries: F & CheckFind<F>): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
229
236
  }
230
237
 
231
238
  interface InteriorRuleScope<Rels extends SchemaRelations, Classes extends SchemaClasses = SchemaClasses>
@@ -292,6 +299,9 @@ interface InteriorRuleChain<
292
299
  * Nonrecursive derived stages emit aggregate/computed outputs too
293
300
  * (C05): only the RECURSIVE head stays projection-only.
294
301
  */
302
+ find<const F extends Readonly<Record<string, AnyVar>>>(
303
+ entries: F
304
+ ): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
295
305
  find<const F extends FindShape>(entries: F & CheckFind<F>): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
296
306
  }
297
307
 
@@ -355,6 +365,9 @@ interface RecRuleChain<
355
365
  name: string,
356
366
  bindings: B & CheckInteriorBindings<B>
357
367
  ): RecRuleChain<Rels, P, Classes>
368
+ find<const F extends Readonly<Record<string, AnyVar>>>(
369
+ entries: F
370
+ ): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
358
371
  find<const F extends FindShape>(entries: F & CheckRecFind<F>): RuleValue<RowOfFind<F>, P, HeadRecordOf<Classes, F>>
359
372
  }
360
373
 
@@ -388,22 +401,23 @@ interface Query<
388
401
  Rels extends SchemaRelations,
389
402
  Row,
390
403
  Params extends ParamsRecord,
391
- Classes extends SchemaClasses = SchemaClasses
404
+ Classes extends SchemaClasses = SchemaClasses,
405
+ Head extends HeadShape = HeadShape
392
406
  > {
393
407
  readonly schema: Schema<Rels, Classes>
394
408
  readonly data: QueryData
395
409
 
396
410
  rule<RV extends AnyRuleValue>(
397
411
  build: (r: QueryRuleScope<Rels, Classes>) => RV
398
- ): Query<Rels, Row | RowOf<RV>, Flatten<Params & ParamsOf<RV>>, Classes>
412
+ ): Query<Rels, Row | RowOf<RV>, Flatten<Params & ParamsOf<RV>>, Classes, Head | HeadOf<RV>>
399
413
 
400
414
  /** A diagnostic name for composition/tracing — never a schema relation. */
401
- named(label: string): Query<Rels, Row, Params, Classes>
415
+ named(label: string): Query<Rels, Row, Params, Classes, Head>
402
416
 
403
417
  interior(name: string, ...builds: never[]): never
404
418
 
405
419
  reach(name: string, arms: never): never
406
- readonly [inferred]?: { readonly row: Row; readonly params: Params }
420
+ readonly [inferred]?: { readonly row: Row; readonly params: Params; readonly head: Head }
407
421
  }
408
422
 
409
423
  interface AnyQuery {
@@ -422,7 +436,7 @@ type QueryStart<
422
436
  > = {
423
437
  rule<RV extends AnyRuleValue>(
424
438
  build: (r: QueryRuleScope<Rels, Classes>) => RV
425
- ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes>
439
+ ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>>
426
440
  interior<const Builds extends readonly InteriorBuild<Rels, Classes>[]>(
427
441
  name: string,
428
442
  ...builds: Builds
@@ -440,7 +454,7 @@ type QueryReachStart<
440
454
  > = {
441
455
  rule<RV extends AnyRuleValue>(
442
456
  build: (r: QueryRuleScope<Rels, Classes>) => RV
443
- ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes>
457
+ ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>>
444
458
  }
445
459
 
446
460
  const termOps: TermOps = Object.freeze({
@@ -1774,13 +1788,19 @@ function makeRawQuery(
1774
1788
  return value
1775
1789
  }
1776
1790
 
1777
- function makeQuery<Rels extends SchemaRelations, Row, P extends ParamsRecord, Classes extends SchemaClasses>(
1791
+ function makeQuery<
1792
+ Rels extends SchemaRelations,
1793
+ Row,
1794
+ P extends ParamsRecord,
1795
+ Classes extends SchemaClasses,
1796
+ Head extends HeadShape
1797
+ >(
1778
1798
  theory: Schema<Rels, Classes>,
1779
1799
  interiors: readonly InteriorData[],
1780
1800
  rec: RecData | undefined,
1781
1801
  rules: readonly RuleData[]
1782
- ): Query<Rels, Row, P, Classes> {
1783
- return makeRawQuery(theory, interiors, rec, rules) as unknown as Query<Rels, Row, P, Classes>
1802
+ ): Query<Rels, Row, P, Classes, Head> {
1803
+ return makeRawQuery(theory, interiors, rec, rules) as unknown as Query<Rels, Row, P, Classes, Head>
1784
1804
  }
1785
1805
 
1786
1806
  function collectInterior<Rels extends SchemaRelations, Classes extends SchemaClasses>(
@@ -1899,9 +1919,11 @@ function makeQueryStart<Rels extends SchemaRelations, Classes extends SchemaClas
1899
1919
  },
1900
1920
  rule<RV extends AnyRuleValue>(
1901
1921
  build: (r: QueryRuleScope<Rels, Classes>) => RV
1902
- ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes> {
1922
+ ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>> {
1903
1923
  const built = build(makeQueryRuleScope<Rels, Classes>(theory, env))
1904
- return makeQuery<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes>(theory, interiors, undefined, [built.rule])
1924
+ return makeQuery<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>>(theory, interiors, undefined, [
1925
+ built.rule
1926
+ ])
1905
1927
  }
1906
1928
  }
1907
1929
  Object.freeze(start)
@@ -1917,9 +1939,11 @@ function makeQueryReachStart<Rels extends SchemaRelations, Classes extends Schem
1917
1939
  const start = {
1918
1940
  rule<RV extends AnyRuleValue>(
1919
1941
  build: (r: QueryRuleScope<Rels, Classes>) => RV
1920
- ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes> {
1942
+ ): Query<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>> {
1921
1943
  const built = build(makeQueryRuleScope<Rels, Classes>(theory, env))
1922
- return makeQuery<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes>(theory, interiors, rec, [built.rule])
1944
+ return makeQuery<Rels, RowOf<RV>, Flatten<P & ParamsOf<RV>>, Classes, HeadOf<RV>>(theory, interiors, rec, [
1945
+ built.rule
1946
+ ])
1923
1947
  }
1924
1948
  }
1925
1949
  Object.freeze(start)
@@ -122,9 +122,23 @@ function isImportedSource(value: unknown): value is ImportedSource {
122
122
 
123
123
  type RowOfImport<Q> = InferredOf<Q> extends { readonly row: infer R } ? R : never
124
124
 
125
+ type HeadOfImport<Q> = InferredOf<Q> extends { readonly head: infer H } ? H : never
126
+
127
+ /** Named imported slot so downstream declarations need not spell its private marker. */
128
+ interface ImportedFieldVar<S extends ClassedField, K extends string> extends Var<S["field"], string, K> {
129
+ readonly [inferred]?: { readonly slot: S }
130
+ }
131
+
132
+ // Retain the same descriptor and carrier class as the runtime import facade.
133
+ // A host bigint alone cannot distinguish i64 from u64 or a closed identifier.
134
+ type ImportedVar<Q, K extends string> =
135
+ HeadOfImport<Q> extends Readonly<Record<K, infer S extends ClassedField>>
136
+ ? ImportedFieldVar<S, K>
137
+ : Var<AnyField, string, K>
138
+
125
139
  type ImportVars<Q> = [RowOfImport<Q>] extends [never]
126
140
  ? Readonly<Record<string, Var<AnyField, string, string>>>
127
- : { readonly [K in keyof RowOfImport<Q> & string]: Var<AnyField, string, K> }
141
+ : { readonly [K in keyof RowOfImport<Q> & string]: ImportedVar<Q, K> }
128
142
 
129
143
  interface ImportFacade {
130
144
  /** The pseudo-owner every import var carries (structurally an owner). */
@@ -241,10 +255,11 @@ type MintClassOf<Classes extends SchemaClasses, V> =
241
255
  ? ClassLookup<ClassRecordOf<Classes, RN>, K>
242
256
  : never
243
257
 
244
- type MintSlotOf<Classes extends SchemaClasses, V extends AnyVar> = {
245
- readonly field: V["field"]
246
- readonly class: MintClassOf<Classes, V>
247
- }
258
+ type MintSlotOf<Classes extends SchemaClasses, V extends AnyVar> = [InferredOf<V>] extends [never]
259
+ ? { readonly field: V["field"]; readonly class: MintClassOf<Classes, V> }
260
+ : InferredOf<V> extends { readonly slot: infer S extends ClassedField }
261
+ ? S
262
+ : { readonly field: V["field"]; readonly class: MintClassOf<Classes, V> }
248
263
 
249
264
  type ParamsRecord = Readonly<Record<string, unknown>>
250
265
 
@@ -257,15 +272,8 @@ type UnionToIntersection<U> = (U extends unknown ? (member: U) => void : never)
257
272
  type ShapeOf<U> = [U] extends [never] ? Record<never, never> : Flatten<UnionToIntersection<U>>
258
273
 
259
274
  /**
260
- * A slot's identity for the positive-join judgment: the field's structural
261
- * signature ({@link SignatureOf} the ONE interpreter, shared with the
262
- * face pairing wall) plus the slot's law class.
263
- */
264
- type SlotSignature<S extends ClassedField> = readonly [SignatureOf<S["field"]>, S["class"]]
265
-
266
- /**
267
- * A widened slot — a variable minted from an imported query template (its
268
- * facade columns carry `AnyField`) or fully generic code — cannot be judged
275
+ * A widened slot an explicitly erased query template or fully generic
276
+ * code with no retained descriptor cannot be judged
269
277
  * at the type tier. The degradation law applies: best effort degrades to
270
278
  * SILENT, never to a wrong refusal; the runtime join judgment (real
271
279
  * descriptors off the imported head's slots) stays authoritative.
@@ -273,7 +281,15 @@ type SlotSignature<S extends ClassedField> = readonly [SignatureOf<S["field"]>,
273
281
  type WidenedSlot<S extends ClassedField> = [AnyField] extends [S["field"]] ? true : false
274
282
 
275
283
  type JoinOk<A extends ClassedField, B extends ClassedField> =
276
- WidenedSlot<A> extends true ? true : WidenedSlot<B> extends true ? true : Same<SlotSignature<A>, SlotSignature<B>>
284
+ WidenedSlot<A> extends true
285
+ ? true
286
+ : WidenedSlot<B> extends true
287
+ ? true
288
+ : Same<SignatureOf<A["field"]>, SignatureOf<B["field"]>> extends true
289
+ ? string extends A["class"] | B["class"]
290
+ ? true
291
+ : Same<A["class"], B["class"]>
292
+ : false
277
293
 
278
294
  type U64Wire<F extends AnyField> = F extends { readonly kind: "u64" }
279
295
  ? F extends { readonly closed: unknown }
@@ -390,6 +406,7 @@ export type {
390
406
  ClassedField,
391
407
  ExactVars,
392
408
  Flatten,
409
+ ImportedFieldVar,
393
410
  ImportedSource,
394
411
  ImportVars,
395
412
  InferredOf,
package/src/shape.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Query } from "#query/lower.ts"
2
- import type { ParamsRecord } from "#query/scope.ts"
2
+ import type { inferred, ParamsRecord } from "#query/scope.ts"
3
3
  /**
4
4
  * Shared derived types: `S` is a
5
5
  * declared core schema value's type, `Rel<S>` its ordinary (writable)
@@ -24,7 +24,13 @@ type Key<K extends KeyStatement<AnyRelation, readonly string[]>> = Pick<
24
24
  Extract<K["projection"][number], keyof Fact<K["owner"]>>
25
25
  >
26
26
 
27
- /** Immutable typed query template. */
28
- type QueryTemplate<S extends AnySchema, P extends ParamsRecord, A> = Query<S["relations"], A, P>
27
+ /** The immutable executable view of a query. Readers consume its schema/data
28
+ * and inferred result/parameters, not the author's rule-building methods.
29
+ * Runtime schema identity remains authoritative for dynamically built schemas.
30
+ */
31
+ type QueryTemplate<S extends AnySchema, P extends ParamsRecord, A> = Pick<
32
+ Query<S["relations"], A, P>,
33
+ "schema" | "data" | typeof inferred
34
+ >
29
35
 
30
36
  export type { Key, QueryTemplate, Rel }