@confect/core 10.0.0-next.21 → 10.0.0-next.23
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.
- package/CHANGELOG.md +168 -81
- package/dist/FunctionProvenance.d.ts +34 -26
- package/dist/FunctionProvenance.d.ts.map +1 -1
- package/dist/FunctionProvenance.js +14 -13
- package/dist/FunctionProvenance.js.map +1 -1
- package/dist/FunctionSpec.d.ts +15 -9
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +12 -6
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/GroupPath.d.ts +5 -6
- package/dist/GroupPath.d.ts.map +1 -1
- package/dist/GroupPath.js.map +1 -1
- package/dist/GroupSpec.d.ts +10 -3
- package/dist/GroupSpec.d.ts.map +1 -1
- package/dist/GroupSpec.js +33 -19
- package/dist/GroupSpec.js.map +1 -1
- package/dist/Identifier.d.ts +6 -5
- package/dist/Identifier.d.ts.map +1 -1
- package/dist/Identifier.js +6 -5
- package/dist/Identifier.js.map +1 -1
- package/dist/Lazy.d.ts +11 -13
- package/dist/Lazy.d.ts.map +1 -1
- package/dist/Lazy.js +11 -13
- package/dist/Lazy.js.map +1 -1
- package/dist/MiddlewareAttachment.d.ts +171 -0
- package/dist/MiddlewareAttachment.d.ts.map +1 -0
- package/dist/MiddlewareAttachment.js +48 -0
- package/dist/MiddlewareAttachment.js.map +1 -0
- package/dist/MiddlewareSpec.d.ts +59 -45
- package/dist/MiddlewareSpec.d.ts.map +1 -1
- package/dist/MiddlewareSpec.js +9 -4
- package/dist/MiddlewareSpec.js.map +1 -1
- package/dist/PaginationError.d.ts +9 -3
- package/dist/PaginationError.d.ts.map +1 -1
- package/dist/PaginationError.js +9 -3
- package/dist/PaginationError.js.map +1 -1
- package/dist/PaginationOptions.d.ts +3 -3
- package/dist/PaginationOptions.js +3 -3
- package/dist/PaginationOptions.js.map +1 -1
- package/dist/Ref.d.ts +42 -35
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +32 -30
- package/dist/Ref.js.map +1 -1
- package/dist/Refs.d.ts +1 -1
- package/dist/Refs.d.ts.map +1 -1
- package/dist/Refs.js +3 -2
- package/dist/Refs.js.map +1 -1
- package/dist/SchemaToValidator.d.ts.map +1 -1
- package/dist/SchemaToValidator.js +4 -2
- package/dist/SchemaToValidator.js.map +1 -1
- package/dist/Spec.d.ts +15 -12
- package/dist/Spec.d.ts.map +1 -1
- package/dist/Spec.js +13 -8
- package/dist/Spec.js.map +1 -1
- package/dist/SystemFields.d.ts +15 -14
- package/dist/SystemFields.d.ts.map +1 -1
- package/dist/SystemFields.js +11 -10
- package/dist/SystemFields.js.map +1 -1
- package/dist/Table.d.ts +1 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/package.json +8 -7
- package/src/FunctionProvenance.ts +35 -27
- package/src/FunctionSpec.ts +33 -15
- package/src/GroupPath.ts +5 -6
- package/src/GroupSpec.ts +83 -31
- package/src/Identifier.ts +6 -5
- package/src/Lazy.ts +11 -13
- package/src/MiddlewareAttachment.ts +106 -0
- package/src/MiddlewareSpec.ts +79 -43
- package/src/PaginationError.ts +9 -3
- package/src/PaginationOptions.ts +3 -3
- package/src/Ref.ts +76 -65
- package/src/Refs.ts +3 -3
- package/src/SchemaToValidator.ts +53 -44
- package/src/Spec.ts +50 -39
- package/src/SystemFields.ts +18 -17
- package/src/Table.ts +3 -2
- package/src/index.ts +1 -0
package/src/Ref.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type * as MiddlewareAttachment from "./MiddlewareAttachment";
|
|
1
2
|
import type {
|
|
2
3
|
DefaultFunctionArgs,
|
|
3
4
|
FunctionReference as ConvexFunctionReference,
|
|
@@ -35,8 +36,8 @@ export interface Base<
|
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* A reference to a single Convex function, as callers see it: the wire name
|
|
38
|
-
* plus the data needed to encode args, decode returns, and decode typed
|
|
39
|
-
*
|
|
39
|
+
* plus the data needed to encode args, decode returns, and decode typed errors.
|
|
40
|
+
* A ref is one of two shapes, keyed by the spec's provenance.
|
|
40
41
|
*/
|
|
41
42
|
export type Ref<
|
|
42
43
|
RuntimeAndFunctionType_ extends RuntimeAndFunctionType.RuntimeAndFunctionType,
|
|
@@ -80,8 +81,8 @@ export type ConfectRef<
|
|
|
80
81
|
/**
|
|
81
82
|
* Internal form used while mapping a spec to a ref. Supplying the already
|
|
82
83
|
* derived value types avoids repeatedly expanding `Schema.Struct` for every
|
|
83
|
-
* leaf in a generated ref tree; the public `ConfectRef` alias still derives
|
|
84
|
-
*
|
|
84
|
+
* leaf in a generated ref tree; the public `ConfectRef` alias still derives the
|
|
85
|
+
* same values from its fields and schemas.
|
|
85
86
|
*/
|
|
86
87
|
interface ConfectRefWithTypes<
|
|
87
88
|
RuntimeAndFunctionType_ extends RuntimeAndFunctionType.RuntimeAndFunctionType,
|
|
@@ -102,6 +103,7 @@ interface ConfectRefWithTypes<
|
|
|
102
103
|
readonly returns: Schema.Codec<any, any>;
|
|
103
104
|
readonly kind: FunctionProvenance.ConfectKind;
|
|
104
105
|
readonly middlewareSpecs: ReadonlyArray<MiddlewareSpec.AnyMiddlewareSpec>;
|
|
106
|
+
readonly middlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>;
|
|
105
107
|
readonly error?: Schema.Codec<any, any>;
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -123,7 +125,9 @@ export interface ConvexRef<
|
|
|
123
125
|
|
|
124
126
|
export type Any = Ref<any, any, any, any, any>;
|
|
125
127
|
|
|
126
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Erased Confect-provenance ref used by provenance-specific APIs.
|
|
130
|
+
*/
|
|
127
131
|
export type AnyConfect = Extract<Any, { readonly _tag: "Confect" }>;
|
|
128
132
|
|
|
129
133
|
export type AnyInternal = Ref<any, "internal", any, any, any>;
|
|
@@ -226,7 +230,9 @@ export type Args<Ref_> = Ref_ extends { readonly "~Args": infer Args_ }
|
|
|
226
230
|
? Args_
|
|
227
231
|
: never;
|
|
228
232
|
|
|
229
|
-
/**
|
|
233
|
+
/**
|
|
234
|
+
* The field map captured by a Confect-provenance ref.
|
|
235
|
+
*/
|
|
230
236
|
export type ArgsFields<Ref_> = Ref_ extends {
|
|
231
237
|
readonly _tag: "Confect";
|
|
232
238
|
readonly args: {
|
|
@@ -236,7 +242,9 @@ export type ArgsFields<Ref_> = Ref_ extends {
|
|
|
236
242
|
? ArgsFields_
|
|
237
243
|
: never;
|
|
238
244
|
|
|
239
|
-
/**
|
|
245
|
+
/**
|
|
246
|
+
* The assembled args schema carried by a Confect-provenance ref.
|
|
247
|
+
*/
|
|
240
248
|
export type ArgsSchema<Ref_> = Ref_ extends {
|
|
241
249
|
readonly _tag: "Confect";
|
|
242
250
|
readonly args: infer ArgsSchema_ extends FunctionProvenance.AnyArgsSchema;
|
|
@@ -322,7 +330,7 @@ export const make = <FunctionSpec_ extends FunctionSpec.AnyWithProps>(
|
|
|
322
330
|
*/
|
|
323
331
|
convexFunctionNamespace: string,
|
|
324
332
|
functionSpec: FunctionSpec_,
|
|
325
|
-
|
|
333
|
+
groupMiddlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment> = [],
|
|
326
334
|
): FromFunctionSpec<FunctionSpec_> => {
|
|
327
335
|
const convexFunctionName = `${convexFunctionNamespace}:${functionSpec.name}`;
|
|
328
336
|
|
|
@@ -340,10 +348,13 @@ export const make = <FunctionSpec_ extends FunctionSpec.AnyWithProps>(
|
|
|
340
348
|
_tag: "Confect" as const,
|
|
341
349
|
convexFunctionName,
|
|
342
350
|
kind: provenance.kind,
|
|
343
|
-
|
|
344
|
-
...
|
|
345
|
-
...functionSpec.
|
|
351
|
+
middlewareAttachments: [
|
|
352
|
+
...groupMiddlewareAttachments,
|
|
353
|
+
...functionSpec.middlewareAttachments,
|
|
346
354
|
],
|
|
355
|
+
get middlewareSpecs() {
|
|
356
|
+
return this.middlewareAttachments.map(({ spec }) => spec);
|
|
357
|
+
},
|
|
347
358
|
};
|
|
348
359
|
|
|
349
360
|
Lazy.defineProperty(ref, "args", () => provenance.args);
|
|
@@ -476,11 +487,11 @@ export const isConvexError = (error: unknown): error is ConvexError<Value> =>
|
|
|
476
487
|
/**
|
|
477
488
|
* Build a callback-style handler that decodes the ref's typed error from a
|
|
478
489
|
* caught `ConvexError`, or else forwards the value to `mapUnknownError`. The
|
|
479
|
-
* fallback is also invoked when the input
|
|
480
|
-
* doesn't declare a typed-error schema—by definition such a value falls
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
490
|
+
* fallback is also invoked when the input _is_ a `ConvexError` but the ref
|
|
491
|
+
* doesn't declare a typed-error schema—by definition such a value falls outside
|
|
492
|
+
* the ref's error contract. Useful when adapting non-Effect APIs (e.g. emitter
|
|
493
|
+
* callbacks for streamed subscriptions) to the same error semantics that
|
|
494
|
+
* `runWithCodec` provides.
|
|
484
495
|
*/
|
|
485
496
|
export const decodeErrorOrElse =
|
|
486
497
|
<Ref_ extends Any, E>(ref: Ref_, mapUnknownError: (error: unknown) => E) =>
|
|
@@ -514,13 +525,13 @@ const errorSchemaOf = (ref: Any): Option.Option<Schema.Codec<any, any>> =>
|
|
|
514
525
|
);
|
|
515
526
|
|
|
516
527
|
/**
|
|
517
|
-
* Decode `encodedError` against the ref's error schema
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
528
|
+
* Decode `encodedError` against the ref's error schema—the function's declared
|
|
529
|
+
* `error` schema unioned with its covering middlewares' error schemas. Returns
|
|
530
|
+
* `None` if the ref declares no typed error at all (Confect ref without an
|
|
531
|
+
* `error` schema and without failing middleware, or a Convex-provenance ref)—by
|
|
532
|
+
* definition there's nothing to decode the value into, and the caller is
|
|
533
|
+
* responsible for deciding what to do (typically: surface the original value as
|
|
534
|
+
* a defect).
|
|
524
535
|
*/
|
|
525
536
|
export const decodeError = <Ref_ extends Any>(
|
|
526
537
|
ref: Ref_,
|
|
@@ -529,26 +540,24 @@ export const decodeError = <Ref_ extends Any>(
|
|
|
529
540
|
Option.match(errorSchemaOf(ref), {
|
|
530
541
|
onNone: () => Effect.succeed(Option.none<Error<Ref_>>()),
|
|
531
542
|
onSome: (schema) =>
|
|
532
|
-
Effect.
|
|
543
|
+
Effect.asSome(
|
|
533
544
|
Schema.decodeUnknownEffect(schema)(encodedError),
|
|
534
|
-
Option.some,
|
|
535
545
|
) as Effect.Effect<Option.Option<Error<Ref_>>, Schema.SchemaError>,
|
|
536
546
|
});
|
|
537
547
|
|
|
538
548
|
/**
|
|
539
549
|
* Synchronous counterpart to `decodeError`. Returns `None` when the value is
|
|
540
|
-
* not this ref's typed error
|
|
541
|
-
*
|
|
550
|
+
* not this ref's typed error—either because the ref declares no `error` schema,
|
|
551
|
+
* or because `encodedError` doesn't match the one it declares.
|
|
542
552
|
*
|
|
543
553
|
* The second case is reachable in normal operation: Convex raises its own
|
|
544
|
-
* `ConvexError`s (an `InvalidCursor` pagination error, for instance), and
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
* doesn't.
|
|
554
|
+
* `ConvexError`s (an `InvalidCursor` pagination error, for instance), and those
|
|
555
|
+
* never match a user-declared error schema. Callers pair this with a fallback
|
|
556
|
+
* that surfaces the original error, so failing to decode must not throw—a
|
|
557
|
+
* `ParseError` here would replace the real error with an opaque one and lose
|
|
558
|
+
* the only useful diagnostic. Hence the `Option` suffix rather than `Sync`,
|
|
559
|
+
* matching `Schema.decodeUnknownOption`: the sibling `*Sync` helpers in this
|
|
560
|
+
* module all throw on a parse failure, and this one deliberately doesn't.
|
|
552
561
|
*/
|
|
553
562
|
export const decodeErrorOption = <Ref_ extends Any>(
|
|
554
563
|
ref: Ref_,
|
|
@@ -585,11 +594,11 @@ const paginatedKind = (ref: AnyConfect): FunctionProvenance.Paginated =>
|
|
|
585
594
|
);
|
|
586
595
|
|
|
587
596
|
/**
|
|
588
|
-
* Encode the args of a paginated query ref via its user-args
|
|
589
|
-
*
|
|
597
|
+
* Encode the args of a paginated query ref via its user-args
|
|
598
|
+
* schema—`paginationOpts` is excluded, since the pagination protocol fields are
|
|
590
599
|
* managed by the client (e.g. `usePaginatedQuery` from `convex/react`), not by
|
|
591
|
-
* the caller. Requires a ref built with `FunctionSpec.publicPaginatedQuery`
|
|
592
|
-
*
|
|
600
|
+
* the caller. Requires a ref built with `FunctionSpec.publicPaginatedQuery` (or
|
|
601
|
+
* `internalPaginatedQuery`).
|
|
593
602
|
*/
|
|
594
603
|
export const encodePaginatedQueryArgsSync = <
|
|
595
604
|
Ref_ extends AnyPublicPaginatedQuery,
|
|
@@ -630,7 +639,10 @@ export const decodePaginationPageSync = <Ref_ extends AnyPublicPaginatedQuery>(
|
|
|
630
639
|
* `mapUnknownError` to be turned into a typed `E`, or surfaced as a defect when
|
|
631
640
|
* no handler is provided.
|
|
632
641
|
*/
|
|
633
|
-
export const runWithCodec = <
|
|
642
|
+
export const runWithCodec = Effect.fnUntraced(function* <
|
|
643
|
+
Ref_ extends Any,
|
|
644
|
+
E = never,
|
|
645
|
+
>(
|
|
634
646
|
ref: Ref_,
|
|
635
647
|
args: Args<Ref_>,
|
|
636
648
|
call: (
|
|
@@ -638,29 +650,28 @@ export const runWithCodec = <Ref_ extends Any, E = never>(
|
|
|
638
650
|
encodedArgs: unknown,
|
|
639
651
|
) => PromiseLike<unknown>,
|
|
640
652
|
mapUnknownError?: (error: unknown) => E,
|
|
641
|
-
): Effect.
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
return decoded.value;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
if (mapUnknownError !== undefined) {
|
|
657
|
-
return mapUnknownError(error);
|
|
653
|
+
): Effect.fn.Return<Returns<Ref_>, E | Error<Ref_> | Schema.SchemaError> {
|
|
654
|
+
const functionReference = getFunctionReference(ref);
|
|
655
|
+
const invoke = (
|
|
656
|
+
encodedArgs: unknown,
|
|
657
|
+
): Effect.Effect<unknown, Error<Ref_> | E> =>
|
|
658
|
+
Effect.tryPromise({
|
|
659
|
+
try: () => Promise.resolve(call(functionReference, encodedArgs)),
|
|
660
|
+
catch: (error): Error<Ref_> | E => {
|
|
661
|
+
if (isConvexError(error)) {
|
|
662
|
+
const decoded = decodeErrorOption(ref, error.data);
|
|
663
|
+
if (Option.isSome(decoded)) {
|
|
664
|
+
return decoded.value;
|
|
658
665
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
666
|
+
}
|
|
667
|
+
if (mapUnknownError !== undefined) {
|
|
668
|
+
return mapUnknownError(error);
|
|
669
|
+
}
|
|
670
|
+
throw error;
|
|
671
|
+
},
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
const encodedArgs = yield* encodeArgs(ref, args);
|
|
675
|
+
const encodedReturns = yield* invoke(encodedArgs);
|
|
676
|
+
return yield* decodeReturns(ref, encodedReturns);
|
|
677
|
+
});
|
package/src/Refs.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type * as FunctionSpec from "./FunctionSpec";
|
|
|
6
6
|
import type * as GroupSpec from "./GroupSpec";
|
|
7
7
|
import type * as MiddlewareSpec from "./MiddlewareSpec";
|
|
8
8
|
import * as Ref from "./Ref";
|
|
9
|
-
import
|
|
9
|
+
import * as Spec from "./Spec";
|
|
10
10
|
|
|
11
11
|
export type Refs<
|
|
12
12
|
Spec_ extends Spec.AnyWithProps,
|
|
@@ -98,7 +98,7 @@ type Any =
|
|
|
98
98
|
export const make = <Spec_ extends Spec.AnyWithProps>(
|
|
99
99
|
spec: Spec_,
|
|
100
100
|
): FromSpec<Spec_> => {
|
|
101
|
-
const refs = makeHelper(
|
|
101
|
+
const refs = makeHelper(Spec.groups(spec));
|
|
102
102
|
return {
|
|
103
103
|
public: refs as Refs<Spec_, Ref.AnyPublic>,
|
|
104
104
|
internal: refs as Refs<Spec_, Ref.AnyInternal>,
|
|
@@ -126,7 +126,7 @@ const makeHelper = (
|
|
|
126
126
|
Ref.make(
|
|
127
127
|
currentConvexFunctionNamespace,
|
|
128
128
|
function_,
|
|
129
|
-
group.
|
|
129
|
+
group.middlewareAttachments,
|
|
130
130
|
),
|
|
131
131
|
),
|
|
132
132
|
(_subGroup, _function) => {
|
package/src/SchemaToValidator.ts
CHANGED
|
@@ -384,23 +384,27 @@ export const compileAst = (
|
|
|
384
384
|
const handleUnion = (
|
|
385
385
|
{ types }: SchemaAST.Union,
|
|
386
386
|
isOptionalPropertyOfTypeLiteral: boolean,
|
|
387
|
-
) =>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
387
|
+
) => handleUnionTypes(types, isOptionalPropertyOfTypeLiteral);
|
|
388
|
+
|
|
389
|
+
const handleUnionTypes = Effect.fnUntraced(function* (
|
|
390
|
+
types: SchemaAST.Union["types"],
|
|
391
|
+
isOptionalPropertyOfTypeLiteral: boolean,
|
|
392
|
+
) {
|
|
393
|
+
const members = isOptionalPropertyOfTypeLiteral
|
|
394
|
+
? Array.filter(types, Predicate.not(SchemaAST.isUndefined))
|
|
395
|
+
: types;
|
|
396
|
+
|
|
397
|
+
const [firstValidator, secondValidator, ...restValidators] =
|
|
398
|
+
yield* Effect.all(Array.map(members, (type) => compileAst(type)));
|
|
399
|
+
|
|
400
|
+
if (firstValidator === undefined) {
|
|
401
|
+
return yield* new EmptyUnionIsNotSupportedError();
|
|
402
|
+
} else if (secondValidator === undefined) {
|
|
403
|
+
return firstValidator;
|
|
404
|
+
} else {
|
|
405
|
+
return v.union(firstValidator, secondValidator, ...restValidators);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
404
408
|
|
|
405
409
|
const handleObjects = (objectsAst: SchemaAST.Objects) =>
|
|
406
410
|
pipe(
|
|
@@ -431,35 +435,40 @@ const handleObjects = (objectsAst: SchemaAST.Objects) =>
|
|
|
431
435
|
);
|
|
432
436
|
|
|
433
437
|
const handleArrays = ({ elements, rest }: SchemaAST.Arrays) =>
|
|
434
|
-
|
|
435
|
-
const [f, s, ...r] = elements;
|
|
438
|
+
handleArrayElements(elements, rest);
|
|
436
439
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
440
|
+
const handleArrayElements = Effect.fnUntraced(function* (
|
|
441
|
+
elements: SchemaAST.Arrays["elements"],
|
|
442
|
+
rest: SchemaAST.Arrays["rest"],
|
|
443
|
+
) {
|
|
444
|
+
const [f, s, ...r] = elements;
|
|
445
|
+
|
|
446
|
+
const elementToValidator = (element: SchemaAST.AST) =>
|
|
447
|
+
SchemaAST.isOptional(element)
|
|
448
|
+
? Effect.fail(new OptionalTupleElementsAreNotSupportedError())
|
|
449
|
+
: compileAst(element);
|
|
450
|
+
|
|
451
|
+
const arrayItemsValidator = yield* f === undefined
|
|
452
|
+
? pipe(
|
|
453
|
+
rest,
|
|
454
|
+
Array.head,
|
|
455
|
+
Option.match({
|
|
456
|
+
onNone: () => Effect.fail(new EmptyTupleIsNotSupportedError()),
|
|
457
|
+
onSome: (type) => compileAst(type),
|
|
458
|
+
}),
|
|
459
|
+
)
|
|
460
|
+
: s === undefined
|
|
461
|
+
? elementToValidator(f)
|
|
462
|
+
: Effect.gen(function* () {
|
|
463
|
+
const firstValidator = yield* elementToValidator(f);
|
|
464
|
+
const secondValidator = yield* elementToValidator(s);
|
|
465
|
+
const restValidators = yield* Effect.forEach(r, elementToValidator);
|
|
466
|
+
|
|
467
|
+
return v.union(firstValidator, secondValidator, ...restValidators);
|
|
468
|
+
});
|
|
441
469
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
rest,
|
|
445
|
-
Array.head,
|
|
446
|
-
Option.match({
|
|
447
|
-
onNone: () => Effect.fail(new EmptyTupleIsNotSupportedError()),
|
|
448
|
-
onSome: (type) => compileAst(type),
|
|
449
|
-
}),
|
|
450
|
-
)
|
|
451
|
-
: s === undefined
|
|
452
|
-
? elementToValidator(f)
|
|
453
|
-
: Effect.gen(function* () {
|
|
454
|
-
const firstValidator = yield* elementToValidator(f);
|
|
455
|
-
const secondValidator = yield* elementToValidator(s);
|
|
456
|
-
const restValidators = yield* Effect.forEach(r, elementToValidator);
|
|
457
|
-
|
|
458
|
-
return v.union(firstValidator, secondValidator, ...restValidators);
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
return v.array(arrayItemsValidator);
|
|
462
|
-
});
|
|
470
|
+
return v.array(arrayItemsValidator);
|
|
471
|
+
});
|
|
463
472
|
|
|
464
473
|
const handlePropertySignatures = (objectsAst: SchemaAST.Objects) =>
|
|
465
474
|
pipe(
|
package/src/Spec.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Predicate from "effect/Predicate";
|
|
2
2
|
import * as Record from "effect/Record";
|
|
3
|
+
import * as Struct from "effect/Struct";
|
|
3
4
|
import * as GroupSpec from "./GroupSpec";
|
|
4
5
|
|
|
5
6
|
export const TypeId = "~@confect/core/Spec";
|
|
@@ -10,66 +11,76 @@ export const isSpec = (u: unknown): u is AnyWithProps =>
|
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* A Confect spec: a flat container of function groups. Groups may be of any
|
|
13
|
-
* runtime
|
|
14
|
+
* runtime—a group built with `GroupSpec.makeNode()` (a Node action group) sits
|
|
14
15
|
* alongside `GroupSpec.make()` groups in the same namespace. The runtime of a
|
|
15
16
|
* group lives on the group itself (`GroupSpec.runtime`) and on each function's
|
|
16
17
|
* `RuntimeAndFunctionType`; the spec does not carry a runtime of its own.
|
|
17
18
|
*/
|
|
18
|
-
export interface Spec<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Groups_,
|
|
23
|
-
GroupName
|
|
24
|
-
>;
|
|
25
|
-
};
|
|
26
|
-
readonly "~Groups": Groups_;
|
|
19
|
+
export interface Spec<
|
|
20
|
+
Groups_ extends Record.ReadonlyRecord<string, GroupSpec.AnyWithProps> = {},
|
|
21
|
+
> {
|
|
22
|
+
readonly [TypeId]: Readonly<Groups_>;
|
|
27
23
|
|
|
28
24
|
add<Group extends GroupSpec.AnyWithProps>(
|
|
29
25
|
group: Group,
|
|
30
|
-
): Spec<
|
|
26
|
+
): Spec<
|
|
27
|
+
Struct.Assign<Groups_, Record.ReadonlyRecord<GroupSpec.Name<Group>, Group>>
|
|
28
|
+
>;
|
|
31
29
|
|
|
32
30
|
addAt<const Name extends string, Group extends GroupSpec.AnyWithProps>(
|
|
33
31
|
name: Name,
|
|
34
32
|
group: Group,
|
|
35
|
-
): Spec<
|
|
33
|
+
): Spec<
|
|
34
|
+
Struct.Assign<
|
|
35
|
+
Groups_,
|
|
36
|
+
Record.ReadonlyRecord<Name, GroupSpec.NamedAt<Group, Name>>
|
|
37
|
+
>
|
|
38
|
+
>;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
export interface Any {
|
|
39
|
-
readonly [TypeId]:
|
|
42
|
+
readonly [TypeId]: unknown;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export interface AnyWithProps extends
|
|
45
|
+
export interface AnyWithProps extends Any {
|
|
46
|
+
readonly [TypeId]: Record.ReadonlyRecord<string, GroupSpec.AnyWithProps>;
|
|
47
|
+
}
|
|
43
48
|
|
|
44
|
-
export type Groups<Spec_ extends AnyWithProps> =
|
|
49
|
+
export type Groups<Spec_ extends AnyWithProps> =
|
|
50
|
+
Spec_[TypeId][keyof Spec_[TypeId]];
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
/**
|
|
53
|
+
* The group record stored by a spec, with its precise member types.
|
|
54
|
+
*/
|
|
55
|
+
export const groups = <Spec_ extends AnyWithProps>(
|
|
56
|
+
self: Spec_,
|
|
57
|
+
): Spec_[TypeId] => self[TypeId];
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
const makeRecord = <
|
|
60
|
+
Groups_ extends Record.ReadonlyRecord<string, GroupSpec.AnyWithProps>,
|
|
61
|
+
>(
|
|
62
|
+
record: Groups_,
|
|
63
|
+
): Spec<Groups_> => ({
|
|
64
|
+
[TypeId]: record,
|
|
65
|
+
add<Group extends GroupSpec.AnyWithProps>(group: Group) {
|
|
66
|
+
return makeRecord(
|
|
67
|
+
Struct.assign(
|
|
68
|
+
record,
|
|
69
|
+
Record.singleton<GroupSpec.Name<Group>, Group>(group.name, group),
|
|
70
|
+
),
|
|
71
|
+
);
|
|
53
72
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this: AnyWithProps,
|
|
57
|
-
name: string,
|
|
73
|
+
addAt<const Name extends string, Group extends GroupSpec.AnyWithProps>(
|
|
74
|
+
name: Name,
|
|
58
75
|
group: Group,
|
|
59
76
|
) {
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
return makeRecord(
|
|
78
|
+
Struct.assign(
|
|
79
|
+
record,
|
|
80
|
+
Record.singleton(name, GroupSpec.withName(name, group)),
|
|
81
|
+
),
|
|
82
|
+
);
|
|
63
83
|
},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const makeProto = <Groups_ extends GroupSpec.AnyWithProps>({
|
|
67
|
-
groups,
|
|
68
|
-
}: {
|
|
69
|
-
groups: Record.ReadonlyRecord<string, Groups_>;
|
|
70
|
-
}): Spec<Groups_> =>
|
|
71
|
-
Object.assign(Object.create(Proto), {
|
|
72
|
-
groups,
|
|
73
|
-
}) as Spec<Groups_>;
|
|
84
|
+
});
|
|
74
85
|
|
|
75
|
-
export const make = (): Spec =>
|
|
86
|
+
export const make = (): Spec => makeRecord({});
|
package/src/SystemFields.ts
CHANGED
|
@@ -13,7 +13,8 @@ import * as Struct from "effect/Struct";
|
|
|
13
13
|
import * as GenericId from "./GenericId";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Produces a schema for Convex system fields. In Confect, system fields include
|
|
16
|
+
* Produces a schema for Convex system fields. In Confect, system fields include
|
|
17
|
+
* `_id`.
|
|
17
18
|
*/
|
|
18
19
|
export const SystemFields = <TableName extends string>(tableName: TableName) =>
|
|
19
20
|
Schema.Struct({
|
|
@@ -93,8 +94,8 @@ const wrapTransformation = (
|
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
96
|
* Builds an AST walker that adds the given system-field property signatures to
|
|
96
|
-
* every object node of a schema's AST
|
|
97
|
-
* chain
|
|
97
|
+
* every object node of a schema's AST—including each step of its encoding
|
|
98
|
+
* chain—wrapping transformations so the fields survive them.
|
|
98
99
|
*/
|
|
99
100
|
const makeExtendAst = (
|
|
100
101
|
systemPropertySignatures: ReadonlyArray<SchemaAST.PropertySignature>,
|
|
@@ -113,7 +114,7 @@ const makeExtendAst = (
|
|
|
113
114
|
if (SchemaAST.isUnion(ast)) {
|
|
114
115
|
return new SchemaAST.Union(
|
|
115
116
|
Array.map(ast.types, extendAst),
|
|
116
|
-
ast.
|
|
117
|
+
ast.options,
|
|
117
118
|
ast.annotations,
|
|
118
119
|
ast.checks,
|
|
119
120
|
ast.encoding === undefined ? undefined : extendEncoding(ast.encoding),
|
|
@@ -154,11 +155,11 @@ const makeExtendAst = (
|
|
|
154
155
|
/**
|
|
155
156
|
* Extend a table schema with Convex system fields.
|
|
156
157
|
*
|
|
157
|
-
* A plain `Struct` gains the fields via `Schema.fieldsAssign` and a `Union`
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* `Schema.decodeTo`/`Schema.encodeKeys`, a branded struct, a suspended
|
|
161
|
-
* —
|
|
158
|
+
* A plain `Struct` gains the fields via `Schema.fieldsAssign` and a `Union` has
|
|
159
|
+
* them distributed across its members, preserving the schema's `Struct`/`Union`
|
|
160
|
+
* structure. Any other object-shaped schema—one built with
|
|
161
|
+
* `Schema.decodeTo`/`Schema.encodeKeys`, a branded struct, a suspended
|
|
162
|
+
* schema—is extended at the AST level: every object node in its encoding chain
|
|
162
163
|
* gains the system fields, and each transformation is wrapped so the fields
|
|
163
164
|
* bypass the user-defined getters. Schemas that do not resolve to an object
|
|
164
165
|
* shape at every step (such as `Schema.Class`, whose decoded values are class
|
|
@@ -219,9 +220,9 @@ export const extendWithSystemFields = <
|
|
|
219
220
|
};
|
|
220
221
|
|
|
221
222
|
/**
|
|
222
|
-
* Applies the system fields to a single struct, mirroring
|
|
223
|
-
* Any other (already-extended or opaque) schema falls
|
|
224
|
-
* the system-field document shape.
|
|
223
|
+
* Applies the system fields to a single struct, mirroring
|
|
224
|
+
* `Schema.fieldsAssign`. Any other (already-extended or opaque) schema falls
|
|
225
|
+
* back to a `Codec` carrying the system-field document shape.
|
|
225
226
|
*/
|
|
226
227
|
type ApplySystemFields<TableName extends string, S> =
|
|
227
228
|
S extends Schema.Struct<infer Fields extends Schema.Struct.Fields>
|
|
@@ -241,10 +242,10 @@ type ApplySystemFields<TableName extends string, S> =
|
|
|
241
242
|
* This mirrors the runtime {@link extendWithSystemFields}: a `Struct` gains the
|
|
242
243
|
* system fields directly (matching `Schema.fieldsAssign`), and a `Union` has
|
|
243
244
|
* them distributed across its members (matching
|
|
244
|
-
* `union.mapMembers(Tuple.map(Schema.fieldsAssign(...)))`). The
|
|
245
|
-
* structure is preserved rather than collapsed to a bare
|
|
246
|
-
* schema falls back to a `Codec` carrying the system-field
|
|
247
|
-
* matching the runtime's AST-level extension.
|
|
245
|
+
* `union.mapMembers(Tuple.map(Schema.fieldsAssign(...)))`). The
|
|
246
|
+
* `Struct`/`Union` structure is preserved rather than collapsed to a bare
|
|
247
|
+
* `Codec`; any other schema falls back to a `Codec` carrying the system-field
|
|
248
|
+
* document shape, matching the runtime's AST-level extension.
|
|
248
249
|
*/
|
|
249
250
|
export type ExtendWithSystemFields<
|
|
250
251
|
TableName extends string,
|
|
@@ -264,7 +265,7 @@ export type ExtendWithSystemFields<
|
|
|
264
265
|
|
|
265
266
|
/**
|
|
266
267
|
* The decoded/encoded document shape: a table's fields plus Convex's system
|
|
267
|
-
* fields. Deliberately a bare intersection (no `Expand`/`Simplify`)
|
|
268
|
+
* fields. Deliberately a bare intersection (no `Expand`/`Simplify`)—flattening
|
|
268
269
|
* it with a homomorphic mapped type collapses to `{ [x: string]: any }` when
|
|
269
270
|
* `Document` is still an unresolved generic, which breaks structural
|
|
270
271
|
* comparability in the database reader/writer plumbing.
|
package/src/Table.ts
CHANGED
|
@@ -86,7 +86,7 @@ export type AnyWithProps = Table<
|
|
|
86
86
|
// (`.index`, `.searchIndex`, `.vectorIndex`) live here and return new
|
|
87
87
|
// `UnnamedTable`s, accumulating plain index metadata records. The
|
|
88
88
|
// user-supplied `lazyFields` callback is just carried through until first
|
|
89
|
-
// access of `Fields
|
|
89
|
+
// access of `Fields`/`Doc` on a bound table. The codegen pipeline emits a
|
|
90
90
|
// wrapper file per user-authored table that simply invokes the unnamed
|
|
91
91
|
// callable with the filename basename.
|
|
92
92
|
|
|
@@ -241,7 +241,7 @@ export type TablesRecord<Tables extends AnyWithProps> = {
|
|
|
241
241
|
// spread of the metadata records) and never invokes the callback. Binding
|
|
242
242
|
// via `unnamed(tableName)` installs lazy memoised getters for `Fields` and
|
|
243
243
|
// `Doc` via `Lazy.defineProperty`, so the first access materialises the
|
|
244
|
-
// value and replaces the getter with a plain data property
|
|
244
|
+
// value and replaces the getter with a plain data property—second-and-
|
|
245
245
|
// subsequent accesses are observably indistinguishable from a plain
|
|
246
246
|
// property and avoid all function-call overhead.
|
|
247
247
|
|
|
@@ -417,6 +417,7 @@ export const make = <const TableSchema_ extends Schema.Codec<any, any>>(
|
|
|
417
417
|
* Extract all of the index field paths within a Convex `Validator`.
|
|
418
418
|
*
|
|
419
419
|
* This is used when declaring table indexes.
|
|
420
|
+
*
|
|
420
421
|
* @public
|
|
421
422
|
*/
|
|
422
423
|
type ExtractFieldPaths<T extends Validator<any, any, any>> =
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * as GroupPath from "./GroupPath";
|
|
|
5
5
|
export * as GroupSpec from "./GroupSpec";
|
|
6
6
|
export * as Identifier from "./Identifier";
|
|
7
7
|
export * as Lazy from "./Lazy";
|
|
8
|
+
export * as MiddlewareAttachment from "./MiddlewareAttachment";
|
|
8
9
|
export * as MiddlewareSpec from "./MiddlewareSpec";
|
|
9
10
|
export * as PaginationError from "./PaginationError";
|
|
10
11
|
export * as PaginationOptions from "./PaginationOptions";
|