effect-start 0.25.0 → 0.27.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 (174) hide show
  1. package/package.json +20 -86
  2. package/src/Entity.ts +6 -6
  3. package/src/FileRouterCodegen.ts +4 -4
  4. package/src/FileSystem.ts +4 -8
  5. package/src/RouteHook.ts +1 -1
  6. package/src/RouteSse.ts +3 -3
  7. package/src/SqlIntrospect.ts +2 -2
  8. package/src/Start.ts +102 -2
  9. package/src/Values.ts +11 -0
  10. package/src/bun/BunRoute.ts +1 -1
  11. package/src/bun/BunRuntime.ts +5 -5
  12. package/src/hyper/HyperHtml.ts +11 -7
  13. package/src/hyper/jsx.d.ts +1 -1
  14. package/src/lint/plugin.js +174 -4
  15. package/src/sql/SqlClient.ts +355 -0
  16. package/src/sql/bun/index.ts +117 -50
  17. package/src/sql/index.ts +1 -1
  18. package/src/sql/libsql/index.ts +91 -77
  19. package/src/sql/libsql/libsql.d.ts +4 -1
  20. package/src/sql/mssql/index.ts +141 -108
  21. package/src/sql/mssql/mssql.d.ts +1 -0
  22. package/src/testing/TestLogger.ts +4 -4
  23. package/src/x/tailwind/compile.ts +6 -14
  24. package/dist/ChildProcess.js +0 -42
  25. package/dist/Commander.js +0 -410
  26. package/dist/ContentNegotiation.js +0 -465
  27. package/dist/Cookies.js +0 -371
  28. package/dist/Development.js +0 -94
  29. package/dist/Effectify.js +0 -27
  30. package/dist/Entity.js +0 -289
  31. package/dist/Fetch.js +0 -192
  32. package/dist/FilePathPattern.js +0 -97
  33. package/dist/FileRouter.js +0 -204
  34. package/dist/FileRouterCodegen.js +0 -298
  35. package/dist/FileSystem.js +0 -132
  36. package/dist/Http.js +0 -107
  37. package/dist/PathPattern.js +0 -451
  38. package/dist/PlatformError.js +0 -40
  39. package/dist/PlatformRuntime.js +0 -71
  40. package/dist/Route.js +0 -143
  41. package/dist/RouteBody.js +0 -92
  42. package/dist/RouteError.js +0 -76
  43. package/dist/RouteHook.js +0 -64
  44. package/dist/RouteHttp.js +0 -367
  45. package/dist/RouteHttpTracer.js +0 -90
  46. package/dist/RouteMount.js +0 -86
  47. package/dist/RouteSchema.js +0 -271
  48. package/dist/RouteSse.js +0 -94
  49. package/dist/RouteTree.js +0 -119
  50. package/dist/RouteTrie.js +0 -179
  51. package/dist/SchemaExtra.js +0 -99
  52. package/dist/Socket.js +0 -40
  53. package/dist/SqlIntrospect.js +0 -515
  54. package/dist/Start.js +0 -79
  55. package/dist/StartApp.js +0 -3
  56. package/dist/StreamExtra.js +0 -135
  57. package/dist/System.js +0 -38
  58. package/dist/TuplePathPattern.js +0 -74
  59. package/dist/Unique.js +0 -226
  60. package/dist/Values.js +0 -52
  61. package/dist/bun/BunBundle.js +0 -186
  62. package/dist/bun/BunChildProcessSpawner.js +0 -142
  63. package/dist/bun/BunImportTrackerPlugin.js +0 -91
  64. package/dist/bun/BunRoute.js +0 -157
  65. package/dist/bun/BunRuntime.js +0 -41
  66. package/dist/bun/BunServer.js +0 -285
  67. package/dist/bun/BunVirtualFilesPlugin.js +0 -54
  68. package/dist/bun/_BunEnhancedResolve.js +0 -127
  69. package/dist/bun/index.js +0 -5
  70. package/dist/bundler/Bundle.js +0 -92
  71. package/dist/bundler/BundleFiles.js +0 -154
  72. package/dist/bundler/BundleRoute.js +0 -62
  73. package/dist/client/Overlay.js +0 -33
  74. package/dist/client/ScrollState.js +0 -106
  75. package/dist/client/index.js +0 -97
  76. package/dist/console/Console.js +0 -42
  77. package/dist/console/ConsoleErrors.js +0 -211
  78. package/dist/console/ConsoleLogger.js +0 -56
  79. package/dist/console/ConsoleMetrics.js +0 -72
  80. package/dist/console/ConsoleProcess.js +0 -59
  81. package/dist/console/ConsoleStore.js +0 -72
  82. package/dist/console/ConsoleTracer.js +0 -107
  83. package/dist/console/Simulation.js +0 -784
  84. package/dist/console/index.js +0 -3
  85. package/dist/console/routes/tree.js +0 -30
  86. package/dist/datastar/actions/fetch.js +0 -536
  87. package/dist/datastar/actions/peek.js +0 -13
  88. package/dist/datastar/actions/setAll.js +0 -19
  89. package/dist/datastar/actions/toggleAll.js +0 -19
  90. package/dist/datastar/attributes/attr.js +0 -49
  91. package/dist/datastar/attributes/bind.js +0 -194
  92. package/dist/datastar/attributes/class.js +0 -54
  93. package/dist/datastar/attributes/computed.js +0 -25
  94. package/dist/datastar/attributes/effect.js +0 -10
  95. package/dist/datastar/attributes/indicator.js +0 -33
  96. package/dist/datastar/attributes/init.js +0 -27
  97. package/dist/datastar/attributes/jsonSignals.js +0 -33
  98. package/dist/datastar/attributes/on.js +0 -81
  99. package/dist/datastar/attributes/onIntersect.js +0 -53
  100. package/dist/datastar/attributes/onInterval.js +0 -31
  101. package/dist/datastar/attributes/onSignalPatch.js +0 -51
  102. package/dist/datastar/attributes/ref.js +0 -11
  103. package/dist/datastar/attributes/show.js +0 -32
  104. package/dist/datastar/attributes/signals.js +0 -18
  105. package/dist/datastar/attributes/style.js +0 -57
  106. package/dist/datastar/attributes/text.js +0 -29
  107. package/dist/datastar/engine.js +0 -1145
  108. package/dist/datastar/index.js +0 -25
  109. package/dist/datastar/utils.js +0 -250
  110. package/dist/datastar/watchers/patchElements.js +0 -486
  111. package/dist/datastar/watchers/patchSignals.js +0 -14
  112. package/dist/experimental/EncryptedCookies.js +0 -328
  113. package/dist/experimental/index.js +0 -1
  114. package/dist/hyper/Hyper.js +0 -28
  115. package/dist/hyper/HyperHtml.js +0 -165
  116. package/dist/hyper/HyperNode.js +0 -13
  117. package/dist/hyper/HyperRoute.js +0 -45
  118. package/dist/hyper/html.js +0 -30
  119. package/dist/hyper/index.js +0 -5
  120. package/dist/hyper/jsx-runtime.js +0 -14
  121. package/dist/index.js +0 -8
  122. package/dist/node/NodeFileSystem.js +0 -675
  123. package/dist/node/NodeUtils.js +0 -23
  124. package/dist/sql/Sql.js +0 -8
  125. package/dist/sql/bun/index.js +0 -142
  126. package/dist/sql/index.js +0 -1
  127. package/dist/sql/libsql/index.js +0 -156
  128. package/dist/sql/mssql/docker.js +0 -110
  129. package/dist/sql/mssql/index.js +0 -194
  130. package/dist/testing/TestLogger.js +0 -42
  131. package/dist/testing/index.js +0 -2
  132. package/dist/testing/utils.js +0 -61
  133. package/dist/x/cloudflare/CloudflareTunnel.js +0 -63
  134. package/dist/x/cloudflare/index.js +0 -1
  135. package/dist/x/tailscale/TailscaleTunnel.js +0 -94
  136. package/dist/x/tailscale/index.js +0 -1
  137. package/dist/x/tailwind/TailwindPlugin.js +0 -294
  138. package/dist/x/tailwind/compile.js +0 -210
  139. package/dist/x/tailwind/plugin.js +0 -17
  140. package/src/console/Console.ts +0 -42
  141. package/src/console/ConsoleErrors.ts +0 -213
  142. package/src/console/ConsoleLogger.ts +0 -56
  143. package/src/console/ConsoleMetrics.ts +0 -72
  144. package/src/console/ConsoleProcess.ts +0 -59
  145. package/src/console/ConsoleStore.ts +0 -187
  146. package/src/console/ConsoleTracer.ts +0 -107
  147. package/src/console/Simulation.ts +0 -814
  148. package/src/console/console.html +0 -340
  149. package/src/console/index.ts +0 -3
  150. package/src/console/routes/errors/route.tsx +0 -97
  151. package/src/console/routes/fiberDetail.tsx +0 -54
  152. package/src/console/routes/fibers/route.tsx +0 -45
  153. package/src/console/routes/git/route.tsx +0 -64
  154. package/src/console/routes/layout.tsx +0 -4
  155. package/src/console/routes/logs/route.tsx +0 -77
  156. package/src/console/routes/metrics/route.tsx +0 -36
  157. package/src/console/routes/route.tsx +0 -8
  158. package/src/console/routes/routes/route.tsx +0 -30
  159. package/src/console/routes/services/route.tsx +0 -21
  160. package/src/console/routes/system/route.tsx +0 -43
  161. package/src/console/routes/traceDetail.tsx +0 -22
  162. package/src/console/routes/traces/route.tsx +0 -81
  163. package/src/console/routes/tree.ts +0 -30
  164. package/src/console/ui/Errors.tsx +0 -76
  165. package/src/console/ui/Fibers.tsx +0 -321
  166. package/src/console/ui/Git.tsx +0 -182
  167. package/src/console/ui/Logs.tsx +0 -46
  168. package/src/console/ui/Metrics.tsx +0 -78
  169. package/src/console/ui/Routes.tsx +0 -125
  170. package/src/console/ui/Services.tsx +0 -273
  171. package/src/console/ui/Shell.tsx +0 -62
  172. package/src/console/ui/System.tsx +0 -131
  173. package/src/console/ui/Traces.tsx +0 -426
  174. package/src/sql/Sql.ts +0 -51
