@gaganref/confect-server 0.0.0-stage → 10.3.1-fork.10
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 +2119 -0
- package/LICENSE +7 -0
- package/README.md +16 -2
- package/dist/ActionCtx.d.ts +10 -0
- package/dist/ActionCtx.d.ts.map +1 -0
- package/dist/ActionCtx.js +18 -0
- package/dist/ActionCtx.js.map +1 -0
- package/dist/ActionRunner.d.ts +16 -0
- package/dist/ActionRunner.d.ts.map +1 -0
- package/dist/ActionRunner.js +18 -0
- package/dist/ActionRunner.js.map +1 -0
- package/dist/AiGatewayDecisionClient.d.ts +20 -0
- package/dist/AiGatewayDecisionClient.d.ts.map +1 -0
- package/dist/AiGatewayDecisionClient.js +31 -0
- package/dist/AiGatewayDecisionClient.js.map +1 -0
- package/dist/AiGatewayDecisionModel.d.ts +24 -0
- package/dist/AiGatewayDecisionModel.d.ts.map +1 -0
- package/dist/AiGatewayDecisionModel.js +27 -0
- package/dist/AiGatewayDecisionModel.js.map +1 -0
- package/dist/AiGatewayLanguageClient.d.ts +21 -0
- package/dist/AiGatewayLanguageClient.d.ts.map +1 -0
- package/dist/AiGatewayLanguageClient.js +32 -0
- package/dist/AiGatewayLanguageClient.js.map +1 -0
- package/dist/AiGatewayLanguageModel.d.ts +95 -0
- package/dist/AiGatewayLanguageModel.d.ts.map +1 -0
- package/dist/AiGatewayLanguageModel.js +42 -0
- package/dist/AiGatewayLanguageModel.js.map +1 -0
- package/dist/Auth.d.ts +20 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +31 -0
- package/dist/Auth.js.map +1 -0
- package/dist/BlobNotFoundError.d.ts +9 -0
- package/dist/BlobNotFoundError.d.ts.map +1 -0
- package/dist/BlobNotFoundError.js +13 -0
- package/dist/BlobNotFoundError.js.map +1 -0
- package/dist/Callback.d.ts +31 -0
- package/dist/Callback.d.ts.map +1 -0
- package/dist/Callback.js +182 -0
- package/dist/Callback.js.map +1 -0
- package/dist/ComponentCtx.d.ts +71 -0
- package/dist/ComponentCtx.d.ts.map +1 -0
- package/dist/ComponentCtx.js +0 -0
- package/dist/ConvexConfigProvider.d.ts +21 -0
- package/dist/ConvexConfigProvider.d.ts.map +1 -0
- package/dist/ConvexConfigProvider.js +36 -0
- package/dist/ConvexConfigProvider.js.map +1 -0
- package/dist/ConvexFunctionDefinitions.d.ts +25 -0
- package/dist/ConvexFunctionDefinitions.d.ts.map +1 -0
- package/dist/ConvexFunctionDefinitions.js +25 -0
- package/dist/ConvexFunctionDefinitions.js.map +1 -0
- package/dist/ConvexLogger.d.ts +17 -0
- package/dist/ConvexLogger.d.ts.map +1 -0
- package/dist/ConvexLogger.js +33 -0
- package/dist/ConvexLogger.js.map +1 -0
- package/dist/CronJob.d.ts +14 -0
- package/dist/CronJob.d.ts.map +1 -0
- package/dist/CronJob.js +22 -0
- package/dist/CronJob.js.map +1 -0
- package/dist/CronJobs.d.ts +22 -0
- package/dist/CronJobs.d.ts.map +1 -0
- package/dist/CronJobs.js +83 -0
- package/dist/CronJobs.js.map +1 -0
- package/dist/DataModel.d.ts +28 -0
- package/dist/DataModel.d.ts.map +1 -0
- package/dist/DataModel.js +7 -0
- package/dist/DataModel.js.map +1 -0
- package/dist/DatabaseReader.d.ts +26 -0
- package/dist/DatabaseReader.d.ts.map +1 -0
- package/dist/DatabaseReader.js +33 -0
- package/dist/DatabaseReader.js.map +1 -0
- package/dist/DatabaseSchema.d.ts +67 -0
- package/dist/DatabaseSchema.d.ts.map +1 -0
- package/dist/DatabaseSchema.js +61 -0
- package/dist/DatabaseSchema.js.map +1 -0
- package/dist/DatabaseWriter.d.ts +44 -0
- package/dist/DatabaseWriter.d.ts.map +1 -0
- package/dist/DatabaseWriter.js +47 -0
- package/dist/DatabaseWriter.js.map +1 -0
- package/dist/Document.d.ts +37 -0
- package/dist/Document.d.ts.map +1 -0
- package/dist/Document.js +54 -0
- package/dist/Document.js.map +1 -0
- package/dist/ExecutionMetadata.d.ts +13 -0
- package/dist/ExecutionMetadata.d.ts.map +1 -0
- package/dist/ExecutionMetadata.js +19 -0
- package/dist/ExecutionMetadata.js.map +1 -0
- package/dist/FunctionImpl.d.ts +39 -0
- package/dist/FunctionImpl.d.ts.map +1 -0
- package/dist/FunctionImpl.js +46 -0
- package/dist/FunctionImpl.js.map +1 -0
- package/dist/FunctionRegistryItem.d.ts +36 -0
- package/dist/FunctionRegistryItem.d.ts.map +1 -0
- package/dist/FunctionRegistryItem.js +34 -0
- package/dist/FunctionRegistryItem.js.map +1 -0
- package/dist/GroupImpl.d.ts +77 -0
- package/dist/GroupImpl.d.ts.map +1 -0
- package/dist/GroupImpl.js +81 -0
- package/dist/GroupImpl.js.map +1 -0
- package/dist/GroupRegistry.d.ts +8 -0
- package/dist/GroupRegistry.d.ts.map +1 -0
- package/dist/GroupRegistry.js +26 -0
- package/dist/GroupRegistry.js.map +1 -0
- package/dist/Handler.d.ts +47 -0
- package/dist/Handler.d.ts.map +1 -0
- package/dist/Handler.js +7 -0
- package/dist/Handler.js.map +1 -0
- package/dist/HttpRouter.d.ts +80 -0
- package/dist/HttpRouter.d.ts.map +1 -0
- package/dist/HttpRouter.js +195 -0
- package/dist/HttpRouter.js.map +1 -0
- package/dist/MiddlewareImpl.d.ts +79 -0
- package/dist/MiddlewareImpl.d.ts.map +1 -0
- package/dist/MiddlewareImpl.js +58 -0
- package/dist/MiddlewareImpl.js.map +1 -0
- package/dist/MiddlewareRegistryItem.d.ts +12 -0
- package/dist/MiddlewareRegistryItem.d.ts.map +1 -0
- package/dist/MiddlewareRegistryItem.js +15 -0
- package/dist/MiddlewareRegistryItem.js.map +1 -0
- package/dist/MutationCtx.d.ts +10 -0
- package/dist/MutationCtx.d.ts.map +1 -0
- package/dist/MutationCtx.js +18 -0
- package/dist/MutationCtx.js.map +1 -0
- package/dist/MutationRunner.d.ts +27 -0
- package/dist/MutationRunner.d.ts.map +1 -0
- package/dist/MutationRunner.js +28 -0
- package/dist/MutationRunner.js.map +1 -0
- package/dist/MutationTransactionContext.d.ts +17 -0
- package/dist/MutationTransactionContext.d.ts.map +1 -0
- package/dist/MutationTransactionContext.js +20 -0
- package/dist/MutationTransactionContext.js.map +1 -0
- package/dist/OrderedQuery.d.ts +32 -0
- package/dist/OrderedQuery.d.ts.map +1 -0
- package/dist/OrderedQuery.js +36 -0
- package/dist/OrderedQuery.js.map +1 -0
- package/dist/QueryCtx.d.ts +10 -0
- package/dist/QueryCtx.d.ts.map +1 -0
- package/dist/QueryCtx.js +18 -0
- package/dist/QueryCtx.js.map +1 -0
- package/dist/QueryInitializer.d.ts +75 -0
- package/dist/QueryInitializer.d.ts.map +1 -0
- package/dist/QueryInitializer.js +105 -0
- package/dist/QueryInitializer.js.map +1 -0
- package/dist/QueryRunner.d.ts +46 -0
- package/dist/QueryRunner.d.ts.map +1 -0
- package/dist/QueryRunner.js +30 -0
- package/dist/QueryRunner.js.map +1 -0
- package/dist/QueryStream.d.ts +678 -0
- package/dist/QueryStream.d.ts.map +1 -0
- package/dist/QueryStream.js +943 -0
- package/dist/QueryStream.js.map +1 -0
- package/dist/QueryStreamCursor.d.ts +39 -0
- package/dist/QueryStreamCursor.d.ts.map +1 -0
- package/dist/QueryStreamCursor.js +52 -0
- package/dist/QueryStreamCursor.js.map +1 -0
- package/dist/QueryStreamIndexPrefix.d.ts +48 -0
- package/dist/QueryStreamIndexPrefix.d.ts.map +1 -0
- package/dist/QueryStreamIndexPrefix.js +38 -0
- package/dist/QueryStreamIndexPrefix.js.map +1 -0
- package/dist/QueryStreamIndexRange.d.ts +193 -0
- package/dist/QueryStreamIndexRange.d.ts.map +1 -0
- package/dist/QueryStreamIndexRange.js +241 -0
- package/dist/QueryStreamIndexRange.js.map +1 -0
- package/dist/QueryStreamKey.d.ts +64 -0
- package/dist/QueryStreamKey.d.ts.map +1 -0
- package/dist/QueryStreamKey.js +69 -0
- package/dist/QueryStreamKey.js.map +1 -0
- package/dist/QueryStreamKeyBounds.d.ts +136 -0
- package/dist/QueryStreamKeyBounds.d.ts.map +1 -0
- package/dist/QueryStreamKeyBounds.js +208 -0
- package/dist/QueryStreamKeyBounds.js.map +1 -0
- package/dist/QueryStreamKeyLabels.d.ts +27 -0
- package/dist/QueryStreamKeyLabels.d.ts.map +1 -0
- package/dist/QueryStreamKeyLabels.js +22 -0
- package/dist/QueryStreamKeyLabels.js.map +1 -0
- package/dist/QueryStreamKeyLayout.d.ts +179 -0
- package/dist/QueryStreamKeyLayout.d.ts.map +1 -0
- package/dist/QueryStreamKeyLayout.js +167 -0
- package/dist/QueryStreamKeyLayout.js.map +1 -0
- package/dist/QueryStreamKeyValues.d.ts +40 -0
- package/dist/QueryStreamKeyValues.d.ts.map +1 -0
- package/dist/QueryStreamKeyValues.js +57 -0
- package/dist/QueryStreamKeyValues.js.map +1 -0
- package/dist/QueryStreamOrderDirection.d.ts +24 -0
- package/dist/QueryStreamOrderDirection.d.ts.map +1 -0
- package/dist/QueryStreamOrderDirection.js +11 -0
- package/dist/QueryStreamOrderDirection.js.map +1 -0
- package/dist/QueryStreamPagination.d.ts +264 -0
- package/dist/QueryStreamPagination.d.ts.map +1 -0
- package/dist/QueryStreamPagination.js +172 -0
- package/dist/QueryStreamPagination.js.map +1 -0
- package/dist/QueryStreamReadBudget.d.ts +63 -0
- package/dist/QueryStreamReadBudget.d.ts.map +1 -0
- package/dist/QueryStreamReadBudget.js +81 -0
- package/dist/QueryStreamReadBudget.js.map +1 -0
- package/dist/QueryTransactionContext.d.ts +16 -0
- package/dist/QueryTransactionContext.d.ts.map +1 -0
- package/dist/QueryTransactionContext.js +17 -0
- package/dist/QueryTransactionContext.js.map +1 -0
- package/dist/RegisteredConvexFunction.d.ts +359 -0
- package/dist/RegisteredConvexFunction.d.ts.map +1 -0
- package/dist/RegisteredConvexFunction.js +154 -0
- package/dist/RegisteredConvexFunction.js.map +1 -0
- package/dist/RegisteredFunction.d.ts +143 -0
- package/dist/RegisteredFunction.d.ts.map +1 -0
- package/dist/RegisteredFunction.js +125 -0
- package/dist/RegisteredFunction.js.map +1 -0
- package/dist/RegisteredFunctions.d.ts +57 -0
- package/dist/RegisteredFunctions.d.ts.map +1 -0
- package/dist/RegisteredFunctions.js +32 -0
- package/dist/RegisteredFunctions.js.map +1 -0
- package/dist/RegisteredNodeFunction.d.ts +11 -0
- package/dist/RegisteredNodeFunction.d.ts.map +1 -0
- package/dist/RegisteredNodeFunction.js +45 -0
- package/dist/RegisteredNodeFunction.js.map +1 -0
- package/dist/Registry.d.ts +12 -0
- package/dist/Registry.d.ts.map +1 -0
- package/dist/Registry.js +17 -0
- package/dist/Registry.js.map +1 -0
- package/dist/RegistryItems.d.ts +21 -0
- package/dist/RegistryItems.d.ts.map +1 -0
- package/dist/RegistryItems.js +27 -0
- package/dist/RegistryItems.js.map +1 -0
- package/dist/RequestMetadata.d.ts +12 -0
- package/dist/RequestMetadata.d.ts.map +1 -0
- package/dist/RequestMetadata.js +16 -0
- package/dist/RequestMetadata.js.map +1 -0
- package/dist/ResolvedMiddleware.d.ts +24 -0
- package/dist/ResolvedMiddleware.d.ts.map +1 -0
- package/dist/ResolvedMiddleware.js +34 -0
- package/dist/ResolvedMiddleware.js.map +1 -0
- package/dist/Scheduler.d.ts +31 -0
- package/dist/Scheduler.d.ts.map +1 -0
- package/dist/Scheduler.js +35 -0
- package/dist/Scheduler.js.map +1 -0
- package/dist/Storage.d.ts +22 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +27 -0
- package/dist/Storage.js.map +1 -0
- package/dist/StorageActionWriter.d.ts +35 -0
- package/dist/StorageActionWriter.d.ts.map +1 -0
- package/dist/StorageActionWriter.js +24 -0
- package/dist/StorageActionWriter.js.map +1 -0
- package/dist/StorageReader.d.ts +26 -0
- package/dist/StorageReader.d.ts.map +1 -0
- package/dist/StorageReader.js +22 -0
- package/dist/StorageReader.js.map +1 -0
- package/dist/StorageWriter.d.ts +29 -0
- package/dist/StorageWriter.d.ts.map +1 -0
- package/dist/StorageWriter.js +24 -0
- package/dist/StorageWriter.js.map +1 -0
- package/dist/Table.d.ts +274 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +70 -0
- package/dist/Table.js.map +1 -0
- package/dist/TableInfo.d.ts +44 -0
- package/dist/TableInfo.d.ts.map +1 -0
- package/dist/TableInfo.js +7 -0
- package/dist/TableInfo.js.map +1 -0
- package/dist/TransactionMetadata.d.ts +12 -0
- package/dist/TransactionMetadata.d.ts.map +1 -0
- package/dist/TransactionMetadata.js +16 -0
- package/dist/TransactionMetadata.js.map +1 -0
- package/dist/VectorSearch.d.ts +23 -0
- package/dist/VectorSearch.d.ts.map +1 -0
- package/dist/VectorSearch.js +17 -0
- package/dist/VectorSearch.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/internal/AiGatewayDecisionClient.d.ts +7 -0
- package/dist/internal/AiGatewayDecisionClient.d.ts.map +1 -0
- package/dist/internal/AiGatewayDecisionClient.js +19 -0
- package/dist/internal/AiGatewayDecisionClient.js.map +1 -0
- package/dist/internal/AiGatewayLanguageClient.d.ts +7 -0
- package/dist/internal/AiGatewayLanguageClient.d.ts.map +1 -0
- package/dist/internal/AiGatewayLanguageClient.js +19 -0
- package/dist/internal/AiGatewayLanguageClient.js.map +1 -0
- package/dist/internal/AiGatewayServiceToken.d.ts +46 -0
- package/dist/internal/AiGatewayServiceToken.d.ts.map +1 -0
- package/dist/internal/AiGatewayServiceToken.js +62 -0
- package/dist/internal/AiGatewayServiceToken.js.map +1 -0
- package/dist/internal/constants.d.ts +2 -0
- package/dist/internal/constants.d.ts.map +1 -0
- package/dist/internal/constants.js +6 -0
- package/dist/internal/constants.js.map +1 -0
- package/dist/internal/utils.d.ts +13 -0
- package/dist/internal/utils.d.ts.map +1 -0
- package/dist/internal/utils.js +50 -0
- package/dist/internal/utils.js.map +1 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +1 -0
- package/package.json +68 -3
- package/src/ActionCtx.ts +45 -0
- package/src/ActionRunner.ts +36 -0
- package/src/AiGatewayDecisionClient.ts +40 -0
- package/src/AiGatewayDecisionModel.ts +46 -0
- package/src/AiGatewayLanguageClient.ts +41 -0
- package/src/AiGatewayLanguageModel.ts +61 -0
- package/src/Auth.ts +51 -0
- package/src/BlobNotFoundError.ts +12 -0
- package/src/Callback.ts +313 -0
- package/src/ComponentCtx.ts +192 -0
- package/src/ConvexConfigProvider.ts +39 -0
- package/src/ConvexFunctionDefinitions.ts +91 -0
- package/src/ConvexLogger.ts +43 -0
- package/src/CronJob.ts +42 -0
- package/src/CronJobs.ts +165 -0
- package/src/DataModel.ts +81 -0
- package/src/DatabaseReader.ts +118 -0
- package/src/DatabaseSchema.ts +139 -0
- package/src/DatabaseWriter.ts +232 -0
- package/src/Document.ts +146 -0
- package/src/ExecutionMetadata.ts +26 -0
- package/src/FunctionImpl.ts +96 -0
- package/src/FunctionRegistryItem.ts +85 -0
- package/src/GroupImpl.ts +167 -0
- package/src/GroupRegistry.ts +41 -0
- package/src/Handler.ts +191 -0
- package/src/HttpRouter.ts +388 -0
- package/src/MiddlewareImpl.ts +247 -0
- package/src/MiddlewareRegistryItem.ts +21 -0
- package/src/MutationCtx.ts +45 -0
- package/src/MutationRunner.ts +66 -0
- package/src/MutationTransactionContext.ts +48 -0
- package/src/OrderedQuery.ts +136 -0
- package/src/QueryCtx.ts +45 -0
- package/src/QueryInitializer.ts +537 -0
- package/src/QueryRunner.ts +91 -0
- package/src/QueryStream.ts +2476 -0
- package/src/QueryStreamCursor.ts +99 -0
- package/src/QueryStreamIndexPrefix.ts +79 -0
- package/src/QueryStreamIndexRange.ts +489 -0
- package/src/QueryStreamKey.ts +118 -0
- package/src/QueryStreamKeyBounds.ts +395 -0
- package/src/QueryStreamKeyLabels.ts +56 -0
- package/src/QueryStreamKeyLayout.ts +382 -0
- package/src/QueryStreamKeyValues.ts +112 -0
- package/src/QueryStreamOrderDirection.ts +29 -0
- package/src/QueryStreamPagination.ts +357 -0
- package/src/QueryStreamReadBudget.ts +167 -0
- package/src/QueryTransactionContext.ts +37 -0
- package/src/RegisteredConvexFunction.ts +415 -0
- package/src/RegisteredFunction.ts +391 -0
- package/src/RegisteredFunctions.ts +88 -0
- package/src/RegisteredNodeFunction.ts +120 -0
- package/src/Registry.ts +17 -0
- package/src/RegistryItems.ts +40 -0
- package/src/RequestMetadata.ts +20 -0
- package/src/ResolvedMiddleware.ts +70 -0
- package/src/Scheduler.ts +85 -0
- package/src/Storage.ts +37 -0
- package/src/StorageActionWriter.ts +59 -0
- package/src/StorageReader.ts +59 -0
- package/src/StorageWriter.ts +58 -0
- package/src/Table.ts +156 -0
- package/src/TableInfo.ts +106 -0
- package/src/TransactionMetadata.ts +20 -0
- package/src/VectorSearch.ts +75 -0
- package/src/index.ts +87 -0
- package/src/internal/AiGatewayDecisionClient.ts +16 -0
- package/src/internal/AiGatewayLanguageClient.ts +16 -0
- package/src/internal/AiGatewayServiceToken.ts +129 -0
- package/src/internal/constants.ts +1 -0
- package/src/internal/utils.ts +89 -0
- package/src/node.ts +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as Array from "effect/Array";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as QueryStreamKey from "./QueryStreamKey.js";
|
|
4
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
5
|
+
import * as Match from "effect/Match";
|
|
6
|
+
import * as Schema from "effect/Schema";
|
|
7
|
+
import * as SchemaGetter from "effect/SchemaGetter";
|
|
8
|
+
import * as QueryStreamKeyLayout from "./QueryStreamKeyLayout.js";
|
|
9
|
+
import * as QueryStreamKeyValues from "./QueryStreamKeyValues.js";
|
|
10
|
+
|
|
11
|
+
// Serialized labels are a cursor boundary representation. They include every
|
|
12
|
+
// runtime position but do not preserve implicitness.
|
|
13
|
+
const RuntimeLabels = Schema.Array(Schema.String);
|
|
14
|
+
const RuntimeLabelsEquivalence = Schema.toEquivalence(RuntimeLabels);
|
|
15
|
+
const positionRuntimeLabel = Match.type<QueryStreamKeyLayout.Position>().pipe(
|
|
16
|
+
Match.tagsExhaustive({
|
|
17
|
+
Visible: ({ label }) => label,
|
|
18
|
+
ImplicitId: () => "_id",
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @experimental
|
|
24
|
+
*/
|
|
25
|
+
export const QueryStreamCursor = Schema.Struct({
|
|
26
|
+
runtimeLabels: RuntimeLabels,
|
|
27
|
+
keyValues: QueryStreamKeyValues.QueryStreamKeyValues,
|
|
28
|
+
}).check(
|
|
29
|
+
Schema.makeFilter(
|
|
30
|
+
(cursor) => cursor.keyValues.length === cursor.runtimeLabels.length,
|
|
31
|
+
{ message: "key values and runtime labels must have the same length" },
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @experimental
|
|
37
|
+
*/
|
|
38
|
+
export interface QueryStreamCursor extends Schema.Schema.Type<
|
|
39
|
+
typeof QueryStreamCursor
|
|
40
|
+
> {}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @experimental
|
|
44
|
+
*/
|
|
45
|
+
export const END_CURSOR = "[]";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Bind cursor string encoding and decoding to a layout.
|
|
49
|
+
*
|
|
50
|
+
* @experimental
|
|
51
|
+
*/
|
|
52
|
+
export const fromKeyLayout = (
|
|
53
|
+
keyLayout: QueryStreamKeyLayout.QueryStreamKeyLayout,
|
|
54
|
+
) => {
|
|
55
|
+
const runtimeLabels = Array.map(
|
|
56
|
+
QueryStreamKeyLayout.positions(keyLayout),
|
|
57
|
+
positionRuntimeLabel,
|
|
58
|
+
);
|
|
59
|
+
return Schema.fromJsonString(QueryStreamCursor)
|
|
60
|
+
.check(
|
|
61
|
+
Schema.makeFilter(
|
|
62
|
+
(cursor) =>
|
|
63
|
+
RuntimeLabelsEquivalence(cursor.runtimeLabels, runtimeLabels),
|
|
64
|
+
{ message: "Cursor runtime labels do not match the stream" },
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
.pipe(
|
|
68
|
+
Schema.decodeTo(
|
|
69
|
+
Schema.declare(QueryStreamKey.isComplete).check(
|
|
70
|
+
Schema.makeFilter(
|
|
71
|
+
(key) => QueryStreamKeyLayout.Equivalence(key.layout, keyLayout),
|
|
72
|
+
{ message: "Cursor key does not belong to the stream layout" },
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
{
|
|
76
|
+
decode: SchemaGetter.transformEffect((cursor, options) =>
|
|
77
|
+
Effect.fromResult(
|
|
78
|
+
QueryStreamKey.complete(keyLayout, cursor.keyValues),
|
|
79
|
+
).pipe(
|
|
80
|
+
Effect.mapError(
|
|
81
|
+
(error) =>
|
|
82
|
+
new SchemaIssue.InvalidValue(
|
|
83
|
+
{ message: error.message },
|
|
84
|
+
cursor.keyValues,
|
|
85
|
+
options,
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
encode: SchemaGetter.transformEffect((key) =>
|
|
91
|
+
QueryStreamCursor.makeEffect({
|
|
92
|
+
runtimeLabels,
|
|
93
|
+
keyValues: key.values,
|
|
94
|
+
}),
|
|
95
|
+
),
|
|
96
|
+
},
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as Array from "effect/Array";
|
|
2
|
+
import * as Data from "effect/Data";
|
|
3
|
+
import * as Result from "effect/Result";
|
|
4
|
+
import type * as QueryStreamKey from "./QueryStreamKey.js";
|
|
5
|
+
import type * as QueryStreamKeyValues from "./QueryStreamKeyValues.js";
|
|
6
|
+
|
|
7
|
+
const TypeId = "~@confect/server/QueryStreamIndexPrefix";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @experimental
|
|
11
|
+
*/
|
|
12
|
+
export type IndexEntries = ReadonlyArray<
|
|
13
|
+
readonly [string, QueryStreamKeyValues.QueryStreamKeyValues[number]]
|
|
14
|
+
>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Index coordinates retain the field path belonging to each value.
|
|
18
|
+
*
|
|
19
|
+
* @experimental
|
|
20
|
+
*/
|
|
21
|
+
export interface QueryStreamIndexPrefix {
|
|
22
|
+
readonly [TypeId]: IndexEntries;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @experimental
|
|
27
|
+
*/
|
|
28
|
+
export class IndexPrefixWidthMismatchError extends Data.TaggedError(
|
|
29
|
+
"IndexPrefixWidthMismatchError",
|
|
30
|
+
)<{
|
|
31
|
+
readonly width: number;
|
|
32
|
+
readonly actual: number;
|
|
33
|
+
}> {
|
|
34
|
+
override get message(): string {
|
|
35
|
+
return `Invalid index prefix key width (${this.actual}); expected at most ${this.width}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @experimental
|
|
41
|
+
*/
|
|
42
|
+
export const make = (
|
|
43
|
+
fieldPaths: ReadonlyArray<string>,
|
|
44
|
+
keyValues: QueryStreamKeyValues.QueryStreamKeyValues,
|
|
45
|
+
): Result.Result<QueryStreamIndexPrefix, IndexPrefixWidthMismatchError> =>
|
|
46
|
+
keyValues.length <= fieldPaths.length
|
|
47
|
+
? Result.succeed({ [TypeId]: Array.zip(fieldPaths, keyValues) })
|
|
48
|
+
: Result.fail(
|
|
49
|
+
new IndexPrefixWidthMismatchError({
|
|
50
|
+
width: fieldPaths.length,
|
|
51
|
+
actual: keyValues.length,
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @experimental
|
|
57
|
+
*/
|
|
58
|
+
export const entries = (self: QueryStreamIndexPrefix): IndexEntries =>
|
|
59
|
+
self[TypeId];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @experimental
|
|
63
|
+
*/
|
|
64
|
+
export const keyValues = (
|
|
65
|
+
self: QueryStreamIndexPrefix,
|
|
66
|
+
): QueryStreamKeyValues.QueryStreamKeyValues =>
|
|
67
|
+
Array.map(entries(self), ([, value]) => value);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Restore equality values when crossing into index coordinates.
|
|
71
|
+
*
|
|
72
|
+
* @experimental
|
|
73
|
+
*/
|
|
74
|
+
export const fromStreamKey = (
|
|
75
|
+
fieldPaths: ReadonlyArray<string>,
|
|
76
|
+
equalityKeyValues: QueryStreamKeyValues.QueryStreamKeyValues,
|
|
77
|
+
self: QueryStreamKey.QueryStreamKey,
|
|
78
|
+
): Result.Result<QueryStreamIndexPrefix, IndexPrefixWidthMismatchError> =>
|
|
79
|
+
make(fieldPaths, Array.appendAll(equalityKeyValues, self.values));
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GenericDocument,
|
|
3
|
+
FieldTypeFromFieldPath,
|
|
4
|
+
IndexRange as ConvexIndexRange,
|
|
5
|
+
IndexRangeBuilder as ConvexIndexRangeBuilder,
|
|
6
|
+
} from "convex/server";
|
|
7
|
+
import * as Array from "effect/Array";
|
|
8
|
+
import * as Data from "effect/Data";
|
|
9
|
+
import { identity, pipe } from "effect/Function";
|
|
10
|
+
import * as Match from "effect/Match";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
import * as Result from "effect/Result";
|
|
13
|
+
import type * as Types from "effect/Types";
|
|
14
|
+
import * as QueryStreamIndexPrefix from "./QueryStreamIndexPrefix.js";
|
|
15
|
+
import * as QueryStreamKeyBounds from "./QueryStreamKeyBounds.js";
|
|
16
|
+
import * as QueryStreamKeyValues from "./QueryStreamKeyValues.js";
|
|
17
|
+
import type * as QueryStreamOrderDirection from "./QueryStreamOrderDirection.js";
|
|
18
|
+
|
|
19
|
+
type Head<FieldPaths extends ReadonlyArray<string>> =
|
|
20
|
+
FieldPaths extends readonly [infer H extends string, ...ReadonlyArray<string>]
|
|
21
|
+
? H
|
|
22
|
+
: never;
|
|
23
|
+
|
|
24
|
+
type Tail<FieldPaths extends ReadonlyArray<string>> =
|
|
25
|
+
FieldPaths extends readonly [
|
|
26
|
+
string,
|
|
27
|
+
...infer Rest extends ReadonlyArray<string>,
|
|
28
|
+
]
|
|
29
|
+
? Rest
|
|
30
|
+
: ReadonlyArray<string>;
|
|
31
|
+
|
|
32
|
+
// The range builder mirrors Convex's `IndexRangeBuilder`, but *consumes* the
|
|
33
|
+
// index-field tuple at the type level as `eq` pins field paths. The remaining
|
|
34
|
+
// tuple supplies the initial visible ordering labels of the resulting stream.
|
|
35
|
+
|
|
36
|
+
const TypeId = "~@confect/server/QueryStreamIndexRange";
|
|
37
|
+
|
|
38
|
+
interface Equality {
|
|
39
|
+
readonly fieldPath: string;
|
|
40
|
+
readonly value: QueryStreamKeyValues.KeyValue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface Endpoint {
|
|
44
|
+
readonly value: QueryStreamKeyValues.KeyValue;
|
|
45
|
+
readonly inclusive: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type Interval = Data.TaggedEnum<{
|
|
49
|
+
Lower: { readonly lower: Endpoint };
|
|
50
|
+
Upper: { readonly upper: Endpoint };
|
|
51
|
+
Between: { readonly lower: Endpoint; readonly upper: Endpoint };
|
|
52
|
+
}>;
|
|
53
|
+
const Interval = Data.taggedEnum<Interval>();
|
|
54
|
+
|
|
55
|
+
interface Constraints {
|
|
56
|
+
readonly equalities: ReadonlyArray<Equality>;
|
|
57
|
+
readonly bounded: Option.Option<{
|
|
58
|
+
readonly fieldPath: string;
|
|
59
|
+
readonly interval: Interval;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The equality prefix followed by at most one bounded field.
|
|
65
|
+
*
|
|
66
|
+
* @experimental
|
|
67
|
+
*/
|
|
68
|
+
export interface QueryStreamIndexRange<
|
|
69
|
+
out RemainingFieldPaths extends ReadonlyArray<string> = ReadonlyArray<string>,
|
|
70
|
+
> {
|
|
71
|
+
readonly [TypeId]: Constraints & {
|
|
72
|
+
readonly _Remaining: Types.Covariant<RemainingFieldPaths>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @experimental
|
|
78
|
+
*/
|
|
79
|
+
export type Remaining<IndexRange> =
|
|
80
|
+
IndexRange extends QueryStreamIndexRange<infer RemainingFieldPaths>
|
|
81
|
+
? RemainingFieldPaths
|
|
82
|
+
: never;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* A typed index-range builder. `eq` must target the next unpinned index field,
|
|
86
|
+
* and consumes it; `gt`/`gte`/`lt`/`lte` bound the next field without consuming
|
|
87
|
+
* it (bounded field paths still vary within the range).
|
|
88
|
+
*
|
|
89
|
+
* @experimental
|
|
90
|
+
*/
|
|
91
|
+
export interface Builder<
|
|
92
|
+
ConvexDoc extends GenericDocument,
|
|
93
|
+
FieldPaths extends ReadonlyArray<string>,
|
|
94
|
+
> extends QueryStreamIndexRange<FieldPaths> {
|
|
95
|
+
readonly eq: (
|
|
96
|
+
fieldPath: Head<FieldPaths>,
|
|
97
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
98
|
+
) => Builder<ConvexDoc, Tail<FieldPaths>>;
|
|
99
|
+
readonly gt: (
|
|
100
|
+
fieldPath: Head<FieldPaths>,
|
|
101
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
102
|
+
) => LowerBoundedBuilder<ConvexDoc, FieldPaths>;
|
|
103
|
+
readonly gte: (
|
|
104
|
+
fieldPath: Head<FieldPaths>,
|
|
105
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
106
|
+
) => LowerBoundedBuilder<ConvexDoc, FieldPaths>;
|
|
107
|
+
readonly lt: (
|
|
108
|
+
fieldPath: Head<FieldPaths>,
|
|
109
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
110
|
+
) => QueryStreamIndexRange<FieldPaths>;
|
|
111
|
+
readonly lte: (
|
|
112
|
+
fieldPath: Head<FieldPaths>,
|
|
113
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
114
|
+
) => QueryStreamIndexRange<FieldPaths>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* After `gt`/`gte`, only an upper bound on the same field may follow.
|
|
119
|
+
*
|
|
120
|
+
* @experimental
|
|
121
|
+
*/
|
|
122
|
+
export interface LowerBoundedBuilder<
|
|
123
|
+
ConvexDoc extends GenericDocument,
|
|
124
|
+
FieldPaths extends ReadonlyArray<string>,
|
|
125
|
+
> extends QueryStreamIndexRange<FieldPaths> {
|
|
126
|
+
readonly lt: (
|
|
127
|
+
fieldPath: Head<FieldPaths>,
|
|
128
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
129
|
+
) => QueryStreamIndexRange<FieldPaths>;
|
|
130
|
+
readonly lte: (
|
|
131
|
+
fieldPath: Head<FieldPaths>,
|
|
132
|
+
value: FieldTypeFromFieldPath<ConvexDoc, Head<FieldPaths>>,
|
|
133
|
+
) => QueryStreamIndexRange<FieldPaths>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const make = (constraints: Constraints): QueryStreamIndexRange => ({
|
|
137
|
+
[TypeId]: {
|
|
138
|
+
...constraints,
|
|
139
|
+
_Remaining: identity as Types.Covariant<ReadonlyArray<string>>,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const makeBuilder = (
|
|
144
|
+
equalities: ReadonlyArray<Equality>,
|
|
145
|
+
): Builder<GenericDocument, ReadonlyArray<string>> => {
|
|
146
|
+
const upper =
|
|
147
|
+
(inclusive: boolean) =>
|
|
148
|
+
(fieldPath: string, value: QueryStreamKeyValues.KeyValue) =>
|
|
149
|
+
make({
|
|
150
|
+
equalities,
|
|
151
|
+
bounded: Option.some({
|
|
152
|
+
fieldPath,
|
|
153
|
+
interval: Interval.Upper({ upper: { value, inclusive } }),
|
|
154
|
+
}),
|
|
155
|
+
});
|
|
156
|
+
const lower =
|
|
157
|
+
(inclusive: boolean) =>
|
|
158
|
+
(
|
|
159
|
+
fieldPath: string,
|
|
160
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
161
|
+
): LowerBoundedBuilder<GenericDocument, ReadonlyArray<string>> => {
|
|
162
|
+
const endpoint = { value, inclusive };
|
|
163
|
+
const finish =
|
|
164
|
+
(upperInclusive: boolean) =>
|
|
165
|
+
(_fieldPath: string, upperValue: QueryStreamKeyValues.KeyValue) =>
|
|
166
|
+
make({
|
|
167
|
+
equalities,
|
|
168
|
+
bounded: Option.some({
|
|
169
|
+
fieldPath,
|
|
170
|
+
interval: Interval.Between({
|
|
171
|
+
lower: endpoint,
|
|
172
|
+
upper: { value: upperValue, inclusive: upperInclusive },
|
|
173
|
+
}),
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
...make({
|
|
178
|
+
equalities,
|
|
179
|
+
bounded: Option.some({
|
|
180
|
+
fieldPath,
|
|
181
|
+
interval: Interval.Lower({ lower: endpoint }),
|
|
182
|
+
}),
|
|
183
|
+
}),
|
|
184
|
+
lt: finish(false),
|
|
185
|
+
lte: finish(true),
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
return {
|
|
189
|
+
...make({ equalities, bounded: Option.none() }),
|
|
190
|
+
eq: (fieldPath, value) =>
|
|
191
|
+
makeBuilder(Array.append(equalities, { fieldPath, value })),
|
|
192
|
+
gt: lower(false),
|
|
193
|
+
gte: lower(true),
|
|
194
|
+
lt: upper(false),
|
|
195
|
+
lte: upper(true),
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The initial builder handed to a range callback.
|
|
201
|
+
*
|
|
202
|
+
* @experimental
|
|
203
|
+
*/
|
|
204
|
+
export const builder = <
|
|
205
|
+
ConvexDoc extends GenericDocument,
|
|
206
|
+
FieldPaths extends ReadonlyArray<string>,
|
|
207
|
+
>(): Builder<ConvexDoc, FieldPaths> =>
|
|
208
|
+
makeBuilder([]) as unknown as Builder<ConvexDoc, FieldPaths>;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Number of index fields pinned by equality constraints.
|
|
212
|
+
*
|
|
213
|
+
* @experimental
|
|
214
|
+
*/
|
|
215
|
+
export const equalityPrefixLength = (self: QueryStreamIndexRange): number =>
|
|
216
|
+
self[TypeId].equalities.length;
|
|
217
|
+
|
|
218
|
+
interface ConvexUpperBoundBuilder extends ConvexIndexRange {
|
|
219
|
+
readonly lt: (
|
|
220
|
+
fieldPath: string,
|
|
221
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
222
|
+
) => ConvexIndexRange;
|
|
223
|
+
readonly lte: (
|
|
224
|
+
fieldPath: string,
|
|
225
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
226
|
+
) => ConvexIndexRange;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface ConvexRangeBuilder extends ConvexUpperBoundBuilder {
|
|
230
|
+
readonly eq: (
|
|
231
|
+
fieldPath: string,
|
|
232
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
233
|
+
) => ConvexRangeBuilder;
|
|
234
|
+
readonly gt: (
|
|
235
|
+
fieldPath: string,
|
|
236
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
237
|
+
) => ConvexUpperBoundBuilder;
|
|
238
|
+
readonly gte: (
|
|
239
|
+
fieldPath: string,
|
|
240
|
+
value: QueryStreamKeyValues.KeyValue,
|
|
241
|
+
) => ConvexUpperBoundBuilder;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Apply one range to Convex's index-range builder.
|
|
246
|
+
*
|
|
247
|
+
* @experimental
|
|
248
|
+
*/
|
|
249
|
+
export const apply = (
|
|
250
|
+
self: QueryStreamIndexRange,
|
|
251
|
+
q: ConvexIndexRangeBuilder<GenericDocument, string[]>,
|
|
252
|
+
): ConvexIndexRange => {
|
|
253
|
+
const { equalities, bounded } = self[TypeId];
|
|
254
|
+
// Convex tracks equality progress through a static field tuple. These paths
|
|
255
|
+
// are runtime data; the range model owns their ordering. Its runtime builder
|
|
256
|
+
// supports further equality calls, even when the SDK type has lost the tuple.
|
|
257
|
+
const prefix = Array.reduce(
|
|
258
|
+
equalities,
|
|
259
|
+
q as ConvexRangeBuilder,
|
|
260
|
+
(target, { fieldPath, value }) => target.eq(fieldPath, value),
|
|
261
|
+
);
|
|
262
|
+
return Option.match(bounded, {
|
|
263
|
+
onNone: () => prefix,
|
|
264
|
+
onSome: ({ fieldPath, interval }) => {
|
|
265
|
+
const lower = (
|
|
266
|
+
target: ConvexRangeBuilder,
|
|
267
|
+
endpoint: Endpoint,
|
|
268
|
+
): ConvexUpperBoundBuilder =>
|
|
269
|
+
target[endpoint.inclusive ? "gte" : "gt"](fieldPath, endpoint.value);
|
|
270
|
+
const upper = (
|
|
271
|
+
target: ConvexUpperBoundBuilder,
|
|
272
|
+
endpoint: Endpoint,
|
|
273
|
+
): ConvexIndexRange =>
|
|
274
|
+
target[endpoint.inclusive ? "lte" : "lt"](fieldPath, endpoint.value);
|
|
275
|
+
return Interval.$match(interval, {
|
|
276
|
+
Lower: ({ lower: endpoint }) => lower(prefix, endpoint),
|
|
277
|
+
Upper: ({ upper: endpoint }) => upper(prefix, endpoint),
|
|
278
|
+
Between: (endpoints) =>
|
|
279
|
+
upper(lower(prefix, endpoints.lower), endpoints.upper),
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// Convex index ranges have the shape `eq(f1) … eq(fn), gt/gte(fm)?,
|
|
286
|
+
// lt/lte(fm)?`—every field path pinned except the last, which may carry two
|
|
287
|
+
// inequalities. An arbitrary range between two index keys therefore
|
|
288
|
+
// decomposes into a *sequence* of Convex-expressible ranges (the port of
|
|
289
|
+
// `convex-helpers`' `splitRange`): e.g. `(1, 2, 3) < key <= (1, 3, 2)` over
|
|
290
|
+
// field paths `(f1, f2, f3)` becomes
|
|
291
|
+
//
|
|
292
|
+
// 1. eq(f1, 1), eq(f2, 2), gt(f3, 3)
|
|
293
|
+
// 2. eq(f1, 1), gt(f2, 2), lt(f2, 3)
|
|
294
|
+
// 3. eq(f1, 1), eq(f2, 3), lte(f3, 2)
|
|
295
|
+
|
|
296
|
+
type BoundTag = "gt" | "gte" | "lt" | "lte";
|
|
297
|
+
|
|
298
|
+
class TaggedBound extends Data.Class<{
|
|
299
|
+
readonly indexEntries: QueryStreamIndexPrefix.IndexEntries;
|
|
300
|
+
readonly tag: BoundTag;
|
|
301
|
+
}> {}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Dropping a bound's last entry bounds the remaining prefix exclusively.
|
|
305
|
+
*/
|
|
306
|
+
const excludePrefix = (tag: BoundTag): BoundTag =>
|
|
307
|
+
Match.value(tag).pipe(
|
|
308
|
+
Match.whenOr("gt", "gte", () => "gt" as const),
|
|
309
|
+
Match.whenOr("lt", "lte", () => "lt" as const),
|
|
310
|
+
Match.exhaustive,
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Peel a bound down to the single entry that feeds the middle range.
|
|
315
|
+
*/
|
|
316
|
+
const peelBound = (
|
|
317
|
+
indexEntries: QueryStreamIndexPrefix.IndexEntries,
|
|
318
|
+
tag: BoundTag,
|
|
319
|
+
): {
|
|
320
|
+
readonly peeled: ReadonlyArray<TaggedBound>;
|
|
321
|
+
readonly final: TaggedBound;
|
|
322
|
+
} =>
|
|
323
|
+
indexEntries.length <= 1
|
|
324
|
+
? { peeled: [], final: new TaggedBound({ indexEntries, tag }) }
|
|
325
|
+
: pipe(
|
|
326
|
+
peelBound(Array.dropRight(indexEntries, 1), excludePrefix(tag)),
|
|
327
|
+
({ final, peeled }) => ({
|
|
328
|
+
peeled: Array.prepend(peeled, new TaggedBound({ indexEntries, tag })),
|
|
329
|
+
final,
|
|
330
|
+
}),
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Pin every entry but the last, which gets the bound tag.
|
|
335
|
+
*/
|
|
336
|
+
const rangeFor = (
|
|
337
|
+
prefix: ReadonlyArray<Equality>,
|
|
338
|
+
indexEntries: QueryStreamIndexPrefix.IndexEntries,
|
|
339
|
+
tag: BoundTag,
|
|
340
|
+
): QueryStreamIndexRange =>
|
|
341
|
+
Option.match(Array.last(indexEntries), {
|
|
342
|
+
onNone: () => make({ equalities: prefix, bounded: Option.none() }),
|
|
343
|
+
onSome: ([fieldPath, value]) =>
|
|
344
|
+
make({
|
|
345
|
+
equalities: Array.appendAll(
|
|
346
|
+
prefix,
|
|
347
|
+
Array.map(Array.dropRight(indexEntries, 1), ([path, pinned]) => ({
|
|
348
|
+
fieldPath: path,
|
|
349
|
+
value: pinned,
|
|
350
|
+
})),
|
|
351
|
+
),
|
|
352
|
+
bounded: Option.some({
|
|
353
|
+
fieldPath,
|
|
354
|
+
interval:
|
|
355
|
+
tag === "gt" || tag === "gte"
|
|
356
|
+
? Interval.Lower({ lower: { value, inclusive: tag === "gte" } })
|
|
357
|
+
: Interval.Upper({ upper: { value, inclusive: tag === "lte" } }),
|
|
358
|
+
}),
|
|
359
|
+
}),
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Decompose the range between `indexBounds.lower` and `indexBounds.upper` (over
|
|
364
|
+
* the complete index `fieldPaths`, `_id` tiebreaker included) into a sequence
|
|
365
|
+
* of Convex-expressible ranges, ordered for the given direction.
|
|
366
|
+
*
|
|
367
|
+
* @experimental
|
|
368
|
+
*/
|
|
369
|
+
export const fromBounds = (
|
|
370
|
+
fieldPaths: ReadonlyArray<string>,
|
|
371
|
+
orderDirection: QueryStreamOrderDirection.QueryStreamOrderDirection,
|
|
372
|
+
indexBounds: QueryStreamKeyBounds.IndexBounds,
|
|
373
|
+
): Result.Result<
|
|
374
|
+
ReadonlyArray<QueryStreamIndexRange>,
|
|
375
|
+
QueryStreamIndexPrefix.IndexPrefixWidthMismatchError
|
|
376
|
+
> =>
|
|
377
|
+
Result.gen(function* () {
|
|
378
|
+
const lowerIndexEntries = QueryStreamIndexPrefix.entries(
|
|
379
|
+
yield* QueryStreamIndexPrefix.make(
|
|
380
|
+
fieldPaths,
|
|
381
|
+
indexBounds.lower.keyValues,
|
|
382
|
+
),
|
|
383
|
+
);
|
|
384
|
+
const upperIndexEntries = QueryStreamIndexPrefix.entries(
|
|
385
|
+
yield* QueryStreamIndexPrefix.make(
|
|
386
|
+
fieldPaths,
|
|
387
|
+
indexBounds.upper.keyValues,
|
|
388
|
+
),
|
|
389
|
+
);
|
|
390
|
+
// Equal cuts are an empty range too: e.g. lower exclusive at `k` and
|
|
391
|
+
// upper inclusive at `k`—the half-open (k, k]—both cut at
|
|
392
|
+
// successor(k).
|
|
393
|
+
if (QueryStreamKeyBounds.isEmpty(indexBounds)) {
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const commonLength = pipe(
|
|
398
|
+
Array.zip(indexBounds.lower.keyValues, indexBounds.upper.keyValues),
|
|
399
|
+
Array.takeWhile(
|
|
400
|
+
([lowerValue, upperValue]) =>
|
|
401
|
+
QueryStreamKeyValues.ValueOrder(lowerValue, upperValue) === 0,
|
|
402
|
+
),
|
|
403
|
+
Array.length,
|
|
404
|
+
);
|
|
405
|
+
const equalities = pipe(
|
|
406
|
+
Array.take(lowerIndexEntries, commonLength),
|
|
407
|
+
Array.map(([fieldPath, value]) => ({ fieldPath, value })),
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
const lower = peelBound(
|
|
411
|
+
Array.drop(lowerIndexEntries, commonLength),
|
|
412
|
+
indexBounds.lower.inclusive ? "gte" : "gt",
|
|
413
|
+
);
|
|
414
|
+
const upper = peelBound(
|
|
415
|
+
Array.drop(upperIndexEntries, commonLength),
|
|
416
|
+
indexBounds.upper.inclusive ? "lte" : "lt",
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
const startIndexRanges = Array.map(lower.peeled, ({ indexEntries, tag }) =>
|
|
420
|
+
rangeFor(equalities, indexEntries, tag),
|
|
421
|
+
);
|
|
422
|
+
const endIndexRanges = Array.reverse(
|
|
423
|
+
Array.map(upper.peeled, ({ indexEntries, tag }) =>
|
|
424
|
+
rangeFor(equalities, indexEntries, tag),
|
|
425
|
+
),
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
const { indexEntries: lowerFinalIndexEntries, tag: lowerFinalTag } =
|
|
429
|
+
lower.final;
|
|
430
|
+
const { indexEntries: upperFinalIndexEntries, tag: upperFinalTag } =
|
|
431
|
+
upper.final;
|
|
432
|
+
const middleIndexRange =
|
|
433
|
+
Array.isReadonlyArrayNonEmpty(lowerFinalIndexEntries) &&
|
|
434
|
+
Array.isReadonlyArrayNonEmpty(upperFinalIndexEntries)
|
|
435
|
+
? make({
|
|
436
|
+
equalities,
|
|
437
|
+
bounded: Option.some({
|
|
438
|
+
fieldPath: Array.headNonEmpty(lowerFinalIndexEntries)[0],
|
|
439
|
+
interval: Interval.Between({
|
|
440
|
+
lower: {
|
|
441
|
+
value: Array.headNonEmpty(lowerFinalIndexEntries)[1],
|
|
442
|
+
inclusive: lowerFinalTag === "gte",
|
|
443
|
+
},
|
|
444
|
+
upper: {
|
|
445
|
+
value: Array.headNonEmpty(upperFinalIndexEntries)[1],
|
|
446
|
+
inclusive: upperFinalTag === "lte",
|
|
447
|
+
},
|
|
448
|
+
}),
|
|
449
|
+
}),
|
|
450
|
+
})
|
|
451
|
+
: Array.isReadonlyArrayNonEmpty(lowerFinalIndexEntries)
|
|
452
|
+
? rangeFor(equalities, lowerFinalIndexEntries, lowerFinalTag)
|
|
453
|
+
: rangeFor(equalities, upperFinalIndexEntries, upperFinalTag);
|
|
454
|
+
|
|
455
|
+
const indexRanges = Array.appendAll(
|
|
456
|
+
Array.appendAll(startIndexRanges, Array.of(middleIndexRange)),
|
|
457
|
+
endIndexRanges,
|
|
458
|
+
);
|
|
459
|
+
return orderDirection === "desc" ? Array.reverse(indexRanges) : indexRanges;
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Derive full-index bounds directly from the structural range.
|
|
464
|
+
*
|
|
465
|
+
* @experimental
|
|
466
|
+
*/
|
|
467
|
+
export const toBounds = (
|
|
468
|
+
self: QueryStreamIndexRange,
|
|
469
|
+
): QueryStreamKeyBounds.IndexBounds => {
|
|
470
|
+
const { equalities, bounded } = self[TypeId];
|
|
471
|
+
const keyValues = Array.map(equalities, (equality) => equality.value);
|
|
472
|
+
const unbounded = { keyValues, inclusive: true };
|
|
473
|
+
const endpoint = ({ value, inclusive }: Endpoint) => ({
|
|
474
|
+
keyValues: Array.append(keyValues, value),
|
|
475
|
+
inclusive,
|
|
476
|
+
});
|
|
477
|
+
return Option.match(bounded, {
|
|
478
|
+
onNone: () => ({ lower: unbounded, upper: unbounded }),
|
|
479
|
+
onSome: ({ interval }) =>
|
|
480
|
+
Interval.$match(interval, {
|
|
481
|
+
Lower: ({ lower }) => ({ lower: endpoint(lower), upper: unbounded }),
|
|
482
|
+
Upper: ({ upper }) => ({ lower: unbounded, upper: endpoint(upper) }),
|
|
483
|
+
Between: ({ lower, upper }) => ({
|
|
484
|
+
lower: endpoint(lower),
|
|
485
|
+
upper: endpoint(upper),
|
|
486
|
+
}),
|
|
487
|
+
}),
|
|
488
|
+
});
|
|
489
|
+
};
|