effect 4.0.0-beta.62 → 4.0.0-beta.64
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/dist/Effect.d.ts +38 -0
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +38 -0
- package/dist/Effect.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/effect.js +2 -0
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.js +11 -7
- package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiClient.js +2 -1
- package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiTest.d.ts +20 -0
- package/dist/unstable/httpapi/HttpApiTest.d.ts.map +1 -0
- package/dist/unstable/httpapi/HttpApiTest.js +54 -0
- package/dist/unstable/httpapi/HttpApiTest.js.map +1 -0
- package/dist/unstable/httpapi/index.d.ts +4 -0
- package/dist/unstable/httpapi/index.d.ts.map +1 -1
- package/dist/unstable/httpapi/index.js +4 -0
- package/dist/unstable/httpapi/index.js.map +1 -1
- package/dist/unstable/sql/SqlModel.d.ts +4 -2
- package/dist/unstable/sql/SqlModel.d.ts.map +1 -1
- package/dist/unstable/sql/SqlModel.js +16 -10
- package/dist/unstable/sql/SqlModel.js.map +1 -1
- package/package.json +1 -1
- package/src/Effect.ts +41 -0
- package/src/index.ts +1 -1
- package/src/internal/effect.ts +9 -0
- package/src/unstable/httpapi/HttpApiBuilder.ts +14 -8
- package/src/unstable/httpapi/HttpApiClient.ts +4 -3
- package/src/unstable/httpapi/HttpApiTest.ts +95 -0
- package/src/unstable/httpapi/index.ts +5 -0
- package/src/unstable/sql/SqlModel.ts +52 -21
|
@@ -13,12 +13,15 @@ export const makeRepository = (Model, options) => Effect.gen(function* () {
|
|
|
13
13
|
const sql = yield* SqlClient;
|
|
14
14
|
const idSchema = Model.fields[options.idColumn];
|
|
15
15
|
const idColumn = options.idColumn;
|
|
16
|
+
const softDeleteColumn = options.softDeleteColumn;
|
|
17
|
+
const withSoftDeleteFilter = where => softDeleteColumn === undefined ? where : sql.and([where, sql`${sql(softDeleteColumn)} is null`]);
|
|
18
|
+
const setSoftDeleted = softDeleteColumn === undefined ? undefined : sql`${sql(softDeleteColumn)} = CURRENT_TIMESTAMP`;
|
|
16
19
|
const insertSchema = SqlSchema.findOne({
|
|
17
20
|
Request: Model.insert,
|
|
18
21
|
Result: Model,
|
|
19
22
|
execute: request => sql.onDialectOrElse({
|
|
20
23
|
mysql: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
|
|
21
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID();`.unprepared.pipe(Effect.map(([, results]) => results)),
|
|
24
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = LAST_INSERT_ID()`)};`.unprepared.pipe(Effect.map(([, results]) => results)),
|
|
22
25
|
orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
|
|
23
26
|
})
|
|
24
27
|
});
|
|
@@ -36,9 +39,9 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
|
|
|
36
39
|
Request: Model.update,
|
|
37
40
|
Result: Model,
|
|
38
41
|
execute: request => sql.onDialectOrElse({
|
|
39
|
-
mysql: () => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${sql(idColumn)} = ${request[idColumn]};
|
|
40
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idColumn]};`.unprepared.pipe(Effect.map(([, results]) => results)),
|
|
41
|
-
orElse: () => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${sql(idColumn)} = ${request[idColumn]} returning *`
|
|
42
|
+
mysql: () => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)};
|
|
43
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)};`.unprepared.pipe(Effect.map(([, results]) => results)),
|
|
44
|
+
orElse: () => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)} returning *`
|
|
42
45
|
})
|
|
43
46
|
});
|
|
44
47
|
const update = update => updateSchema(update).pipe(Effect.catchTag("NoSuchElementError", Effect.die), Effect.withSpan(`${options.spanPrefix}.update`, {
|
|
@@ -50,7 +53,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
50
53
|
}));
|
|
51
54
|
const updateVoidSchema = SqlSchema.void({
|
|
52
55
|
Request: Model.update,
|
|
53
|
-
execute: request => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${sql(idColumn)} = ${request[idColumn]}`
|
|
56
|
+
execute: request => sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)}`
|
|
54
57
|
});
|
|
55
58
|
const updateVoid = update => updateVoidSchema(update).pipe(Effect.withSpan(`${options.spanPrefix}.updateVoid`, {
|
|
56
59
|
attributes: {
|
|
@@ -62,7 +65,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
62
65
|
const findByIdSchema = SqlSchema.findOne({
|
|
63
66
|
Request: idSchema,
|
|
64
67
|
Result: Model,
|
|
65
|
-
execute: id => sql`select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}`
|
|
68
|
+
execute: id => sql`select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${id}`)}`
|
|
66
69
|
});
|
|
67
70
|
const findById = id => findByIdSchema(id).pipe(Effect.withSpan(`${options.spanPrefix}.findById`, {
|
|
68
71
|
attributes: {
|
|
@@ -73,7 +76,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
73
76
|
}));
|
|
74
77
|
const deleteSchema = SqlSchema.void({
|
|
75
78
|
Request: idSchema,
|
|
76
|
-
execute: id => sql`delete from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}`
|
|
79
|
+
execute: id => softDeleteColumn === undefined ? sql`delete from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}` : sql`update ${sql(options.tableName)} set ${setSoftDeleted} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${id}`)}`
|
|
77
80
|
});
|
|
78
81
|
const delete_ = id => deleteSchema(id).pipe(Effect.withSpan(`${options.spanPrefix}.delete`, {
|
|
79
82
|
attributes: {
|
|
@@ -101,12 +104,15 @@ export const makeResolvers = (Model, options) => Effect.gen(function* () {
|
|
|
101
104
|
const sql = yield* SqlClient;
|
|
102
105
|
const idSchema = Model.fields[options.idColumn];
|
|
103
106
|
const idColumn = options.idColumn;
|
|
107
|
+
const softDeleteColumn = options.softDeleteColumn;
|
|
108
|
+
const withSoftDeleteFilter = where => softDeleteColumn === undefined ? where : sql.and([where, sql`${sql(softDeleteColumn)} is null`]);
|
|
109
|
+
const setSoftDeleted = softDeleteColumn === undefined ? undefined : sql`${sql(softDeleteColumn)} = CURRENT_TIMESTAMP`;
|
|
104
110
|
const insert = SqlResolver.ordered({
|
|
105
111
|
Request: Model.insert,
|
|
106
112
|
Result: Model,
|
|
107
113
|
execute: request => sql.onDialectOrElse({
|
|
108
114
|
mysql: () => Effect.forEach(request, request => sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
|
|
109
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID();`.unprepared.pipe(Effect.map(([, results]) => results[0])), {
|
|
115
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = LAST_INSERT_ID()`)};`.unprepared.pipe(Effect.map(([, results]) => results[0])), {
|
|
110
116
|
concurrency: 10
|
|
111
117
|
}),
|
|
112
118
|
orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
|
|
@@ -122,11 +128,11 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
|
|
|
122
128
|
ResultId(request) {
|
|
123
129
|
return request[idColumn];
|
|
124
130
|
},
|
|
125
|
-
execute: ids => sql`select * from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
|
|
131
|
+
execute: ids => sql`select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql.in(idColumn, ids))}`
|
|
126
132
|
}).pipe(RequestResolver.withSpan(`${options.spanPrefix}.findByIdResolver`));
|
|
127
133
|
const delete_ = SqlResolver.void({
|
|
128
134
|
Request: idSchema,
|
|
129
|
-
execute: ids => sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
|
|
135
|
+
execute: ids => softDeleteColumn === undefined ? sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}` : sql`update ${sql(options.tableName)} set ${setSoftDeleted} where ${withSoftDeleteFilter(sql.in(idColumn, ids))}`
|
|
130
136
|
}).pipe(RequestResolver.withSpan(`${options.spanPrefix}.deleteResolver`));
|
|
131
137
|
return {
|
|
132
138
|
insert,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlModel.js","names":["Effect","RequestResolver","SqlClient","SqlResolver","SqlSchema","makeRepository","Model","options","gen","sql","idSchema","fields","idColumn","insertSchema","findOne","Request","insert","Result","execute","request","onDialectOrElse","mysql","tableName","unprepared","pipe","map","results","orElse","returning","catchTag","die","withSpan","spanPrefix","captureStackTrace","insertVoidSchema","void","insertVoid","updateSchema","update","attributes","id","updateVoidSchema","updateVoid","findByIdSchema","findById","deleteSchema","delete_","delete","makeResolvers","ordered","forEach","concurrency","Id","ResultId","ids","in"],"sources":["../../../src/unstable/sql/SqlModel.ts"],"sourcesContent":[null],"mappings":"AAKA,OAAO,KAAKA,MAAM,MAAM,iBAAiB;AACzC,OAAO,KAAKC,eAAe,MAAM,0BAA0B;AAI3D,SAASC,SAAS,QAAQ,gBAAgB;AAE1C,OAAO,KAAKC,WAAW,MAAM,kBAAkB;AAC/C,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;;;;AAMA,OAAO,MAAMC,cAAc,GAAGA,
|
|
1
|
+
{"version":3,"file":"SqlModel.js","names":["Effect","RequestResolver","SqlClient","SqlResolver","SqlSchema","makeRepository","Model","options","gen","sql","idSchema","fields","idColumn","softDeleteColumn","withSoftDeleteFilter","where","undefined","and","setSoftDeleted","insertSchema","findOne","Request","insert","Result","execute","request","onDialectOrElse","mysql","tableName","unprepared","pipe","map","results","orElse","returning","catchTag","die","withSpan","spanPrefix","captureStackTrace","insertVoidSchema","void","insertVoid","updateSchema","update","attributes","id","updateVoidSchema","updateVoid","findByIdSchema","findById","deleteSchema","delete_","delete","makeResolvers","ordered","forEach","concurrency","Id","ResultId","ids","in"],"sources":["../../../src/unstable/sql/SqlModel.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
package/src/Effect.ts
CHANGED
|
@@ -12039,6 +12039,47 @@ export const acquireRelease: <A, E, R, R2>(
|
|
|
12039
12039
|
options?: { readonly interruptible?: boolean }
|
|
12040
12040
|
) => Effect<A, E, R | R2 | Scope> = internal.acquireRelease
|
|
12041
12041
|
|
|
12042
|
+
/**
|
|
12043
|
+
* This function constructs a scoped resource from an Effect that acquires a
|
|
12044
|
+
* disposable value.
|
|
12045
|
+
*
|
|
12046
|
+
* The resource is automatically disposed when the surrounding
|
|
12047
|
+
* {@link Scope} is closed, using {@link Symbol.dispose} for
|
|
12048
|
+
* synchronous disposables or {@link Symbol.asyncDispose} for asynchronous
|
|
12049
|
+
* disposables.
|
|
12050
|
+
*
|
|
12051
|
+
* This is similar to {@link acquireRelease}, but uses the standard
|
|
12052
|
+
* JavaScript disposal protocal instead of requiring an explicit release
|
|
12053
|
+
* function.
|
|
12054
|
+
*
|
|
12055
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using}
|
|
12056
|
+
*
|
|
12057
|
+
* @example
|
|
12058
|
+
* ```ts
|
|
12059
|
+
* import sqlite from "node:sqlite";
|
|
12060
|
+
* import { Effect } from "effect";
|
|
12061
|
+
*
|
|
12062
|
+
* const program = Effect.scoped(
|
|
12063
|
+
* Effect.gen(function* () {
|
|
12064
|
+
* // acquire database connection
|
|
12065
|
+
* // database will be closed when the scope is closed
|
|
12066
|
+
* const db = yield* Effect.acquireDisposable(
|
|
12067
|
+
* Effect.sync(() => new sqlite.DatabaseSync(":memory:"))
|
|
12068
|
+
* )
|
|
12069
|
+
*
|
|
12070
|
+
* const row = db.prepare("SELECT 1 AS value").get()
|
|
12071
|
+
* yield* Effect.log(row) // { value: 1 }
|
|
12072
|
+
* })
|
|
12073
|
+
* )
|
|
12074
|
+
* ```
|
|
12075
|
+
*
|
|
12076
|
+
* @since 4.0.0
|
|
12077
|
+
* @category Resource Management & Finalization
|
|
12078
|
+
*/
|
|
12079
|
+
export const acquireDisposable: <A extends AsyncDisposable | Disposable, E, R>(
|
|
12080
|
+
acquire: Effect<A, E, R>
|
|
12081
|
+
) => Effect<A, E, R | Scope> = internal.acquireDisposable
|
|
12082
|
+
|
|
12042
12083
|
/**
|
|
12043
12084
|
* This function is used to ensure that an `Effect` value that represents the
|
|
12044
12085
|
* acquisition of a resource (for example, opening a file, launching a thread,
|
package/src/index.ts
CHANGED
|
@@ -3796,7 +3796,7 @@ export * as SchemaRepresentation from "./SchemaRepresentation.ts"
|
|
|
3796
3796
|
* - Trim/case strings → {@link trim}, {@link toLowerCase}, {@link toUpperCase}, {@link capitalize}, {@link uncapitalize}, {@link snakeToCamel}
|
|
3797
3797
|
* - Parse key-value strings → {@link splitKeyValue}
|
|
3798
3798
|
* - Coerce string ↔ number/bigint → {@link numberFromString}, {@link bigintFromString}
|
|
3799
|
-
* - Coerce string ↔ Date → {@link dateFromString}
|
|
3799
|
+
* - Coerce string ↔ Date/Duration → {@link dateFromString}, {@link durationFromString}
|
|
3800
3800
|
* - Decode durations → {@link durationFromNanos}, {@link durationFromMillis}
|
|
3801
3801
|
* - Wrap nullable/optional as Option → {@link optionFromNullOr}, {@link optionFromOptionalKey}, {@link optionFromOptional}
|
|
3802
3802
|
* - Parse URLs → {@link urlFromString}
|
package/src/internal/effect.ts
CHANGED
|
@@ -4053,6 +4053,15 @@ export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
|
|
|
4053
4053
|
))
|
|
4054
4054
|
)
|
|
4055
4055
|
|
|
4056
|
+
/** @internal */
|
|
4057
|
+
export const acquireDisposable = <A extends AsyncDisposable | Disposable, E, R>(
|
|
4058
|
+
acquire: Effect.Effect<A, E, R>
|
|
4059
|
+
): Effect.Effect<A, E, R | Scope.Scope> =>
|
|
4060
|
+
acquireRelease(acquire, (resource) =>
|
|
4061
|
+
hasProperty(resource, Symbol.asyncDispose)
|
|
4062
|
+
? promise(() => resource[Symbol.asyncDispose]())
|
|
4063
|
+
: sync(() => resource[Symbol.dispose]()))
|
|
4064
|
+
|
|
4056
4065
|
// ----------------------------------------------------------------------------
|
|
4057
4066
|
// Caching
|
|
4058
4067
|
// ----------------------------------------------------------------------------
|
|
@@ -77,7 +77,7 @@ export const layer = <Id extends string, Groups extends HttpApiGroup.Any>(
|
|
|
77
77
|
key.startsWith("effect/httpapi/HttpApiGroup/")
|
|
78
78
|
)
|
|
79
79
|
for (const group of Object.values(api.groups)) {
|
|
80
|
-
const groupRoutes = services.mapUnsafe.get(group.key) as Array<HttpRouter.Route<any, any>>
|
|
80
|
+
const groupRoutes = services.mapUnsafe.get(group.key)?.routes as Array<HttpRouter.Route<any, any>>
|
|
81
81
|
if (groupRoutes === undefined) {
|
|
82
82
|
const available = availableGroups.length === 0 ? "none" : availableGroups.join(", ")
|
|
83
83
|
return yield* Effect.die(
|
|
@@ -130,10 +130,15 @@ export const group = <
|
|
|
130
130
|
? (yield* result as Effect.Effect<any, any, any>)
|
|
131
131
|
: result
|
|
132
132
|
const routes: Array<HttpRouter.Route<any, any>> = []
|
|
133
|
-
for (const item of handlers.handlers) {
|
|
133
|
+
for (const item of handlers.handlers.values()) {
|
|
134
134
|
routes.push(handlerToRoute(group as any, item, services))
|
|
135
135
|
}
|
|
136
|
-
return Context.makeUnsafe(
|
|
136
|
+
return Context.makeUnsafe(
|
|
137
|
+
new Map([[group.key, {
|
|
138
|
+
routes,
|
|
139
|
+
handlers: handlers.handlers
|
|
140
|
+
}]])
|
|
141
|
+
)
|
|
137
142
|
})) as any
|
|
138
143
|
|
|
139
144
|
/**
|
|
@@ -162,7 +167,7 @@ export interface Handlers<
|
|
|
162
167
|
_Endpoints: Covariant<Endpoints>
|
|
163
168
|
}
|
|
164
169
|
readonly group: HttpApiGroup.AnyWithProps
|
|
165
|
-
readonly handlers:
|
|
170
|
+
readonly handlers: Map<string, Handlers.Item<R>>
|
|
166
171
|
|
|
167
172
|
/**
|
|
168
173
|
* Add the implementation for an `HttpApiEndpoint` to a `Handlers` group.
|
|
@@ -449,7 +454,7 @@ const HandlersProto = {
|
|
|
449
454
|
options?: { readonly uninterruptible?: boolean | undefined } | undefined
|
|
450
455
|
) {
|
|
451
456
|
const endpoint = this.group.endpoints[name]
|
|
452
|
-
this.handlers.
|
|
457
|
+
this.handlers.set(name, {
|
|
453
458
|
endpoint,
|
|
454
459
|
handler,
|
|
455
460
|
isRaw: false,
|
|
@@ -464,7 +469,7 @@ const HandlersProto = {
|
|
|
464
469
|
options?: { readonly uninterruptible?: boolean | undefined } | undefined
|
|
465
470
|
) {
|
|
466
471
|
const endpoint = this.group.endpoints[name]
|
|
467
|
-
this.handlers.
|
|
472
|
+
this.handlers.set(name, {
|
|
468
473
|
endpoint,
|
|
469
474
|
handler,
|
|
470
475
|
isRaw: true,
|
|
@@ -479,7 +484,7 @@ const makeHandlers = <R, Endpoints extends HttpApiEndpoint.Any>(
|
|
|
479
484
|
): Handlers<R, Endpoints> => {
|
|
480
485
|
const self = Object.create(HandlersProto)
|
|
481
486
|
self.group = group
|
|
482
|
-
self.handlers = new
|
|
487
|
+
self.handlers = new Map<string, Handlers.Item<R>>()
|
|
483
488
|
return self
|
|
484
489
|
}
|
|
485
490
|
|
|
@@ -632,7 +637,8 @@ function handlerToHttpEffect(
|
|
|
632
637
|
)
|
|
633
638
|
}
|
|
634
639
|
|
|
635
|
-
|
|
640
|
+
/** @internal */
|
|
641
|
+
export function handlerToRoute(
|
|
636
642
|
group: HttpApiGroup.AnyWithProps,
|
|
637
643
|
handler: Handlers.Item<any>,
|
|
638
644
|
context: Context.Context<any>
|
|
@@ -175,7 +175,8 @@ type UrlBuilderTopLevelMethods<Groups extends HttpApiGroup.Any> = Extract<Groups
|
|
|
175
175
|
: never :
|
|
176
176
|
never
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
/** @internal */
|
|
179
|
+
export const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>(
|
|
179
180
|
api: HttpApi.HttpApi<ApiId, Groups>,
|
|
180
181
|
options: {
|
|
181
182
|
readonly httpClient: HttpClient.HttpClient.With<E, R>
|
|
@@ -201,9 +202,9 @@ const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>
|
|
|
201
202
|
| undefined
|
|
202
203
|
readonly baseUrl?: URL | string | undefined
|
|
203
204
|
}
|
|
204
|
-
): Effect.Effect<void
|
|
205
|
+
): Effect.Effect<void> =>
|
|
205
206
|
Effect.gen(function*() {
|
|
206
|
-
const services = yield* Effect.context
|
|
207
|
+
const services = yield* Effect.context()
|
|
207
208
|
|
|
208
209
|
const httpClient = options.httpClient.pipe(
|
|
209
210
|
options?.baseUrl === undefined
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 4.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as Context from "../../Context.ts"
|
|
5
|
+
import * as Effect from "../../Effect.ts"
|
|
6
|
+
import type { FileSystem } from "../../FileSystem.ts"
|
|
7
|
+
import * as Layer from "../../Layer.ts"
|
|
8
|
+
import type { Path } from "../../Path.ts"
|
|
9
|
+
import type { Scope } from "../../Scope.ts"
|
|
10
|
+
import type { Generator } from "../http/Etag.ts"
|
|
11
|
+
import * as HttpClient from "../http/HttpClient.ts"
|
|
12
|
+
import type { HttpPlatform } from "../http/HttpPlatform.ts"
|
|
13
|
+
import * as HttpRouter from "../http/HttpRouter.ts"
|
|
14
|
+
import * as HttpServerRequest from "../http/HttpServerRequest.ts"
|
|
15
|
+
import * as HttpServerResponse from "../http/HttpServerResponse.ts"
|
|
16
|
+
import type * as HttpApi from "./HttpApi.ts"
|
|
17
|
+
import type { Handlers } from "./HttpApiBuilder.ts"
|
|
18
|
+
import * as HttpApiBuilder from "./HttpApiBuilder.ts"
|
|
19
|
+
import * as HttpApiClient from "./HttpApiClient.ts"
|
|
20
|
+
import type * as HttpApiEndpoint from "./HttpApiEndpoint.ts"
|
|
21
|
+
import type * as HttpApiGroup from "./HttpApiGroup.ts"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @since 4.0.0
|
|
25
|
+
* @category Testing
|
|
26
|
+
*/
|
|
27
|
+
export const groups = Effect.fnUntraced(function*<
|
|
28
|
+
ApiId extends string,
|
|
29
|
+
Groups extends HttpApiGroup.Any,
|
|
30
|
+
const Names extends ReadonlyArray<HttpApiGroup.Name<Groups>>,
|
|
31
|
+
SelectedGroups = HttpApiGroup.WithName<Groups, Names[number]>
|
|
32
|
+
>(
|
|
33
|
+
api: HttpApi.HttpApi<ApiId, Groups>,
|
|
34
|
+
groupNames: Names
|
|
35
|
+
): Effect.fn.Return<
|
|
36
|
+
HttpApiClient.Client<Groups>,
|
|
37
|
+
never,
|
|
38
|
+
| HttpApiGroup.ToService<ApiId, SelectedGroups>
|
|
39
|
+
| HttpApiGroup.MiddlewareClient<Groups>
|
|
40
|
+
| HttpApiEndpoint.Middleware<HttpApiGroup.Endpoints<Groups>>
|
|
41
|
+
| FileSystem
|
|
42
|
+
| Generator
|
|
43
|
+
| HttpPlatform
|
|
44
|
+
| Path
|
|
45
|
+
| Scope
|
|
46
|
+
> {
|
|
47
|
+
let context = yield* Effect.context<HttpApiGroup.ToService<ApiId, SelectedGroups>>()
|
|
48
|
+
|
|
49
|
+
for (const name in api.groups) {
|
|
50
|
+
const group = api.groups[name]
|
|
51
|
+
if (groupNames.includes(name as any)) {
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
const handlers = new Map<string, Handlers.Item<never>>()
|
|
55
|
+
const routes: Array<HttpRouter.Route<any, any>> = []
|
|
56
|
+
for (const endpointName in group.endpoints) {
|
|
57
|
+
const endpoint = group.endpoints[endpointName]
|
|
58
|
+
const handler: Handlers.Item<never> = {
|
|
59
|
+
endpoint: endpoint as any,
|
|
60
|
+
handler: () => Effect.die(new Error(`Unhandled endpoint: ${endpointName}`)),
|
|
61
|
+
isRaw: false,
|
|
62
|
+
uninterruptible: false
|
|
63
|
+
}
|
|
64
|
+
handlers.set(endpointName, handler)
|
|
65
|
+
routes.push(HttpApiBuilder.handlerToRoute(group as any, handler, context))
|
|
66
|
+
}
|
|
67
|
+
context = Context.add(context, group as any, { handlers, routes })
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const layer: Layer.Layer<
|
|
71
|
+
never,
|
|
72
|
+
never,
|
|
73
|
+
| FileSystem
|
|
74
|
+
| Generator
|
|
75
|
+
| HttpPlatform
|
|
76
|
+
| HttpRouter.HttpRouter
|
|
77
|
+
| Path
|
|
78
|
+
> = HttpApiBuilder.layer(api).pipe(
|
|
79
|
+
Layer.provide(Layer.succeedContext(context))
|
|
80
|
+
) as any
|
|
81
|
+
const handler = yield* HttpRouter.toHttpEffect(layer)
|
|
82
|
+
const httpClient = HttpClient.make(Effect.fnUntraced(function*(request) {
|
|
83
|
+
const serverRequest = HttpServerRequest.fromClientRequest(request)
|
|
84
|
+
const response = yield* handler.pipe(
|
|
85
|
+
Effect.provideService(HttpServerRequest.HttpServerRequest, serverRequest),
|
|
86
|
+
Effect.orDie
|
|
87
|
+
)
|
|
88
|
+
return HttpServerResponse.toClientResponse(response)
|
|
89
|
+
}, Effect.scoped))
|
|
90
|
+
|
|
91
|
+
return yield* HttpApiClient.makeWith(api, {
|
|
92
|
+
httpClient,
|
|
93
|
+
baseUrl: "http://localhost:3000"
|
|
94
|
+
})
|
|
95
|
+
})
|
|
@@ -21,11 +21,13 @@ import * as SqlSchema from "./SqlSchema.ts"
|
|
|
21
21
|
*/
|
|
22
22
|
export const makeRepository = <
|
|
23
23
|
S extends Model.Any,
|
|
24
|
-
Id extends (keyof S["Type"]) & (keyof S["update"]["Type"]) & (keyof S["fields"])
|
|
24
|
+
Id extends (keyof S["Type"]) & (keyof S["update"]["Type"]) & (keyof S["fields"]),
|
|
25
|
+
SoftDelete extends keyof S["fields"] = never
|
|
25
26
|
>(Model: S, options: {
|
|
26
27
|
readonly tableName: string
|
|
27
28
|
readonly spanPrefix: string
|
|
28
29
|
readonly idColumn: Id
|
|
30
|
+
readonly softDeleteColumn?: SoftDelete | undefined
|
|
29
31
|
}): Effect.Effect<
|
|
30
32
|
{
|
|
31
33
|
readonly insert: (
|
|
@@ -66,6 +68,12 @@ export const makeRepository = <
|
|
|
66
68
|
const sql = yield* SqlClient
|
|
67
69
|
const idSchema = Model.fields[options.idColumn] as Schema.Top
|
|
68
70
|
const idColumn = options.idColumn as string
|
|
71
|
+
const softDeleteColumn = options.softDeleteColumn as string | undefined
|
|
72
|
+
const withSoftDeleteFilter = (where: any) =>
|
|
73
|
+
softDeleteColumn === undefined ? where : sql.and([where, sql`${sql(softDeleteColumn)} is null`])
|
|
74
|
+
const setSoftDeleted = softDeleteColumn === undefined
|
|
75
|
+
? undefined
|
|
76
|
+
: sql`${sql(softDeleteColumn)} = CURRENT_TIMESTAMP`
|
|
69
77
|
|
|
70
78
|
const insertSchema = SqlSchema.findOne({
|
|
71
79
|
Request: Model.insert,
|
|
@@ -74,9 +82,10 @@ export const makeRepository = <
|
|
|
74
82
|
sql.onDialectOrElse({
|
|
75
83
|
mysql: () =>
|
|
76
84
|
sql`insert into ${sql(options.tableName)} ${sql.insert(request as any)};
|
|
77
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID()
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = LAST_INSERT_ID()`)};`
|
|
86
|
+
.unprepared.pipe(
|
|
87
|
+
Effect.map(([, results]) => results as any)
|
|
88
|
+
),
|
|
80
89
|
orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request as any).returning("*")}`
|
|
81
90
|
})
|
|
82
91
|
})
|
|
@@ -111,15 +120,16 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
|
|
|
111
120
|
execute: (request: any) =>
|
|
112
121
|
sql.onDialectOrElse({
|
|
113
122
|
mysql: () =>
|
|
114
|
-
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
115
|
-
request[idColumn]
|
|
123
|
+
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
124
|
+
withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)
|
|
116
125
|
};
|
|
117
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idColumn]}
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)};`
|
|
127
|
+
.unprepared.pipe(
|
|
128
|
+
Effect.map(([, results]) => results as any)
|
|
129
|
+
),
|
|
120
130
|
orElse: () =>
|
|
121
|
-
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
122
|
-
request[idColumn]
|
|
131
|
+
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
132
|
+
withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)
|
|
123
133
|
} returning *`
|
|
124
134
|
})
|
|
125
135
|
})
|
|
@@ -142,8 +152,8 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
142
152
|
const updateVoidSchema = SqlSchema.void({
|
|
143
153
|
Request: Model.update,
|
|
144
154
|
execute: (request: any) =>
|
|
145
|
-
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
146
|
-
request[idColumn]
|
|
155
|
+
sql`update ${sql(options.tableName)} set ${sql.update(request, [idColumn])} where ${
|
|
156
|
+
withSoftDeleteFilter(sql`${sql(idColumn)} = ${request[idColumn]}`)
|
|
147
157
|
}`
|
|
148
158
|
})
|
|
149
159
|
const updateVoid = (
|
|
@@ -160,7 +170,8 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
160
170
|
const findByIdSchema = SqlSchema.findOne({
|
|
161
171
|
Request: idSchema,
|
|
162
172
|
Result: Model,
|
|
163
|
-
execute: (id: any) =>
|
|
173
|
+
execute: (id: any) =>
|
|
174
|
+
sql`select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = ${id}`)}`
|
|
164
175
|
})
|
|
165
176
|
const findById = (
|
|
166
177
|
id: S["fields"][Id]["Type"]
|
|
@@ -177,7 +188,12 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
177
188
|
|
|
178
189
|
const deleteSchema = SqlSchema.void({
|
|
179
190
|
Request: idSchema,
|
|
180
|
-
execute: (id: any) =>
|
|
191
|
+
execute: (id: any) =>
|
|
192
|
+
softDeleteColumn === undefined
|
|
193
|
+
? sql`delete from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}`
|
|
194
|
+
: sql`update ${sql(options.tableName)} set ${setSoftDeleted} where ${
|
|
195
|
+
withSoftDeleteFilter(sql`${sql(idColumn)} = ${id}`)
|
|
196
|
+
}`
|
|
181
197
|
})
|
|
182
198
|
const delete_ = (
|
|
183
199
|
id: S["fields"][Id]["Type"]
|
|
@@ -201,13 +217,15 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
|
|
|
201
217
|
*/
|
|
202
218
|
export const makeResolvers = <
|
|
203
219
|
S extends Model.Any,
|
|
204
|
-
Id extends (keyof S["Type"]) & (keyof S["update"]["Type"]) & (keyof S["fields"])
|
|
220
|
+
Id extends (keyof S["Type"]) & (keyof S["update"]["Type"]) & (keyof S["fields"]),
|
|
221
|
+
SoftDelete extends keyof S["fields"] = never
|
|
205
222
|
>(
|
|
206
223
|
Model: S,
|
|
207
224
|
options: {
|
|
208
225
|
readonly tableName: string
|
|
209
226
|
readonly spanPrefix: string
|
|
210
227
|
readonly idColumn: Id
|
|
228
|
+
readonly softDeleteColumn?: SoftDelete | undefined
|
|
211
229
|
}
|
|
212
230
|
): Effect.Effect<
|
|
213
231
|
{
|
|
@@ -246,6 +264,12 @@ export const makeResolvers = <
|
|
|
246
264
|
const sql = yield* SqlClient
|
|
247
265
|
const idSchema = Model.fields[options.idColumn] as Schema.Top
|
|
248
266
|
const idColumn = options.idColumn as string
|
|
267
|
+
const softDeleteColumn = options.softDeleteColumn as string | undefined
|
|
268
|
+
const withSoftDeleteFilter = (where: any) =>
|
|
269
|
+
softDeleteColumn === undefined ? where : sql.and([where, sql`${sql(softDeleteColumn)} is null`])
|
|
270
|
+
const setSoftDeleted = softDeleteColumn === undefined
|
|
271
|
+
? undefined
|
|
272
|
+
: sql`${sql(softDeleteColumn)} = CURRENT_TIMESTAMP`
|
|
249
273
|
|
|
250
274
|
const insert: RequestResolver.RequestResolver<
|
|
251
275
|
SqlResolver.SqlRequest<
|
|
@@ -262,9 +286,10 @@ export const makeResolvers = <
|
|
|
262
286
|
mysql: () =>
|
|
263
287
|
Effect.forEach(request, (request: any) =>
|
|
264
288
|
sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
|
|
265
|
-
select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID()
|
|
266
|
-
|
|
267
|
-
|
|
289
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = LAST_INSERT_ID()`)};`
|
|
290
|
+
.unprepared.pipe(
|
|
291
|
+
Effect.map(([, results]) => results[0] as any)
|
|
292
|
+
), { concurrency: 10 }),
|
|
268
293
|
orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
|
|
269
294
|
})
|
|
270
295
|
}).pipe(
|
|
@@ -293,7 +318,8 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
|
|
|
293
318
|
ResultId(request: any) {
|
|
294
319
|
return request[idColumn]
|
|
295
320
|
},
|
|
296
|
-
execute: (ids: any) =>
|
|
321
|
+
execute: (ids: any) =>
|
|
322
|
+
sql`select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql.in(idColumn, ids))}`
|
|
297
323
|
}).pipe(
|
|
298
324
|
RequestResolver.withSpan(`${options.spanPrefix}.findByIdResolver`)
|
|
299
325
|
)
|
|
@@ -307,7 +333,12 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
|
|
|
307
333
|
>
|
|
308
334
|
> = SqlResolver.void({
|
|
309
335
|
Request: idSchema,
|
|
310
|
-
execute: (ids: any) =>
|
|
336
|
+
execute: (ids: any) =>
|
|
337
|
+
softDeleteColumn === undefined
|
|
338
|
+
? sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
|
|
339
|
+
: sql`update ${sql(options.tableName)} set ${setSoftDeleted} where ${
|
|
340
|
+
withSoftDeleteFilter(sql.in(idColumn, ids))
|
|
341
|
+
}`
|
|
311
342
|
}).pipe(
|
|
312
343
|
RequestResolver.withSpan(`${options.spanPrefix}.deleteResolver`)
|
|
313
344
|
)
|