@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.
Files changed (157) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +7 -0
  3. package/dist/ActionCtx.d.ts +12 -0
  4. package/dist/ActionCtx.d.ts.map +1 -0
  5. package/dist/ActionCtx.js +10 -0
  6. package/dist/ActionCtx.js.map +1 -0
  7. package/dist/ActionRunner.d.ts +15 -0
  8. package/dist/ActionRunner.d.ts.map +1 -0
  9. package/dist/ActionRunner.js +23 -0
  10. package/dist/ActionRunner.js.map +1 -0
  11. package/dist/Api.d.ts +27 -0
  12. package/dist/Api.d.ts.map +1 -0
  13. package/dist/Api.js +26 -0
  14. package/dist/Api.js.map +1 -0
  15. package/dist/Auth.d.ts +30 -0
  16. package/dist/Auth.d.ts.map +1 -0
  17. package/dist/Auth.js +24 -0
  18. package/dist/Auth.js.map +1 -0
  19. package/dist/DataModel.d.ts +33 -0
  20. package/dist/DataModel.d.ts.map +1 -0
  21. package/dist/DataModel.js +6 -0
  22. package/dist/DataModel.js.map +1 -0
  23. package/dist/DatabaseReader.d.ts +73 -0
  24. package/dist/DatabaseReader.d.ts.map +1 -0
  25. package/dist/DatabaseReader.js +32 -0
  26. package/dist/DatabaseReader.js.map +1 -0
  27. package/dist/DatabaseSchema.d.ts +139 -0
  28. package/dist/DatabaseSchema.d.ts.map +1 -0
  29. package/dist/DatabaseSchema.js +45 -0
  30. package/dist/DatabaseSchema.js.map +1 -0
  31. package/dist/DatabaseWriter.d.ts +39 -0
  32. package/dist/DatabaseWriter.d.ts.map +1 -0
  33. package/dist/DatabaseWriter.js +43 -0
  34. package/dist/DatabaseWriter.js.map +1 -0
  35. package/dist/Document.d.ts +47 -0
  36. package/dist/Document.d.ts.map +1 -0
  37. package/dist/Document.js +66 -0
  38. package/dist/Document.js.map +1 -0
  39. package/dist/FunctionImpl.d.ts +34 -0
  40. package/dist/FunctionImpl.d.ts.map +1 -0
  41. package/dist/FunctionImpl.js +35 -0
  42. package/dist/FunctionImpl.js.map +1 -0
  43. package/dist/GroupImpl.d.ts +24 -0
  44. package/dist/GroupImpl.d.ts.map +1 -0
  45. package/dist/GroupImpl.js +14 -0
  46. package/dist/GroupImpl.js.map +1 -0
  47. package/dist/Handler.d.ts +31 -0
  48. package/dist/Handler.d.ts.map +1 -0
  49. package/dist/Handler.js +6 -0
  50. package/dist/Handler.js.map +1 -0
  51. package/dist/HttpApi.d.ts +26 -0
  52. package/dist/HttpApi.d.ts.map +1 -0
  53. package/dist/HttpApi.js +74 -0
  54. package/dist/HttpApi.js.map +1 -0
  55. package/dist/Impl.d.ts +24 -0
  56. package/dist/Impl.d.ts.map +1 -0
  57. package/dist/Impl.js +28 -0
  58. package/dist/Impl.js.map +1 -0
  59. package/dist/MutationCtx.d.ts +12 -0
  60. package/dist/MutationCtx.d.ts.map +1 -0
  61. package/dist/MutationCtx.js +10 -0
  62. package/dist/MutationCtx.js.map +1 -0
  63. package/dist/MutationRunner.d.ts +24 -0
  64. package/dist/MutationRunner.d.ts.map +1 -0
  65. package/dist/MutationRunner.js +33 -0
  66. package/dist/MutationRunner.js.map +1 -0
  67. package/dist/OrderedQuery.d.ts +23 -0
  68. package/dist/OrderedQuery.d.ts.map +1 -0
  69. package/dist/OrderedQuery.js +34 -0
  70. package/dist/OrderedQuery.js.map +1 -0
  71. package/dist/QueryCtx.d.ts +12 -0
  72. package/dist/QueryCtx.d.ts.map +1 -0
  73. package/dist/QueryCtx.js +10 -0
  74. package/dist/QueryCtx.js.map +1 -0
  75. package/dist/QueryInitializer.d.ts +49 -0
  76. package/dist/QueryInitializer.d.ts.map +1 -0
  77. package/dist/QueryInitializer.js +83 -0
  78. package/dist/QueryInitializer.js.map +1 -0
  79. package/dist/QueryRunner.d.ts +14 -0
  80. package/dist/QueryRunner.d.ts.map +1 -0
  81. package/dist/QueryRunner.js +23 -0
  82. package/dist/QueryRunner.js.map +1 -0
  83. package/dist/RegisteredFunctions.d.ts +66 -0
  84. package/dist/RegisteredFunctions.d.ts.map +1 -0
  85. package/dist/RegisteredFunctions.js +71 -0
  86. package/dist/RegisteredFunctions.js.map +1 -0
  87. package/dist/Registry.d.ts +15 -0
  88. package/dist/Registry.d.ts.map +1 -0
  89. package/dist/Registry.js +10 -0
  90. package/dist/Registry.js.map +1 -0
  91. package/dist/RegistryItem.d.ts +31 -0
  92. package/dist/RegistryItem.d.ts.map +1 -0
  93. package/dist/RegistryItem.js +20 -0
  94. package/dist/RegistryItem.js.map +1 -0
  95. package/dist/Scheduler.d.ts +23 -0
  96. package/dist/Scheduler.d.ts.map +1 -0
  97. package/dist/Scheduler.js +24 -0
  98. package/dist/Scheduler.js.map +1 -0
  99. package/dist/SchemaToValidator.d.ts +88 -0
  100. package/dist/SchemaToValidator.d.ts.map +1 -0
  101. package/dist/SchemaToValidator.js +155 -0
  102. package/dist/SchemaToValidator.js.map +1 -0
  103. package/dist/Storage.d.ts +69 -0
  104. package/dist/Storage.d.ts.map +1 -0
  105. package/dist/Storage.js +46 -0
  106. package/dist/Storage.js.map +1 -0
  107. package/dist/Table.d.ts +247 -0
  108. package/dist/Table.d.ts.map +1 -0
  109. package/dist/Table.js +97 -0
  110. package/dist/Table.js.map +1 -0
  111. package/dist/TableInfo.d.ts +48 -0
  112. package/dist/TableInfo.d.ts.map +1 -0
  113. package/dist/TableInfo.js +6 -0
  114. package/dist/TableInfo.js.map +1 -0
  115. package/dist/VectorSearch.d.ts +42 -0
  116. package/dist/VectorSearch.d.ts.map +1 -0
  117. package/dist/VectorSearch.js +16 -0
  118. package/dist/VectorSearch.js.map +1 -0
  119. package/dist/_virtual/rolldown_runtime.js +13 -0
  120. package/dist/index.d.ts +30 -0
  121. package/dist/index.js +31 -0
  122. package/dist/internal/utils.d.ts +15 -0
  123. package/dist/internal/utils.d.ts.map +1 -0
  124. package/dist/internal/utils.js +49 -0
  125. package/dist/internal/utils.js.map +1 -0
  126. package/package.json +90 -0
  127. package/src/ActionCtx.ts +9 -0
  128. package/src/ActionRunner.ts +28 -0
  129. package/src/Api.ts +63 -0
  130. package/src/Auth.ts +31 -0
  131. package/src/DataModel.ts +69 -0
  132. package/src/DatabaseReader.ts +75 -0
  133. package/src/DatabaseSchema.ts +134 -0
  134. package/src/DatabaseWriter.ts +166 -0
  135. package/src/Document.ts +200 -0
  136. package/src/FunctionImpl.ts +112 -0
  137. package/src/GroupImpl.ts +60 -0
  138. package/src/Handler.ts +105 -0
  139. package/src/HttpApi.ts +232 -0
  140. package/src/Impl.ts +57 -0
  141. package/src/MutationCtx.ts +11 -0
  142. package/src/MutationRunner.ts +41 -0
  143. package/src/OrderedQuery.ts +109 -0
  144. package/src/QueryCtx.ts +9 -0
  145. package/src/QueryInitializer.ts +308 -0
  146. package/src/QueryRunner.ts +29 -0
  147. package/src/RegisteredFunctions.ts +381 -0
  148. package/src/Registry.ts +13 -0
  149. package/src/RegistryItem.ts +44 -0
  150. package/src/Scheduler.ts +39 -0
  151. package/src/SchemaToValidator.ts +619 -0
  152. package/src/Storage.ts +86 -0
  153. package/src/Table.ts +439 -0
  154. package/src/TableInfo.ts +91 -0
  155. package/src/VectorSearch.ts +46 -0
  156. package/src/index.ts +29 -0
  157. 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
+ };
@@ -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));