@@ -1,142 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Exit from "effect/Exit"
3
- import * as FiberRef from "effect/FiberRef"
4
- import * as GlobalValue from "effect/GlobalValue"
5
- import * as Layer from "effect/Layer"
6
- import * as Option from "effect/Option"
7
- import * as Sql from "../Sql.js"
8
-
9
- const errorCode = (error) => {
10
- const e = error
11
- if (typeof e?.errno === "string") return e.errno
12
- return e?.code ?? "UNKNOWN"
13
- }
14
-
15
- const wrapError = (error) =>
16
- new Sql.SqlError({
17
- code: errorCode(error),
18
- message: error instanceof Error ? error.message : String(error),
19
- cause: error,
20
- })
21
-
22
- const wrap = (fn) =>
23
- Effect.tryPromise({ try: () => Promise.resolve(fn()), catch: wrapError })
24
-
25
- const makeValues = (obj, ...columns) => {
26
- const items = Array.isArray(obj) ? obj : [obj]
27
- const cols = columns.length > 0 ? columns : Object.keys(items[0])
28
- return { value: items, columns: cols }
29
- }
30
-
31
- const currentTransaction = GlobalValue.globalValue(
32
- Symbol.for("effect-start/sql/bun/currentTransaction"),
33
- () => FiberRef.unsafeMake(Option.none()),
34
- )
35
-
36
- const makeRun =
37
- (bunSql) =>
38
- (fn) =>
39
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) =>
40
- wrap(() => fn(Option.isSome(txOpt) ? txOpt.value.conn : bunSql)),
41
- )
42
-
43
- const makeWithTransaction =
44
- (bunSql) =>
45
- (self) =>
46
- Effect.uninterruptibleMask((restore) =>
47
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
48
- if (Option.isSome(txOpt)) {
49
- const { conn, depth } = txOpt.value
50
- const name = `sp_${depth}`
51
- return Effect.gen(function* () {
52
- yield* wrap(() => conn.unsafe(`SAVEPOINT ${name}`))
53
- const exit = yield* Effect.exit(
54
- restore(
55
- Effect.locally(self, currentTransaction, Option.some({ conn, depth: depth + 1 })),
56
- ),
57
- )
58
- if (Exit.isSuccess(exit)) {
59
- yield* wrap(() => conn.unsafe(`RELEASE SAVEPOINT ${name}`))
60
- return exit.value
61
- }
62
- yield* wrap(() => conn.unsafe(`ROLLBACK TO SAVEPOINT ${name}`)).pipe(Effect.orDie)
63
- return yield* exit
64
- })
65
- }
66
-
67
- const runTx = (conn) =>
68
- Effect.gen(function* () {
69
- yield* wrap(() => conn.unsafe("BEGIN"))
70
- const exit = yield* Effect.exit(
71
- restore(Effect.locally(self, currentTransaction, Option.some({ conn, depth: 1 }))),
72
- )
73
- if (Exit.isSuccess(exit)) {
74
- yield* wrap(() => conn.unsafe("COMMIT"))
75
- return exit.value
76
- }
77
- yield* wrap(() => conn.unsafe("ROLLBACK")).pipe(Effect.orDie)
78
- return yield* exit
79
- })
80
-
81
- return Effect.matchEffect(
82
- wrap(() => bunSql.reserve()),
83
- {
84
- onFailure: () => runTx(bunSql),
85
- onSuccess: (reserved) =>
86
- Effect.ensuring(
87
- runTx(reserved),
88
- Effect.sync(() => reserved.release()),
89
- ),
90
- },
91
- )
92
- }),
93
- )
94
-
95
- export const layer = (
96
- config,
97
- ) =>
98
- Layer.scoped(
99
- Sql.SqlClient,
100
- Effect.acquireRelease(
101
- Effect.try({
102
- try: () => {
103
- const bunSql = new Bun.SQL(config)
104
- const run = makeRun(bunSql)
105
- const use = (fn) =>
106
- Effect.tryPromise({ try: () => Promise.resolve(fn(bunSql)), catch: wrapError })
107
- return Object.assign(
108
- (strings, ...values) =>
109
- run((conn) => conn(strings, ...values)),
110
- {
111
- unsafe: (query, values) =>
112
- run((conn) => conn.unsafe(query, values)),
113
- values: makeValues,
114
- withTransaction: makeWithTransaction(bunSql),
115
- reserve: Effect.acquireRelease(
116
- wrap(() => bunSql.reserve()),
117
- (reserved) => Effect.sync(() => reserved.release()),
118
- ).pipe(
119
- Effect.map(
120
- (reserved) =>
121
- Object.assign(
122
- (strings, ...values) =>
123
- wrap(() => reserved(strings, ...values)),
124
- {
125
- unsafe: (query, values) =>
126
- wrap(() => reserved.unsafe(query, values)),
127
- values: makeValues,
128
- },
129
- ),
130
- ),
131
- ),
132
- close: (options) =>
133
- use((bunSql) => bunSql.close(options)),
134
- use,
135
- },
136
- )
137
- },
138
- catch: wrapError,
139
- }),
140
- (client) => client.close().pipe(Effect.orDie),
141
- ),
142
- )
package/dist/sql/index.js DELETED
@@ -1 +0,0 @@
1
- export * as Sql from "./Sql.js"
@@ -1,156 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Exit from "effect/Exit"
3
- import * as FiberRef from "effect/FiberRef"
4
- import * as GlobalValue from "effect/GlobalValue"
5
- import * as Layer from "effect/Layer"
6
- import * as Option from "effect/Option"
7
- import * as Sql from "../Sql.js"
8
-
9
- const wrapError = (error) =>
10
- new Sql.SqlError({
11
- code: (error)?.code ?? "UNKNOWN",
12
- message: error instanceof Error ? error.message : String(error),
13
- cause: error,
14
- })
15
-
16
- const wrap = (fn) =>
17
- Effect.tryPromise({ try: () => Promise.resolve(fn()), catch: wrapError })
18
-
19
- const makeValues = (obj, ...columns) => {
20
- const items = Array.isArray(obj) ? obj : [obj]
21
- const cols = columns.length > 0 ? columns : Object.keys(items[0])
22
- return { value: items, columns: cols }
23
- }
24
-
25
- const resultSetToRows = (result) => {
26
- const { columns, rows } = result
27
- return rows.map((row) => {
28
- const obj = {}
29
- for (let i = 0; i < columns.length; i++) obj[columns[i]] = row[i]
30
- return obj
31
- })
32
- }
33
-
34
- const buildQuery = (strings, values) => {
35
- let sql = strings[0]
36
- for (let i = 0; i < values.length; i++) sql += "?" + strings[i + 1]
37
- return { sql, args: values }
38
- }
39
-
40
- const loadLibsql = () => import("@libsql/client")
41
-
42
- const currentTransaction = GlobalValue.globalValue(
43
- Symbol.for("effect-start/sql/libsql/currentTransaction"),
44
- () => FiberRef.unsafeMake(Option.none()),
45
- )
46
-
47
- const executeQuery = (
48
- client,
49
- sql,
50
- args,
51
- ) =>
52
- wrap(() => client.execute({ sql, args })).pipe(Effect.map(resultSetToRows<T>))
53
-
54
- const runQuery = (
55
- client,
56
- strings,
57
- values,
58
- ) => {
59
- const { sql, args } = buildQuery(strings, values)
60
- return executeQuery(client, sql, args)
61
- }
62
-
63
- const runUnsafe = (
64
- client,
65
- query,
66
- values,
67
- ) =>
68
- executeQuery(client, query, values ?? [])
69
-
70
- const exec = (client, sql) =>
71
- wrap(() => client.execute(sql))
72
-
73
- const makeWithTransaction =
74
- (client) =>
75
- (self) =>
76
- Effect.uninterruptibleMask((restore) =>
77
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
78
- if (Option.isSome(txOpt)) {
79
- const { depth } = txOpt.value
80
- const name = `sp_${depth}`
81
- return Effect.gen(function* () {
82
- yield* exec(client, `SAVEPOINT ${name}`)
83
- const exit = yield* Effect.exit(
84
- restore(
85
- Effect.locally(self, currentTransaction, Option.some({ depth: depth + 1 })),
86
- ),
87
- )
88
- if (Exit.isSuccess(exit)) {
89
- yield* exec(client, `RELEASE SAVEPOINT ${name}`)
90
- return exit.value
91
- }
92
- yield* exec(client, `ROLLBACK TO SAVEPOINT ${name}`).pipe(Effect.orDie)
93
- return yield* exit
94
- })
95
- }
96
-
97
- return Effect.gen(function* () {
98
- yield* exec(client, "BEGIN")
99
- const exit = yield* Effect.exit(
100
- restore(Effect.locally(self, currentTransaction, Option.some({ depth: 1 }))),
101
- )
102
- if (Exit.isSuccess(exit)) {
103
- yield* exec(client, "COMMIT")
104
- return exit.value
105
- }
106
- yield* exec(client, "ROLLBACK").pipe(Effect.orDie)
107
- return yield* exit
108
- })
109
- }),
110
- )
111
-
112
- export const layer = (config) =>
113
- Layer.scoped(
114
- Sql.SqlClient,
115
- Effect.acquireRelease(
116
- wrap(() => loadLibsql()).pipe(
117
- Effect.map((libsql) => {
118
- const client = libsql.createClient(config)
119
- const use = (fn) =>
120
- Effect.tryPromise({ try: () => Promise.resolve(fn(client)), catch: wrapError })
121
- return Object.assign(
122
- (strings, ...values) =>
123
- runQuery(client, strings, values),
124
- {
125
- unsafe: (query, values) =>
126
- runUnsafe(client, query, values),
127
- values: makeValues,
128
- withTransaction: makeWithTransaction(client),
129
- reserve: Effect.acquireRelease(
130
- wrap(() => loadLibsql()).pipe(
131
- Effect.map((m) => m.createClient(config)),
132
- ),
133
- (reserved) => Effect.sync(() => reserved.close()),
134
- ).pipe(
135
- Effect.map(
136
- (reserved) =>
137
- Object.assign(
138
- (strings, ...values) =>
139
- runQuery(reserved, strings, values),
140
- {
141
- unsafe: (query, values) =>
142
- runUnsafe(reserved, query, values),
143
- values: makeValues,
144
- },
145
- ),
146
- ),
147
- ),
148
- close: () => Effect.sync(() => client.close()),
149
- use,
150
- },
151
- )
152
- }),
153
- ),
154
- (client) => client.close().pipe(Effect.orDie),
155
- ),
156
- )
@@ -1,110 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Stream from "effect/Stream"
3
-
4
- import * as System from "../../System.js"
5
- import * as BunChildProcessSpawner from "../../bun/BunChildProcessSpawner.js"
6
-
7
- const PORT = 1433
8
- const PASSWORD = "TestPass123"
9
- const CONTAINER = "effect-start-mssql"
10
-
11
- const exec = (
12
- ...args
13
- ) =>
14
- Effect.scoped(
15
- Effect.gen(function* () {
16
- const handle = yield* System.spawn("docker", args, {
17
- stdout: "ignore",
18
- stderr: "inherit",
19
- })
20
- return yield* handle.exitCode
21
- }),
22
- )
23
-
24
- const execStdout = (
25
- ...args
26
- ) =>
27
- Effect.scoped(
28
- Effect.gen(function* () {
29
- const handle = yield* System.spawn("docker", args, {
30
- stdout: "pipe",
31
- stderr: "inherit",
32
- })
33
- const [stdout] = yield* Effect.all(
34
- [handle.stdout.pipe(Stream.decodeText("utf-8"), Stream.mkString), handle.exitCode],
35
- { concurrency: 2 },
36
- )
37
- return stdout
38
- }),
39
- )
40
-
41
- const containerRunning = execStdout("ps", "-q", "-f", `name=${CONTAINER}`).pipe(
42
- Effect.map((stdout) => stdout.trim().length > 0),
43
- )
44
-
45
- const removeContainer = exec("rm", "-f", CONTAINER).pipe(Effect.ignore)
46
-
47
- const loadMssql = () => import("mssql")
48
-
49
- const canConnect = Effect.tryPromise({
50
- try: async () => {
51
- const { ConnectionPool } = await loadMssql()
52
- const pool = new ConnectionPool({
53
- server: "localhost",
54
- user: "sa",
55
- password: PASSWORD,
56
- port: PORT,
57
- options: { encrypt: true, trustServerCertificate: true, connectTimeout: 3000 },
58
- })
59
- await pool.connect()
60
- await pool.close()
61
- return true
62
- },
63
- catch: () => /** @type {const} */ false,
64
- }).pipe(Effect.orElseSucceed(() => false))
65
-
66
- const waitReady = Effect.gen(function* () {
67
- const deadline = Date.now() + 60_000
68
- while (Date.now() < deadline) {
69
- if (yield* canConnect) return
70
- yield* Effect.sleep("2 seconds")
71
- }
72
- return yield* Effect.fail(new Error("Timed out waiting for MSSQL"))
73
- })
74
-
75
- const program = Effect.gen(function* () {
76
- if (yield* containerRunning) {
77
- yield* Effect.log("MSSQL container already running")
78
- return
79
- }
80
-
81
- yield* removeContainer
82
-
83
- yield* Effect.log("Starting MSSQL container...")
84
- const code = yield* exec(
85
- "run",
86
- "-d",
87
- "--name",
88
- CONTAINER,
89
- "-p",
90
- `${PORT}:1433`,
91
- "-e",
92
- "ACCEPT_EULA=Y",
93
- "-e",
94
- `MSSQL_SA_PASSWORD=${PASSWORD}`,
95
- "mcr.microsoft.com/azure-sql-edge",
96
- )
97
- if (code !== 0) {
98
- return yield* Effect.fail(new Error(`docker run exited with code ${code}`))
99
- }
100
-
101
- yield* waitReady
102
- yield* Effect.log("MSSQL ready")
103
- })
104
-
105
- const run = (effect) =>
106
- Effect.runPromise(Effect.provide(effect, BunChildProcessSpawner.layer))
107
-
108
- export const start = () => run(program)
109
-
110
- export const stop = () => run(removeContainer)
@@ -1,194 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Exit from "effect/Exit"
3
- import * as FiberRef from "effect/FiberRef"
4
- import * as GlobalValue from "effect/GlobalValue"
5
- import * as Layer from "effect/Layer"
6
- import * as Option from "effect/Option"
7
- import * as Sql from "../Sql.js"
8
-
9
- const wrapError = (error) =>
10
- new Sql.SqlError({
11
- code:
12
- (error)?.code ??
13
- ((error)?.number != null ? String((error).number) : "UNKNOWN"),
14
- message: error instanceof Error ? error.message : String(error),
15
- cause: error,
16
- })
17
-
18
- const makeValues = (obj, ...columns) => {
19
- const items = Array.isArray(obj) ? obj : [obj]
20
- const cols = columns.length > 0 ? columns : Object.keys(items[0])
21
- return { value: items, columns: cols }
22
- }
23
-
24
- const buildQuery = (strings, values) => {
25
- let text = strings[0]
26
- for (let i = 0; i < values.length; i++) text += `@p${i + 1}` + strings[i + 1]
27
- return { text, values }
28
- }
29
-
30
- const addInputs = (request, values) => {
31
- for (let i = 0; i < values.length; i++) {
32
- request.input(`p${i + 1}`, values[i])
33
- }
34
- }
35
-
36
- const loadMssql = () => import("mssql")
37
-
38
- const currentTransaction = GlobalValue.globalValue(
39
- Symbol.for("effect-start/sql/mssql/currentTransaction"),
40
- () => FiberRef.unsafeMake(Option.none()),
41
- )
42
-
43
- const executeQuery = (
44
- pool,
45
- text,
46
- values,
47
- ) =>
48
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
49
- const request = Option.isSome(txOpt) ? txOpt.value.transaction.request() : pool.request()
50
- addInputs(request, values)
51
- return Effect.tryPromise({
52
- try: () => request.query(text),
53
- catch: wrapError,
54
- }).pipe(Effect.map((result) => result.recordset ?? []))
55
- })
56
-
57
- const runQuery = (
58
- pool,
59
- strings,
60
- values,
61
- ) => {
62
- const { text, values: params } = buildQuery(strings, values)
63
- return executeQuery(pool, text, params)
64
- }
65
-
66
- const runUnsafe = (
67
- pool,
68
- query,
69
- values,
70
- ) =>
71
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
72
- const request = Option.isSome(txOpt) ? txOpt.value.transaction.request() : pool.request()
73
- if (values) addInputs(request, values)
74
- return Effect.tryPromise({
75
- try: () => request.query(query),
76
- catch: wrapError,
77
- }).pipe(Effect.map((result) => result.recordset ?? []))
78
- })
79
-
80
- const makeWithTransaction =
81
- (pool) =>
82
- (self) =>
83
- Effect.uninterruptibleMask((restore) =>
84
- Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
85
- if (Option.isSome(txOpt)) {
86
- const { transaction, depth } = txOpt.value
87
- const name = `sp_${depth}`
88
- return Effect.gen(function* () {
89
- const req = transaction.request()
90
- yield* Effect.tryPromise({
91
- try: () => req.query(`SAVE TRANSACTION ${name}`),
92
- catch: wrapError,
93
- })
94
- const exit = yield* Effect.exit(
95
- restore(
96
- Effect.locally(
97
- self,
98
- currentTransaction,
99
- Option.some({ transaction, depth: depth + 1 }),
100
- ),
101
- ),
102
- )
103
- if (Exit.isSuccess(exit)) {
104
- return exit.value
105
- }
106
- const rbReq = transaction.request()
107
- yield* Effect.tryPromise({
108
- try: () => rbReq.query(`ROLLBACK TRANSACTION ${name}`),
109
- catch: wrapError,
110
- }).pipe(Effect.orDie)
111
- return yield* exit
112
- })
113
- }
114
-
115
- return Effect.gen(function* () {
116
- const transaction = pool.transaction()
117
- yield* Effect.tryPromise({ try: () => transaction.begin(), catch: wrapError })
118
- const exit = yield* Effect.exit(
119
- restore(
120
- Effect.locally(self, currentTransaction, Option.some({ transaction, depth: 1 })),
121
- ),
122
- )
123
- if (Exit.isSuccess(exit)) {
124
- yield* Effect.tryPromise({ try: () => transaction.commit(), catch: wrapError })
125
- return exit.value
126
- }
127
- yield* Effect.tryPromise({ try: () => transaction.rollback(), catch: wrapError }).pipe(
128
- Effect.orDie,
129
- )
130
- return yield* exit
131
- })
132
- }),
133
- )
134
-
135
- export const layer = (config) =>
136
- Layer.scoped(
137
- Sql.SqlClient,
138
- Effect.acquireRelease(
139
- Effect.tryPromise({
140
- try: async () => {
141
- const mssql = await loadMssql()
142
- const pool = await new mssql.ConnectionPool(config).connect()
143
- return { mssql, pool }
144
- },
145
- catch: wrapError,
146
- }).pipe(
147
- Effect.map(({ mssql, pool }) => {
148
- const use = (fn) =>
149
- Effect.tryPromise({ try: () => Promise.resolve(fn(pool)), catch: wrapError })
150
- return Object.assign(
151
- (strings, ...values) =>
152
- runQuery(pool, strings, values),
153
- {
154
- unsafe: (query, values) =>
155
- runUnsafe(pool, query, values),
156
- values: makeValues,
157
- withTransaction: makeWithTransaction(pool),
158
- reserve: Effect.acquireRelease(
159
- Effect.tryPromise({
160
- try: () =>
161
- new mssql.ConnectionPool({
162
- ...config,
163
- pool: { max: 1, min: 1 },
164
- }).connect(),
165
- catch: wrapError,
166
- }),
167
- (reserved) =>
168
- Effect.tryPromise({ try: () => reserved.close(), catch: () => void 0 }).pipe(
169
- Effect.asVoid,
170
- Effect.orDie,
171
- ),
172
- ).pipe(
173
- Effect.map(
174
- (reserved) =>
175
- Object.assign(
176
- (strings, ...values) =>
177
- runQuery(reserved, strings, values),
178
- {
179
- unsafe: (query, values) =>
180
- runUnsafe(reserved, query, values),
181
- values: makeValues,
182
- },
183
- ),
184
- ),
185
- ),
186
- close: () => use((pool) => pool.close()),
187
- use,
188
- },
189
- )
190
- }),
191
- ),
192
- (client) => client.close().pipe(Effect.orDie),
193
- ),
194
- )
@@ -1,42 +0,0 @@
1
- import * as Cause from "effect/Cause"
2
- import * as Context from "effect/Context"
3
- import * as Effect from "effect/Effect"
4
- import * as FiberRef from "effect/FiberRef"
5
- import * as HashSet from "effect/HashSet"
6
- import * as Layer from "effect/Layer"
7
- import * as Logger from "effect/Logger"
8
- import * as MutableRef from "effect/MutableRef"
9
- import * as Ref from "effect/Ref"
10
-
11
- export class TestLogger extends Context.Tag("effect-start/TestLogger")() {}
12
-
13
- export function layer() {
14
- return Layer.effect(
15
- TestLogger,
16
- Effect.gen(function* () {
17
- const messages = yield* Ref.make([])
18
- const mutableRef = (messages).ref
19
-
20
- const customLogger = Logger.make(({ message, logLevel, cause }) => {
21
- const causeStr = !Cause.isEmpty(cause)
22
- ? ` ${Cause.pretty(cause, { renderErrorCause: true })}`
23
- : ""
24
- MutableRef.update(mutableRef, (msgs) => [
25
- ...msgs,
26
- `[${logLevel._tag}] ${String(message)}${causeStr}`,
27
- ])
28
- })
29
-
30
- yield* FiberRef.update(FiberRef.currentLoggers, (loggers) =>
31
- HashSet.add(HashSet.remove(loggers, Logger.defaultLogger), customLogger),
32
- )
33
-
34
- return { messages }
35
- }),
36
- )
37
- }
38
-
39
- export const messages = Effect.gen(function* () {
40
- const logger = yield* TestLogger
41
- return yield* Ref.get(logger.messages)
42
- })
@@ -1,2 +0,0 @@
1
- export * as TestLogger from "./TestLogger.js"
2
- export * from "./utils.js"