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.
Files changed (36) hide show
  1. package/dist/Effect.d.ts +38 -0
  2. package/dist/Effect.d.ts.map +1 -1
  3. package/dist/Effect.js +38 -0
  4. package/dist/Effect.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/internal/effect.js +2 -0
  8. package/dist/internal/effect.js.map +1 -1
  9. package/dist/unstable/httpapi/HttpApiBuilder.d.ts +1 -1
  10. package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
  11. package/dist/unstable/httpapi/HttpApiBuilder.js +11 -7
  12. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  13. package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
  14. package/dist/unstable/httpapi/HttpApiClient.js +2 -1
  15. package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
  16. package/dist/unstable/httpapi/HttpApiTest.d.ts +20 -0
  17. package/dist/unstable/httpapi/HttpApiTest.d.ts.map +1 -0
  18. package/dist/unstable/httpapi/HttpApiTest.js +54 -0
  19. package/dist/unstable/httpapi/HttpApiTest.js.map +1 -0
  20. package/dist/unstable/httpapi/index.d.ts +4 -0
  21. package/dist/unstable/httpapi/index.d.ts.map +1 -1
  22. package/dist/unstable/httpapi/index.js +4 -0
  23. package/dist/unstable/httpapi/index.js.map +1 -1
  24. package/dist/unstable/sql/SqlModel.d.ts +4 -2
  25. package/dist/unstable/sql/SqlModel.d.ts.map +1 -1
  26. package/dist/unstable/sql/SqlModel.js +16 -10
  27. package/dist/unstable/sql/SqlModel.js.map +1 -1
  28. package/package.json +1 -1
  29. package/src/Effect.ts +41 -0
  30. package/src/index.ts +1 -1
  31. package/src/internal/effect.ts +9 -0
  32. package/src/unstable/httpapi/HttpApiBuilder.ts +14 -8
  33. package/src/unstable/httpapi/HttpApiClient.ts +4 -3
  34. package/src/unstable/httpapi/HttpApiTest.ts +95 -0
  35. package/src/unstable/httpapi/index.ts +5 -0
  36. 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":"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","ignoreList":[]}
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "effect",
3
3
  "type": "module",
4
- "version": "4.0.0-beta.62",
4
+ "version": "4.0.0-beta.64",
5
5
  "license": "MIT",
6
6
  "description": "The missing standard library for TypeScript, for writing production-grade software.",
7
7
  "homepage": "https://effect.website",
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}
@@ -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(new Map([[group.key, routes]]))
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: Set<Handlers.Item<R>>
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.add({
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.add({
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 Set<Handlers.Item<R>>()
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
- function handlerToRoute(
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
- const makeClient = <ApiId extends string, Groups extends HttpApiGroup.Any, E, R>(
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, unknown, unknown> =>
205
+ ): Effect.Effect<void> =>
205
206
  Effect.gen(function*() {
206
- const services = yield* Effect.context<any>()
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
+ })
@@ -85,6 +85,11 @@ export * as HttpApiSecurity from "./HttpApiSecurity.ts"
85
85
  */
86
86
  export * as HttpApiSwagger from "./HttpApiSwagger.ts"
87
87
 
88
+ /**
89
+ * @since 4.0.0
90
+ */
91
+ export * as HttpApiTest from "./HttpApiTest.ts"
92
+
88
93
  /**
89
94
  * @since 4.0.0
90
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();`.unprepared.pipe(
78
- Effect.map(([, results]) => results as any)
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 ${sql(idColumn)} = ${
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]};`.unprepared.pipe(
118
- Effect.map(([, results]) => results as any)
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 ${sql(idColumn)} = ${
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 ${sql(idColumn)} = ${
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) => sql`select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}`
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) => sql`delete from ${sql(options.tableName)} where ${sql(idColumn)} = ${id}`
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();`.unprepared.pipe(
266
- Effect.map(([, results]) => results[0] as any)
267
- ), { concurrency: 10 }),
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) => sql`select * from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
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) => sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}`
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
  )