@confect/server 1.0.0-next.0
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 +12 -0
- package/LICENSE +7 -0
- package/dist/ActionCtx.d.ts +12 -0
- package/dist/ActionCtx.d.ts.map +1 -0
- package/dist/ActionCtx.js +10 -0
- package/dist/ActionCtx.js.map +1 -0
- package/dist/ActionRunner.d.ts +15 -0
- package/dist/ActionRunner.d.ts.map +1 -0
- package/dist/ActionRunner.js +23 -0
- package/dist/ActionRunner.js.map +1 -0
- package/dist/Api.d.ts +27 -0
- package/dist/Api.d.ts.map +1 -0
- package/dist/Api.js +26 -0
- package/dist/Api.js.map +1 -0
- package/dist/Auth.d.ts +30 -0
- package/dist/Auth.d.ts.map +1 -0
- package/dist/Auth.js +24 -0
- package/dist/Auth.js.map +1 -0
- package/dist/DataModel.d.ts +33 -0
- package/dist/DataModel.d.ts.map +1 -0
- package/dist/DataModel.js +6 -0
- package/dist/DataModel.js.map +1 -0
- package/dist/DatabaseReader.d.ts +73 -0
- package/dist/DatabaseReader.d.ts.map +1 -0
- package/dist/DatabaseReader.js +32 -0
- package/dist/DatabaseReader.js.map +1 -0
- package/dist/DatabaseSchema.d.ts +139 -0
- package/dist/DatabaseSchema.d.ts.map +1 -0
- package/dist/DatabaseSchema.js +45 -0
- package/dist/DatabaseSchema.js.map +1 -0
- package/dist/DatabaseWriter.d.ts +39 -0
- package/dist/DatabaseWriter.d.ts.map +1 -0
- package/dist/DatabaseWriter.js +43 -0
- package/dist/DatabaseWriter.js.map +1 -0
- package/dist/Document.d.ts +47 -0
- package/dist/Document.d.ts.map +1 -0
- package/dist/Document.js +66 -0
- package/dist/Document.js.map +1 -0
- package/dist/FunctionImpl.d.ts +34 -0
- package/dist/FunctionImpl.d.ts.map +1 -0
- package/dist/FunctionImpl.js +35 -0
- package/dist/FunctionImpl.js.map +1 -0
- package/dist/GroupImpl.d.ts +24 -0
- package/dist/GroupImpl.d.ts.map +1 -0
- package/dist/GroupImpl.js +14 -0
- package/dist/GroupImpl.js.map +1 -0
- package/dist/Handler.d.ts +31 -0
- package/dist/Handler.d.ts.map +1 -0
- package/dist/Handler.js +6 -0
- package/dist/Handler.js.map +1 -0
- package/dist/HttpApi.d.ts +26 -0
- package/dist/HttpApi.d.ts.map +1 -0
- package/dist/HttpApi.js +74 -0
- package/dist/HttpApi.js.map +1 -0
- package/dist/Impl.d.ts +24 -0
- package/dist/Impl.d.ts.map +1 -0
- package/dist/Impl.js +28 -0
- package/dist/Impl.js.map +1 -0
- package/dist/MutationCtx.d.ts +12 -0
- package/dist/MutationCtx.d.ts.map +1 -0
- package/dist/MutationCtx.js +10 -0
- package/dist/MutationCtx.js.map +1 -0
- package/dist/MutationRunner.d.ts +24 -0
- package/dist/MutationRunner.d.ts.map +1 -0
- package/dist/MutationRunner.js +33 -0
- package/dist/MutationRunner.js.map +1 -0
- package/dist/OrderedQuery.d.ts +23 -0
- package/dist/OrderedQuery.d.ts.map +1 -0
- package/dist/OrderedQuery.js +34 -0
- package/dist/OrderedQuery.js.map +1 -0
- package/dist/QueryCtx.d.ts +12 -0
- package/dist/QueryCtx.d.ts.map +1 -0
- package/dist/QueryCtx.js +10 -0
- package/dist/QueryCtx.js.map +1 -0
- package/dist/QueryInitializer.d.ts +49 -0
- package/dist/QueryInitializer.d.ts.map +1 -0
- package/dist/QueryInitializer.js +83 -0
- package/dist/QueryInitializer.js.map +1 -0
- package/dist/QueryRunner.d.ts +14 -0
- package/dist/QueryRunner.d.ts.map +1 -0
- package/dist/QueryRunner.js +23 -0
- package/dist/QueryRunner.js.map +1 -0
- package/dist/RegisteredFunctions.d.ts +66 -0
- package/dist/RegisteredFunctions.d.ts.map +1 -0
- package/dist/RegisteredFunctions.js +71 -0
- package/dist/RegisteredFunctions.js.map +1 -0
- package/dist/Registry.d.ts +15 -0
- package/dist/Registry.d.ts.map +1 -0
- package/dist/Registry.js +10 -0
- package/dist/Registry.js.map +1 -0
- package/dist/RegistryItem.d.ts +31 -0
- package/dist/RegistryItem.d.ts.map +1 -0
- package/dist/RegistryItem.js +20 -0
- package/dist/RegistryItem.js.map +1 -0
- package/dist/Scheduler.d.ts +23 -0
- package/dist/Scheduler.d.ts.map +1 -0
- package/dist/Scheduler.js +24 -0
- package/dist/Scheduler.js.map +1 -0
- package/dist/SchemaToValidator.d.ts +88 -0
- package/dist/SchemaToValidator.d.ts.map +1 -0
- package/dist/SchemaToValidator.js +155 -0
- package/dist/SchemaToValidator.js.map +1 -0
- package/dist/Storage.d.ts +69 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +46 -0
- package/dist/Storage.js.map +1 -0
- package/dist/Table.d.ts +247 -0
- package/dist/Table.d.ts.map +1 -0
- package/dist/Table.js +97 -0
- package/dist/Table.js.map +1 -0
- package/dist/TableInfo.d.ts +48 -0
- package/dist/TableInfo.d.ts.map +1 -0
- package/dist/TableInfo.js +6 -0
- package/dist/TableInfo.js.map +1 -0
- package/dist/VectorSearch.d.ts +42 -0
- package/dist/VectorSearch.d.ts.map +1 -0
- package/dist/VectorSearch.js +16 -0
- package/dist/VectorSearch.js.map +1 -0
- package/dist/_virtual/rolldown_runtime.js +13 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +31 -0
- package/dist/internal/utils.d.ts +15 -0
- package/dist/internal/utils.d.ts.map +1 -0
- package/dist/internal/utils.js +49 -0
- package/dist/internal/utils.js.map +1 -0
- package/package.json +90 -0
- package/src/ActionCtx.ts +9 -0
- package/src/ActionRunner.ts +28 -0
- package/src/Api.ts +63 -0
- package/src/Auth.ts +31 -0
- package/src/DataModel.ts +69 -0
- package/src/DatabaseReader.ts +75 -0
- package/src/DatabaseSchema.ts +134 -0
- package/src/DatabaseWriter.ts +166 -0
- package/src/Document.ts +200 -0
- package/src/FunctionImpl.ts +112 -0
- package/src/GroupImpl.ts +60 -0
- package/src/Handler.ts +105 -0
- package/src/HttpApi.ts +232 -0
- package/src/Impl.ts +57 -0
- package/src/MutationCtx.ts +11 -0
- package/src/MutationRunner.ts +41 -0
- package/src/OrderedQuery.ts +109 -0
- package/src/QueryCtx.ts +9 -0
- package/src/QueryInitializer.ts +308 -0
- package/src/QueryRunner.ts +29 -0
- package/src/RegisteredFunctions.ts +381 -0
- package/src/Registry.ts +13 -0
- package/src/RegistryItem.ts +44 -0
- package/src/Scheduler.ts +39 -0
- package/src/SchemaToValidator.ts +619 -0
- package/src/Storage.ts +86 -0
- package/src/Table.ts +439 -0
- package/src/TableInfo.ts +91 -0
- package/src/VectorSearch.ts +46 -0
- package/src/index.ts +29 -0
- package/src/internal/utils.ts +87 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OrderedQuery as ConvexOrderedQuery,
|
|
3
|
+
PaginationResult,
|
|
4
|
+
} from "convex/server";
|
|
5
|
+
import { Chunk, Effect, identity, type Option, pipe, Stream } from "effect";
|
|
6
|
+
import * as Document from "./Document";
|
|
7
|
+
import type * as TableInfo from "./TableInfo";
|
|
8
|
+
|
|
9
|
+
export type OrderedQuery<
|
|
10
|
+
TableInfo_ extends TableInfo.AnyWithProps,
|
|
11
|
+
_TableName extends string,
|
|
12
|
+
> = {
|
|
13
|
+
readonly first: () => Effect.Effect<
|
|
14
|
+
Option.Option<TableInfo_["document"]>,
|
|
15
|
+
Document.DocumentDecodeError
|
|
16
|
+
>;
|
|
17
|
+
readonly take: (
|
|
18
|
+
n: number,
|
|
19
|
+
) => Effect.Effect<
|
|
20
|
+
ReadonlyArray<TableInfo_["document"]>,
|
|
21
|
+
Document.DocumentDecodeError
|
|
22
|
+
>;
|
|
23
|
+
readonly collect: () => Effect.Effect<
|
|
24
|
+
ReadonlyArray<TableInfo_["document"]>,
|
|
25
|
+
Document.DocumentDecodeError
|
|
26
|
+
>;
|
|
27
|
+
readonly stream: () => Stream.Stream<
|
|
28
|
+
TableInfo_["document"],
|
|
29
|
+
Document.DocumentDecodeError
|
|
30
|
+
>;
|
|
31
|
+
readonly paginate: (options: {
|
|
32
|
+
cursor: string | null;
|
|
33
|
+
numItems: number;
|
|
34
|
+
}) => Effect.Effect<
|
|
35
|
+
PaginationResult<TableInfo_["document"]>,
|
|
36
|
+
Document.DocumentDecodeError
|
|
37
|
+
>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const make = <
|
|
41
|
+
TableInfo_ extends TableInfo.AnyWithProps,
|
|
42
|
+
TableName extends string,
|
|
43
|
+
>(
|
|
44
|
+
query: ConvexOrderedQuery<TableInfo.ConvexTableInfo<TableInfo_>>,
|
|
45
|
+
tableName: TableName,
|
|
46
|
+
tableSchema: TableInfo.TableSchema<TableInfo_>,
|
|
47
|
+
): OrderedQuery<TableInfo_, TableName> => {
|
|
48
|
+
type OrderedQueryFunction<
|
|
49
|
+
FunctionName extends keyof OrderedQuery<TableInfo_, TableName>,
|
|
50
|
+
> = OrderedQuery<TableInfo_, TableName>[FunctionName];
|
|
51
|
+
|
|
52
|
+
const streamEncoded = Stream.fromAsyncIterable(query, identity).pipe(
|
|
53
|
+
Stream.orDie,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const stream: OrderedQueryFunction<"stream"> = () =>
|
|
57
|
+
pipe(
|
|
58
|
+
streamEncoded,
|
|
59
|
+
Stream.mapEffect(Document.decode(tableName, tableSchema)),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const first: OrderedQueryFunction<"first"> = () =>
|
|
63
|
+
pipe(stream(), Stream.take(1), Stream.runHead);
|
|
64
|
+
|
|
65
|
+
const take: OrderedQueryFunction<"take"> = (n: number) =>
|
|
66
|
+
pipe(
|
|
67
|
+
stream(),
|
|
68
|
+
Stream.take(n),
|
|
69
|
+
Stream.runCollect,
|
|
70
|
+
Effect.map((chunk) => Chunk.toReadonlyArray(chunk)),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const collect: OrderedQueryFunction<"collect"> = () =>
|
|
74
|
+
pipe(stream(), Stream.runCollect, Effect.map(Chunk.toReadonlyArray));
|
|
75
|
+
|
|
76
|
+
const paginate: OrderedQueryFunction<"paginate"> = (options) =>
|
|
77
|
+
Effect.gen(function* () {
|
|
78
|
+
const paginationResult = yield* Effect.promise(() =>
|
|
79
|
+
query.paginate(options),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const parsedPage = yield* Effect.forEach(
|
|
83
|
+
paginationResult.page,
|
|
84
|
+
Document.decode(tableName, tableSchema),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
page: parsedPage,
|
|
89
|
+
isDone: paginationResult.isDone,
|
|
90
|
+
continueCursor: paginationResult.continueCursor,
|
|
91
|
+
/* v8 ignore start */
|
|
92
|
+
...(paginationResult.splitCursor
|
|
93
|
+
? { splitCursor: paginationResult.splitCursor }
|
|
94
|
+
: {}),
|
|
95
|
+
...(paginationResult.pageStatus
|
|
96
|
+
? { pageStatus: paginationResult.pageStatus }
|
|
97
|
+
: {}),
|
|
98
|
+
/* v8 ignore stop */
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
first,
|
|
104
|
+
take,
|
|
105
|
+
collect,
|
|
106
|
+
paginate,
|
|
107
|
+
stream,
|
|
108
|
+
};
|
|
109
|
+
};
|
package/src/QueryCtx.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GenericDataModel, GenericQueryCtx } from "convex/server";
|
|
2
|
+
import { Context } from "effect";
|
|
3
|
+
|
|
4
|
+
export const QueryCtx = <DataModel extends GenericDataModel>() =>
|
|
5
|
+
Context.GenericTag<GenericQueryCtx<DataModel>>("@confect/server/QueryCtx");
|
|
6
|
+
|
|
7
|
+
export type QueryCtx<DataModel extends GenericDataModel> = ReturnType<
|
|
8
|
+
typeof QueryCtx<DataModel>
|
|
9
|
+
>["Identifier"];
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OrderedQuery as ConvexOrderedQuery,
|
|
3
|
+
QueryInitializer as ConvexQueryInitializer,
|
|
4
|
+
DocumentByInfo,
|
|
5
|
+
GenericTableIndexes,
|
|
6
|
+
GenericTableInfo,
|
|
7
|
+
Indexes,
|
|
8
|
+
IndexRange,
|
|
9
|
+
IndexRangeBuilder,
|
|
10
|
+
NamedIndex,
|
|
11
|
+
NamedSearchIndex,
|
|
12
|
+
NamedTableInfo,
|
|
13
|
+
Query,
|
|
14
|
+
SearchFilter,
|
|
15
|
+
SearchFilterBuilder,
|
|
16
|
+
SearchIndexes,
|
|
17
|
+
} from "convex/server";
|
|
18
|
+
import type { GenericId } from "convex/values";
|
|
19
|
+
import { Array, Effect, Either, pipe, Schema } from "effect";
|
|
20
|
+
import type {
|
|
21
|
+
BaseDatabaseReader,
|
|
22
|
+
IndexFieldTypesForEq,
|
|
23
|
+
} from "@confect/core/Types";
|
|
24
|
+
import type * as DataModel from "./DataModel";
|
|
25
|
+
import * as Document from "./Document";
|
|
26
|
+
import * as OrderedQuery from "./OrderedQuery";
|
|
27
|
+
import type * as Table from "./Table";
|
|
28
|
+
import type * as TableInfo from "./TableInfo";
|
|
29
|
+
|
|
30
|
+
type QueryInitializer<
|
|
31
|
+
DataModel_ extends DataModel.AnyWithProps,
|
|
32
|
+
TableName extends DataModel.TableNames<DataModel_>,
|
|
33
|
+
_ConvexTableInfo extends GenericTableInfo,
|
|
34
|
+
_TableInfo extends TableInfo.AnyWithProps,
|
|
35
|
+
> = {
|
|
36
|
+
readonly get: {
|
|
37
|
+
(
|
|
38
|
+
id: GenericId<TableName>,
|
|
39
|
+
): Effect.Effect<
|
|
40
|
+
_TableInfo["document"],
|
|
41
|
+
Document.DocumentDecodeError | GetByIdFailure
|
|
42
|
+
>;
|
|
43
|
+
<IndexName extends keyof Indexes<_ConvexTableInfo>>(
|
|
44
|
+
indexName: IndexName,
|
|
45
|
+
...indexFieldValues: IndexFieldTypesForEq<
|
|
46
|
+
DataModel.ToConvex<DataModel_>,
|
|
47
|
+
TableName,
|
|
48
|
+
Indexes<_ConvexTableInfo>[IndexName]
|
|
49
|
+
>
|
|
50
|
+
): Effect.Effect<
|
|
51
|
+
_TableInfo["document"],
|
|
52
|
+
Document.DocumentDecodeError | GetByIndexFailure
|
|
53
|
+
>;
|
|
54
|
+
};
|
|
55
|
+
readonly index: {
|
|
56
|
+
<IndexName extends keyof Indexes<_ConvexTableInfo>>(
|
|
57
|
+
indexName: IndexName,
|
|
58
|
+
indexRange?: (
|
|
59
|
+
q: IndexRangeBuilder<
|
|
60
|
+
_TableInfo["convexDocument"],
|
|
61
|
+
NamedIndex<_ConvexTableInfo, IndexName>
|
|
62
|
+
>,
|
|
63
|
+
) => IndexRange,
|
|
64
|
+
order?: "asc" | "desc",
|
|
65
|
+
): OrderedQuery.OrderedQuery<_TableInfo, TableName>;
|
|
66
|
+
<IndexName extends keyof Indexes<_ConvexTableInfo>>(
|
|
67
|
+
indexName: IndexName,
|
|
68
|
+
order?: "asc" | "desc",
|
|
69
|
+
): OrderedQuery.OrderedQuery<_TableInfo, TableName>;
|
|
70
|
+
};
|
|
71
|
+
readonly search: <IndexName extends keyof SearchIndexes<_ConvexTableInfo>>(
|
|
72
|
+
indexName: IndexName,
|
|
73
|
+
searchFilter: (
|
|
74
|
+
q: SearchFilterBuilder<
|
|
75
|
+
DocumentByInfo<_ConvexTableInfo>,
|
|
76
|
+
NamedSearchIndex<_ConvexTableInfo, IndexName>
|
|
77
|
+
>,
|
|
78
|
+
) => SearchFilter,
|
|
79
|
+
) => OrderedQuery.OrderedQuery<_TableInfo, TableName>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const make = <
|
|
83
|
+
Tables extends Table.AnyWithProps,
|
|
84
|
+
TableName extends Table.Name<Tables>,
|
|
85
|
+
>(
|
|
86
|
+
tableName: TableName,
|
|
87
|
+
convexDatabaseReader: BaseDatabaseReader<
|
|
88
|
+
DataModel.ToConvex<DataModel.FromTables<Tables>>
|
|
89
|
+
>,
|
|
90
|
+
table: Table.WithName<Tables, TableName>,
|
|
91
|
+
): QueryInitializer<
|
|
92
|
+
DataModel.DataModel<Tables>,
|
|
93
|
+
TableName,
|
|
94
|
+
DataModel.TableInfoWithName<DataModel.DataModel<Tables>, TableName>,
|
|
95
|
+
DataModel.TableInfoWithName_<DataModel.DataModel<Tables>, TableName>
|
|
96
|
+
> => {
|
|
97
|
+
type DataModel_ = DataModel.DataModel<Tables>;
|
|
98
|
+
type ConvexDataModel_ = DataModel.ToConvex<DataModel_>;
|
|
99
|
+
type ThisQueryInitializer = QueryInitializer<
|
|
100
|
+
DataModel_,
|
|
101
|
+
TableName,
|
|
102
|
+
DataModel.TableInfoWithName<DataModel_, TableName>,
|
|
103
|
+
DataModel.TableInfoWithName_<DataModel_, TableName>
|
|
104
|
+
>;
|
|
105
|
+
type QueryInitializerFunction<
|
|
106
|
+
FunctionName extends keyof ThisQueryInitializer,
|
|
107
|
+
> = ThisQueryInitializer[FunctionName];
|
|
108
|
+
|
|
109
|
+
const getByIndex = <
|
|
110
|
+
IndexName extends keyof Indexes<
|
|
111
|
+
DataModel.TableInfoWithName<DataModel_, TableName>
|
|
112
|
+
>,
|
|
113
|
+
>(
|
|
114
|
+
indexName: IndexName,
|
|
115
|
+
indexFieldValues: IndexFieldTypesForEq<
|
|
116
|
+
DataModel.ToConvex<DataModel_>,
|
|
117
|
+
TableName,
|
|
118
|
+
Indexes<DataModel.TableInfoWithName<DataModel_, TableName>>[IndexName]
|
|
119
|
+
>,
|
|
120
|
+
): Effect.Effect<
|
|
121
|
+
DataModel.DocumentWithName<DataModel_, TableName>,
|
|
122
|
+
Document.DocumentDecodeError | GetByIndexFailure
|
|
123
|
+
> => {
|
|
124
|
+
const indexFields: GenericTableIndexes[keyof GenericTableIndexes] = (
|
|
125
|
+
table.indexes as GenericTableIndexes
|
|
126
|
+
)[indexName as keyof GenericTableIndexes]!;
|
|
127
|
+
|
|
128
|
+
return pipe(
|
|
129
|
+
Effect.promise(() =>
|
|
130
|
+
convexDatabaseReader
|
|
131
|
+
.query(tableName)
|
|
132
|
+
.withIndex(indexName, (q) =>
|
|
133
|
+
Array.reduce(
|
|
134
|
+
indexFieldValues,
|
|
135
|
+
q,
|
|
136
|
+
(q_, v, i) => q_.eq(indexFields[i] as any, v as any) as any,
|
|
137
|
+
),
|
|
138
|
+
)
|
|
139
|
+
.unique(),
|
|
140
|
+
),
|
|
141
|
+
Effect.andThen(
|
|
142
|
+
Either.fromNullable(
|
|
143
|
+
() =>
|
|
144
|
+
new GetByIndexFailure({
|
|
145
|
+
tableName,
|
|
146
|
+
indexName: indexName as string,
|
|
147
|
+
indexFieldValues: indexFieldValues as string[],
|
|
148
|
+
}),
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
Effect.andThen(Document.decode(tableName, table.Fields)),
|
|
152
|
+
);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const get: QueryInitializerFunction<"get"> = ((
|
|
156
|
+
...args: Parameters<QueryInitializerFunction<"get">>
|
|
157
|
+
) => {
|
|
158
|
+
if (args.length === 1) {
|
|
159
|
+
const id = args[0] as GenericId<TableName>;
|
|
160
|
+
|
|
161
|
+
return getById(tableName, convexDatabaseReader, table)(id);
|
|
162
|
+
} else {
|
|
163
|
+
const [indexName, ...indexFieldValues] = args;
|
|
164
|
+
|
|
165
|
+
return getByIndex(
|
|
166
|
+
indexName as keyof Indexes<
|
|
167
|
+
DataModel.TableInfoWithName<DataModel_, TableName>
|
|
168
|
+
>,
|
|
169
|
+
indexFieldValues,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}) as QueryInitializerFunction<"get">;
|
|
173
|
+
|
|
174
|
+
const index: QueryInitializerFunction<"index"> = <
|
|
175
|
+
IndexName extends keyof Indexes<
|
|
176
|
+
DataModel.TableInfoWithName<DataModel_, TableName>
|
|
177
|
+
>,
|
|
178
|
+
>(
|
|
179
|
+
indexName: IndexName,
|
|
180
|
+
indexRangeOrOrder?:
|
|
181
|
+
| ((
|
|
182
|
+
q: IndexRangeBuilder<
|
|
183
|
+
DataModel.TableInfoWithName_<
|
|
184
|
+
DataModel_,
|
|
185
|
+
TableName
|
|
186
|
+
>["convexDocument"],
|
|
187
|
+
NamedIndex<
|
|
188
|
+
DataModel.TableInfoWithName<DataModel_, TableName>,
|
|
189
|
+
IndexName
|
|
190
|
+
>
|
|
191
|
+
>,
|
|
192
|
+
) => IndexRange)
|
|
193
|
+
| "asc"
|
|
194
|
+
| "desc",
|
|
195
|
+
order?: "asc" | "desc",
|
|
196
|
+
) => {
|
|
197
|
+
const {
|
|
198
|
+
applyWithIndex,
|
|
199
|
+
applyOrder,
|
|
200
|
+
}: {
|
|
201
|
+
applyWithIndex: (
|
|
202
|
+
queryInitializer: ConvexQueryInitializer<
|
|
203
|
+
NamedTableInfo<ConvexDataModel_, TableName>
|
|
204
|
+
>,
|
|
205
|
+
) => Query<NamedTableInfo<ConvexDataModel_, TableName>>;
|
|
206
|
+
applyOrder: (
|
|
207
|
+
query: Query<NamedTableInfo<ConvexDataModel_, TableName>>,
|
|
208
|
+
) => ConvexOrderedQuery<NamedTableInfo<ConvexDataModel_, TableName>>;
|
|
209
|
+
} =
|
|
210
|
+
indexRangeOrOrder === undefined
|
|
211
|
+
? {
|
|
212
|
+
applyWithIndex: (q) => q.withIndex(indexName),
|
|
213
|
+
applyOrder: (q) => q.order("asc"),
|
|
214
|
+
}
|
|
215
|
+
: typeof indexRangeOrOrder === "function"
|
|
216
|
+
? order === undefined
|
|
217
|
+
? {
|
|
218
|
+
applyWithIndex: (q) =>
|
|
219
|
+
q.withIndex(indexName, indexRangeOrOrder),
|
|
220
|
+
applyOrder: (q) => q.order("asc"),
|
|
221
|
+
}
|
|
222
|
+
: {
|
|
223
|
+
applyWithIndex: (q) =>
|
|
224
|
+
q.withIndex(indexName, indexRangeOrOrder),
|
|
225
|
+
applyOrder: (q) => q.order(order),
|
|
226
|
+
}
|
|
227
|
+
: {
|
|
228
|
+
applyWithIndex: (q) => q.withIndex(indexName),
|
|
229
|
+
applyOrder: (q) => q.order(indexRangeOrOrder),
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const orderedQuery = pipe(
|
|
233
|
+
convexDatabaseReader.query(tableName),
|
|
234
|
+
applyWithIndex,
|
|
235
|
+
applyOrder,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return OrderedQuery.make<
|
|
239
|
+
DataModel.TableInfoWithName_<DataModel_, TableName>,
|
|
240
|
+
TableName
|
|
241
|
+
>(orderedQuery, tableName, table.Fields);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const search: QueryInitializerFunction<"search"> = (
|
|
245
|
+
indexName,
|
|
246
|
+
searchFilter,
|
|
247
|
+
) =>
|
|
248
|
+
OrderedQuery.make<
|
|
249
|
+
DataModel.TableInfoWithName_<DataModel_, TableName>,
|
|
250
|
+
TableName
|
|
251
|
+
>(
|
|
252
|
+
convexDatabaseReader
|
|
253
|
+
.query(tableName)
|
|
254
|
+
.withSearchIndex(indexName, searchFilter),
|
|
255
|
+
tableName,
|
|
256
|
+
table.Fields,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
get,
|
|
261
|
+
index,
|
|
262
|
+
search,
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export const getById =
|
|
267
|
+
<Tables extends Table.AnyWithProps, TableName extends Table.Name<Tables>>(
|
|
268
|
+
tableName: TableName,
|
|
269
|
+
convexDatabaseReader: BaseDatabaseReader<
|
|
270
|
+
DataModel.ToConvex<DataModel.FromTables<Tables>>
|
|
271
|
+
>,
|
|
272
|
+
table: Table.WithName<Tables, TableName>,
|
|
273
|
+
) =>
|
|
274
|
+
(id: GenericId<TableName>) =>
|
|
275
|
+
pipe(
|
|
276
|
+
Effect.promise(() => convexDatabaseReader.get(id)),
|
|
277
|
+
Effect.andThen(
|
|
278
|
+
Either.fromNullable(() => new GetByIdFailure({ tableName, id })),
|
|
279
|
+
),
|
|
280
|
+
Effect.andThen(Document.decode(tableName, table.Fields)),
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
export class GetByIdFailure extends Schema.TaggedError<GetByIdFailure>(
|
|
284
|
+
"GetByIdFailure",
|
|
285
|
+
)("GetByIdFailure", {
|
|
286
|
+
id: Schema.String,
|
|
287
|
+
tableName: Schema.String,
|
|
288
|
+
}) {
|
|
289
|
+
override get message(): string {
|
|
290
|
+
return Document.documentErrorMessage({
|
|
291
|
+
id: this.id,
|
|
292
|
+
tableName: this.tableName,
|
|
293
|
+
message: "not found",
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export class GetByIndexFailure extends Schema.TaggedError<GetByIndexFailure>(
|
|
299
|
+
"GetByIndexFailure",
|
|
300
|
+
)("GetByIndexFailure", {
|
|
301
|
+
tableName: Schema.String,
|
|
302
|
+
indexName: Schema.String,
|
|
303
|
+
indexFieldValues: Schema.Array(Schema.String),
|
|
304
|
+
}) {
|
|
305
|
+
override get message(): string {
|
|
306
|
+
return `No documents found in table '${this.tableName}' with index '${this.indexName}' and field values '${this.indexFieldValues}'`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as Ref from "@confect/core/Ref";
|
|
2
|
+
import { type GenericQueryCtx } from "convex/server";
|
|
3
|
+
import type { ParseResult } from "effect";
|
|
4
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
5
|
+
|
|
6
|
+
const make =
|
|
7
|
+
(runQuery: GenericQueryCtx<any>["runQuery"]) =>
|
|
8
|
+
<Query extends Ref.AnyQuery>(
|
|
9
|
+
query: Query,
|
|
10
|
+
args: Ref.Args<Query>["Type"],
|
|
11
|
+
): Effect.Effect<Ref.Returns<Query>["Type"], ParseResult.ParseError> =>
|
|
12
|
+
Effect.gen(function* () {
|
|
13
|
+
const function_ = Ref.getFunction(query);
|
|
14
|
+
const functionName = Ref.getConvexFunctionName(query);
|
|
15
|
+
|
|
16
|
+
const encodedArgs = yield* Schema.encode(function_.args)(args);
|
|
17
|
+
const encodedReturns = yield* Effect.promise(() =>
|
|
18
|
+
runQuery(functionName as any, encodedArgs),
|
|
19
|
+
);
|
|
20
|
+
return yield* Schema.decode(function_.returns)(encodedReturns);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const QueryRunner = Context.GenericTag<ReturnType<typeof make>>(
|
|
24
|
+
"@confect/server/QueryRunner",
|
|
25
|
+
);
|
|
26
|
+
export type QueryRunner = typeof QueryRunner.Identifier;
|
|
27
|
+
|
|
28
|
+
export const layer = (runQuery: GenericQueryCtx<any>["runQuery"]) =>
|
|
29
|
+
Layer.succeed(QueryRunner, make(runQuery));
|