effect-start 0.25.0 → 0.26.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 (117) hide show
  1. package/package.json +18 -86
  2. package/dist/ChildProcess.js +0 -42
  3. package/dist/Commander.js +0 -410
  4. package/dist/ContentNegotiation.js +0 -465
  5. package/dist/Cookies.js +0 -371
  6. package/dist/Development.js +0 -94
  7. package/dist/Effectify.js +0 -27
  8. package/dist/Entity.js +0 -289
  9. package/dist/Fetch.js +0 -192
  10. package/dist/FilePathPattern.js +0 -97
  11. package/dist/FileRouter.js +0 -204
  12. package/dist/FileRouterCodegen.js +0 -298
  13. package/dist/FileSystem.js +0 -132
  14. package/dist/Http.js +0 -107
  15. package/dist/PathPattern.js +0 -451
  16. package/dist/PlatformError.js +0 -40
  17. package/dist/PlatformRuntime.js +0 -71
  18. package/dist/Route.js +0 -143
  19. package/dist/RouteBody.js +0 -92
  20. package/dist/RouteError.js +0 -76
  21. package/dist/RouteHook.js +0 -64
  22. package/dist/RouteHttp.js +0 -367
  23. package/dist/RouteHttpTracer.js +0 -90
  24. package/dist/RouteMount.js +0 -86
  25. package/dist/RouteSchema.js +0 -271
  26. package/dist/RouteSse.js +0 -94
  27. package/dist/RouteTree.js +0 -119
  28. package/dist/RouteTrie.js +0 -179
  29. package/dist/SchemaExtra.js +0 -99
  30. package/dist/Socket.js +0 -40
  31. package/dist/SqlIntrospect.js +0 -515
  32. package/dist/Start.js +0 -79
  33. package/dist/StartApp.js +0 -3
  34. package/dist/StreamExtra.js +0 -135
  35. package/dist/System.js +0 -38
  36. package/dist/TuplePathPattern.js +0 -74
  37. package/dist/Unique.js +0 -226
  38. package/dist/Values.js +0 -52
  39. package/dist/bun/BunBundle.js +0 -186
  40. package/dist/bun/BunChildProcessSpawner.js +0 -142
  41. package/dist/bun/BunImportTrackerPlugin.js +0 -91
  42. package/dist/bun/BunRoute.js +0 -157
  43. package/dist/bun/BunRuntime.js +0 -41
  44. package/dist/bun/BunServer.js +0 -285
  45. package/dist/bun/BunVirtualFilesPlugin.js +0 -54
  46. package/dist/bun/_BunEnhancedResolve.js +0 -127
  47. package/dist/bun/index.js +0 -5
  48. package/dist/bundler/Bundle.js +0 -92
  49. package/dist/bundler/BundleFiles.js +0 -154
  50. package/dist/bundler/BundleRoute.js +0 -62
  51. package/dist/client/Overlay.js +0 -33
  52. package/dist/client/ScrollState.js +0 -106
  53. package/dist/client/index.js +0 -97
  54. package/dist/console/Console.js +0 -42
  55. package/dist/console/ConsoleErrors.js +0 -211
  56. package/dist/console/ConsoleLogger.js +0 -56
  57. package/dist/console/ConsoleMetrics.js +0 -72
  58. package/dist/console/ConsoleProcess.js +0 -59
  59. package/dist/console/ConsoleStore.js +0 -72
  60. package/dist/console/ConsoleTracer.js +0 -107
  61. package/dist/console/Simulation.js +0 -784
  62. package/dist/console/index.js +0 -3
  63. package/dist/console/routes/tree.js +0 -30
  64. package/dist/datastar/actions/fetch.js +0 -536
  65. package/dist/datastar/actions/peek.js +0 -13
  66. package/dist/datastar/actions/setAll.js +0 -19
  67. package/dist/datastar/actions/toggleAll.js +0 -19
  68. package/dist/datastar/attributes/attr.js +0 -49
  69. package/dist/datastar/attributes/bind.js +0 -194
  70. package/dist/datastar/attributes/class.js +0 -54
  71. package/dist/datastar/attributes/computed.js +0 -25
  72. package/dist/datastar/attributes/effect.js +0 -10
  73. package/dist/datastar/attributes/indicator.js +0 -33
  74. package/dist/datastar/attributes/init.js +0 -27
  75. package/dist/datastar/attributes/jsonSignals.js +0 -33
  76. package/dist/datastar/attributes/on.js +0 -81
  77. package/dist/datastar/attributes/onIntersect.js +0 -53
  78. package/dist/datastar/attributes/onInterval.js +0 -31
  79. package/dist/datastar/attributes/onSignalPatch.js +0 -51
  80. package/dist/datastar/attributes/ref.js +0 -11
  81. package/dist/datastar/attributes/show.js +0 -32
  82. package/dist/datastar/attributes/signals.js +0 -18
  83. package/dist/datastar/attributes/style.js +0 -57
  84. package/dist/datastar/attributes/text.js +0 -29
  85. package/dist/datastar/engine.js +0 -1145
  86. package/dist/datastar/index.js +0 -25
  87. package/dist/datastar/utils.js +0 -250
  88. package/dist/datastar/watchers/patchElements.js +0 -486
  89. package/dist/datastar/watchers/patchSignals.js +0 -14
  90. package/dist/experimental/EncryptedCookies.js +0 -328
  91. package/dist/experimental/index.js +0 -1
  92. package/dist/hyper/Hyper.js +0 -28
  93. package/dist/hyper/HyperHtml.js +0 -165
  94. package/dist/hyper/HyperNode.js +0 -13
  95. package/dist/hyper/HyperRoute.js +0 -45
  96. package/dist/hyper/html.js +0 -30
  97. package/dist/hyper/index.js +0 -5
  98. package/dist/hyper/jsx-runtime.js +0 -14
  99. package/dist/index.js +0 -8
  100. package/dist/node/NodeFileSystem.js +0 -675
  101. package/dist/node/NodeUtils.js +0 -23
  102. package/dist/sql/Sql.js +0 -8
  103. package/dist/sql/bun/index.js +0 -142
  104. package/dist/sql/index.js +0 -1
  105. package/dist/sql/libsql/index.js +0 -156
  106. package/dist/sql/mssql/docker.js +0 -110
  107. package/dist/sql/mssql/index.js +0 -194
  108. package/dist/testing/TestLogger.js +0 -42
  109. package/dist/testing/index.js +0 -2
  110. package/dist/testing/utils.js +0 -61
  111. package/dist/x/cloudflare/CloudflareTunnel.js +0 -63
  112. package/dist/x/cloudflare/index.js +0 -1
  113. package/dist/x/tailscale/TailscaleTunnel.js +0 -94
  114. package/dist/x/tailscale/index.js +0 -1
  115. package/dist/x/tailwind/TailwindPlugin.js +0 -294
  116. package/dist/x/tailwind/compile.js +0 -210
  117. package/dist/x/tailwind/plugin.js +0 -17
@@ -1,99 +0,0 @@
1
- import * as Function from "effect/Function"
2
- import * as SchemaAST from "effect/SchemaAST"
3
-
4
- export function getBaseSchemaAST(schema) {
5
- let current = schema.ast
6
-
7
- while (SchemaAST.isRefinement(current) || SchemaAST.isTransformation(current)) {
8
- current = current.from
9
- }
10
-
11
- return current
12
- }
13
-
14
- export function isOptional(schema) {
15
- const ast = schema.ast
16
-
17
- if (ast._tag === "Union") {
18
- return ast.types.some((t) => t._tag === "UndefinedKeyword")
19
- }
20
-
21
- return false
22
- }
23
-
24
- export function schemaEqual(
25
- userSchema,
26
- expectedSchema,
27
- ) {
28
- if (!userSchema && !expectedSchema) {
29
- return true
30
- }
31
- if (!userSchema || !expectedSchema) {
32
- return false
33
- }
34
-
35
- const userFields = userSchema.fields
36
- const expectedFields = expectedSchema.fields
37
-
38
- const userKeys = Object.keys(userFields).sort()
39
- const expectedKeys = Object.keys(expectedFields).sort()
40
-
41
- if (userKeys.length !== expectedKeys.length) {
42
- return false
43
- }
44
-
45
- for (let i = 0; i < userKeys.length; i++) {
46
- if (userKeys[i] !== expectedKeys[i]) {
47
- return false
48
- }
49
- }
50
-
51
- for (const key of userKeys) {
52
- const userFieldSchema = userFields[key]
53
- const expectedFieldSchema = expectedFields[key]
54
-
55
- const userOptional = isOptional(userFieldSchema)
56
- const expectedOptional = isOptional(expectedFieldSchema)
57
-
58
- if (userOptional !== expectedOptional) {
59
- return false
60
- }
61
-
62
- const userBaseAST = getBaseSchemaAST(userFieldSchema)
63
- const expectedBaseAST = getBaseSchemaAST(expectedFieldSchema)
64
-
65
- if (userBaseAST._tag !== expectedBaseAST._tag) {
66
- return false
67
- }
68
- }
69
-
70
- return true
71
- }
72
-
73
- export function getSchemaTypeName(schema) {
74
- const baseAST = getBaseSchemaAST(schema)
75
- switch (baseAST._tag) {
76
- case "StringKeyword":
77
- return "Schema.String"
78
- case "NumberKeyword":
79
- return "Schema.Number"
80
- case "BooleanKeyword":
81
- return "Schema.Boolean"
82
- default:
83
- return "Schema.String"
84
- }
85
- }
86
-
87
- export function formatSchemaCode(schema) {
88
- const fields = schema.fields
89
- const fieldStrings = []
90
-
91
- for (const [key, fieldSchema] of Object.entries(fields)) {
92
- const optional = isOptional(fieldSchema)
93
- const typeName = getSchemaTypeName(fieldSchema)
94
- const fieldStr = optional ? `${key}?: ${typeName}` : `${key}: ${typeName}`
95
- fieldStrings.push(fieldStr)
96
- }
97
-
98
- return `{ ${fieldStrings.join(", ")} }`
99
- }
package/dist/Socket.js DELETED
@@ -1,40 +0,0 @@
1
- /*
2
- * Adapted from @effect/platform
3
- */
4
- import * as Predicate from "effect/Predicate"
5
- import * as PlatformError from "./PlatformError.js"
6
-
7
- export const SocketErrorTypeId = Symbol.for("@effect/platform/Socket/SocketError")
8
-
9
- export const isSocketError = (u) =>
10
- Predicate.hasProperty(u, SocketErrorTypeId)
11
-
12
- export class SocketGenericError extends PlatformError.TypeIdError(
13
- SocketErrorTypeId,
14
- "SocketError",
15
- ) {
16
- get message() {
17
- return `An error occurred during ${this.reason}`
18
- }
19
- }
20
-
21
- export class SocketCloseError extends PlatformError.TypeIdError(SocketErrorTypeId, "SocketError") {
22
- static is(u) {
23
- return isSocketError(u) && u.reason === "Close"
24
- }
25
-
26
- static isClean(isClean) {
27
- return function (u) {
28
- return SocketCloseError.is(u) && isClean(u.code)
29
- }
30
- }
31
-
32
- get message() {
33
- if (this.closeReason) {
34
- return `${this.reason}: ${this.code}: ${this.closeReason}`
35
- }
36
- return `${this.reason}: ${this.code}`
37
- }
38
- }
39
-
40
- export const defaultCloseCodeIsError = (code) => code !== 1000 && code !== 1006
@@ -1,515 +0,0 @@
1
- import * as Effect from "effect/Effect"
2
- import * as Schema from "effect/Schema"
3
- import * as Sql from "./sql/Sql.js"
4
-
5
- const sqliteColumns = `
6
- SELECT
7
- '' as tableSchema,
8
- m.name as tableName,
9
- p.name as columnName,
10
- p.cid + 1 as ordinalPosition,
11
- p.dflt_value as columnDefault,
12
- CASE WHEN p."notnull" = 0 THEN 1 ELSE 0 END as isNullable,
13
- p.type as dataType,
14
- NULL as maxLength,
15
- p.pk as isPrimaryKey,
16
- CASE WHEN p.pk = 1 AND lower(p.type) = 'integer' THEN 1 ELSE 0 END as isAutoIncrement
17
- FROM sqlite_master m
18
- JOIN pragma_table_info(m.name) p
19
- WHERE m.type = 'table'
20
- AND m.name NOT LIKE 'sqlite_%'
21
- ORDER BY m.name, p.cid
22
- `
23
-
24
- const sqliteForeignKeys = `
25
- SELECT
26
- '' as constraintName,
27
- '' as tableSchema,
28
- m.name as tableName,
29
- fk."from" as columnName,
30
- '' as referencedSchema,
31
- fk."table" as referencedTable,
32
- fk."to" as referencedColumn,
33
- fk.on_update as updateRule,
34
- fk.on_delete as deleteRule
35
- FROM sqlite_master m
36
- JOIN pragma_foreign_key_list(m.name) fk
37
- WHERE m.type = 'table'
38
- AND m.name NOT LIKE 'sqlite_%'
39
- ORDER BY m.name, fk.seq
40
- `
41
-
42
- const sqliteIndexes = `
43
- SELECT
44
- '' as tableSchema,
45
- m.name as tableName,
46
- il.name as indexName,
47
- ii.name as columnName,
48
- il."unique" as isUnique,
49
- ii.seqno + 1 as ordinalPosition
50
- FROM sqlite_master m
51
- JOIN pragma_index_list(m.name) il
52
- JOIN pragma_index_info(il.name) ii
53
- WHERE m.type = 'table'
54
- AND m.name NOT LIKE 'sqlite_%'
55
- ORDER BY m.name, il.name, ii.seqno
56
- `
57
-
58
- const postgresColumns = `
59
- SELECT
60
- c.table_schema as "tableSchema",
61
- c.table_name as "tableName",
62
- c.column_name as "columnName",
63
- c.ordinal_position as "ordinalPosition",
64
- c.column_default as "columnDefault",
65
- CASE WHEN c.is_nullable = 'YES' THEN true ELSE false END as "isNullable",
66
- c.data_type as "dataType",
67
- c.character_maximum_length as "maxLength",
68
- CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as "isPrimaryKey",
69
- CASE WHEN c.column_default LIKE 'nextval(%' THEN true ELSE false END as "isAutoIncrement"
70
- FROM information_schema.columns c
71
- LEFT JOIN (
72
- SELECT kcu.table_schema, kcu.table_name, kcu.column_name
73
- FROM information_schema.table_constraints tc
74
- JOIN information_schema.key_column_usage kcu
75
- ON tc.constraint_name = kcu.constraint_name
76
- AND tc.table_schema = kcu.table_schema
77
- WHERE tc.constraint_type = 'PRIMARY KEY'
78
- ) pk
79
- ON c.table_schema = pk.table_schema
80
- AND c.table_name = pk.table_name
81
- AND c.column_name = pk.column_name
82
- WHERE c.table_schema NOT IN ('information_schema', 'pg_catalog')
83
- ORDER BY c.table_schema, c.table_name, c.ordinal_position
84
- `
85
-
86
- const postgresForeignKeys = `
87
- SELECT
88
- tc.constraint_name as "constraintName",
89
- tc.table_schema as "tableSchema",
90
- tc.table_name as "tableName",
91
- kcu.column_name as "columnName",
92
- ccu.table_schema as "referencedSchema",
93
- ccu.table_name as "referencedTable",
94
- ccu.column_name as "referencedColumn",
95
- rc.update_rule as "updateRule",
96
- rc.delete_rule as "deleteRule"
97
- FROM information_schema.table_constraints tc
98
- JOIN information_schema.key_column_usage kcu
99
- ON tc.constraint_name = kcu.constraint_name
100
- AND tc.table_schema = kcu.table_schema
101
- JOIN information_schema.constraint_column_usage ccu
102
- ON tc.constraint_name = ccu.constraint_name
103
- AND tc.table_schema = ccu.table_schema
104
- JOIN information_schema.referential_constraints rc
105
- ON tc.constraint_name = rc.constraint_name
106
- AND tc.table_schema = rc.constraint_schema
107
- WHERE tc.constraint_type = 'FOREIGN KEY'
108
- AND tc.table_schema NOT IN ('information_schema', 'pg_catalog')
109
- ORDER BY tc.table_schema, tc.table_name, kcu.ordinal_position
110
- `
111
-
112
- const postgresIndexes = `
113
- SELECT
114
- n.nspname as "tableSchema",
115
- t.relname as "tableName",
116
- i.relname as "indexName",
117
- a.attname as "columnName",
118
- ix.indisunique as "isUnique",
119
- array_position(ix.indkey, a.attnum) as "ordinalPosition"
120
- FROM pg_index ix
121
- JOIN pg_class t ON t.oid = ix.indrelid
122
- JOIN pg_class i ON i.oid = ix.indexrelid
123
- JOIN pg_namespace n ON n.oid = t.relnamespace
124
- JOIN pg_attribute a ON a.attrelid = t.oid
125
- AND a.attnum = ANY(ix.indkey)
126
- WHERE n.nspname NOT IN ('information_schema', 'pg_catalog')
127
- ORDER BY n.nspname, t.relname, i.relname, array_position(ix.indkey, a.attnum)
128
- `
129
-
130
- const mssqlColumns = `
131
- SELECT
132
- s.name as tableSchema,
133
- t.name as tableName,
134
- c.name as columnName,
135
- c.column_id as ordinalPosition,
136
- dc.definition as columnDefault,
137
- c.is_nullable as isNullable,
138
- tp.name as dataType,
139
- c.max_length as maxLength,
140
- CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END as isPrimaryKey,
141
- c.is_identity as isAutoIncrement
142
- FROM sys.tables t
143
- JOIN sys.schemas s ON t.schema_id = s.schema_id
144
- JOIN sys.columns c ON t.object_id = c.object_id
145
- JOIN sys.types tp ON c.user_type_id = tp.user_type_id
146
- LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
147
- LEFT JOIN (
148
- SELECT ic.object_id, ic.column_id
149
- FROM sys.index_columns ic
150
- JOIN sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
151
- WHERE i.is_primary_key = 1
152
- ) pk ON c.object_id = pk.object_id AND c.column_id = pk.column_id
153
- WHERE t.is_ms_shipped = 0
154
- ORDER BY s.name, t.name, c.column_id
155
- `
156
-
157
- const mssqlForeignKeys = `
158
- SELECT
159
- fk.name as constraintName,
160
- s.name as tableSchema,
161
- t.name as tableName,
162
- c.name as columnName,
163
- rs.name as referencedSchema,
164
- rt.name as referencedTable,
165
- rc.name as referencedColumn,
166
- fk.update_referential_action_desc as updateRule,
167
- fk.delete_referential_action_desc as deleteRule
168
- FROM sys.foreign_keys fk
169
- JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
170
- JOIN sys.tables t ON fkc.parent_object_id = t.object_id
171
- JOIN sys.schemas s ON t.schema_id = s.schema_id
172
- JOIN sys.columns c ON fkc.parent_object_id = c.object_id AND fkc.parent_column_id = c.column_id
173
- JOIN sys.tables rt ON fkc.referenced_object_id = rt.object_id
174
- JOIN sys.schemas rs ON rt.schema_id = rs.schema_id
175
- JOIN sys.columns rc ON fkc.referenced_object_id = rc.object_id AND fkc.referenced_column_id = rc.column_id
176
- WHERE t.is_ms_shipped = 0
177
- ORDER BY s.name, t.name, fkc.constraint_column_id
178
- `
179
-
180
- const mssqlIndexes = `
181
- SELECT
182
- s.name as tableSchema,
183
- t.name as tableName,
184
- i.name as indexName,
185
- c.name as columnName,
186
- i.is_unique as isUnique,
187
- ic.key_ordinal as ordinalPosition
188
- FROM sys.indexes i
189
- JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
190
- JOIN sys.tables t ON i.object_id = t.object_id
191
- JOIN sys.schemas s ON t.schema_id = s.schema_id
192
- JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
193
- WHERE t.is_ms_shipped = 0
194
- AND i.name IS NOT NULL
195
- AND i.is_primary_key = 0
196
- AND ic.is_included_column = 0
197
- ORDER BY s.name, t.name, i.name, ic.key_ordinal
198
- `
199
-
200
- const dialectQueries = {
201
- sqlite: { columns: sqliteColumns, foreignKeys: sqliteForeignKeys, indexes: sqliteIndexes },
202
- postgres: {
203
- columns: postgresColumns,
204
- foreignKeys: postgresForeignKeys,
205
- indexes: postgresIndexes,
206
- },
207
- mssql: { columns: mssqlColumns, foreignKeys: mssqlForeignKeys, indexes: mssqlIndexes },
208
- }
209
-
210
- const singleColumnIndexes = (indexes) => {
211
- const countByIndex = new Map()
212
- for (const idx of indexes) {
213
- const key = `${idx.tableSchema}.${idx.tableName}.${idx.indexName}`
214
- const existing = countByIndex.get(key)
215
- if (existing) {
216
- existing.count++
217
- } else {
218
- countByIndex.set(key, { count: 1, columnName: idx.columnName })
219
- }
220
- }
221
- const result = new Set()
222
- for (const [key, entry] of countByIndex) {
223
- if (entry.count === 1) {
224
- const tableKey = key.substring(0, key.lastIndexOf("."))
225
- result.add(`${tableKey}.${entry.columnName}`)
226
- }
227
- }
228
- return result
229
- }
230
-
231
- const groupByTable = (
232
- columns,
233
- foreignKeys,
234
- indexes,
235
- ) => {
236
- const sortable = singleColumnIndexes(indexes)
237
- const tableMap = new Map()
238
- for (const col of columns) {
239
- const key = `${col.tableSchema}.${col.tableName}`
240
- const fullCol = {
241
- ...col,
242
- isSortable: col.isPrimaryKey || sortable.has(`${key}.${col.columnName}`),
243
- }
244
- const existing = tableMap.get(key)
245
- if (existing) {
246
- ;(existing.columns).push(fullCol)
247
- } else {
248
- tableMap.set(key, {
249
- tableSchema: col.tableSchema,
250
- tableName: col.tableName,
251
- columns: [fullCol],
252
- foreignKeys: [],
253
- indexes: [],
254
- })
255
- }
256
- }
257
- for (const fk of foreignKeys) {
258
- const key = `${fk.tableSchema}.${fk.tableName}`
259
- const table = tableMap.get(key)
260
- if (table) {
261
- ;(table.foreignKeys).push(fk)
262
- }
263
- }
264
- for (const idx of indexes) {
265
- const key = `${idx.tableSchema}.${idx.tableName}`
266
- const table = tableMap.get(key)
267
- if (table) {
268
- ;(table.indexes).push(idx)
269
- }
270
- }
271
- return Array.from(tableMap.values())
272
- }
273
-
274
- const normalizeBooleans = (columns) =>
275
- columns.map((c) => ({
276
- ...c,
277
- isNullable: Boolean(c.isNullable),
278
- isPrimaryKey: Boolean(c.isPrimaryKey),
279
- isAutoIncrement: Boolean(c.isAutoIncrement),
280
- }))
281
-
282
- export const introspect = (
283
- dialect,
284
- options,
285
- ) =>
286
- Effect.gen(function* () {
287
- const sql = yield* Sql.SqlClient
288
- const q = dialectQueries[dialect]
289
- const columns = normalizeBooleans(yield* sql.unsafe(q.columns))
290
- const foreignKeys =
291
- options?.foreignKeys !== false ? yield* sql.unsafe(q.foreignKeys) : []
292
- const indexes =
293
- options?.indexes !== false
294
- ? (yield* sql.unsafe(q.indexes)).map((i) => ({
295
- ...i,
296
- isUnique: Boolean(i.isUnique),
297
- }))
298
- : []
299
- return { tables: groupByTable(columns, foreignKeys, indexes) }
300
- })
301
-
302
- const dataTypeToSchema = (dataType) => {
303
- const t = dataType.toLowerCase()
304
- if (
305
- t === "integer" ||
306
- t === "int" ||
307
- t === "int4" ||
308
- t === "int8" ||
309
- t === "smallint" ||
310
- t === "tinyint" ||
311
- t === "mediumint" ||
312
- t === "bigint" ||
313
- t === "int2"
314
- )
315
- return Schema.Number
316
- if (
317
- t === "real" ||
318
- t === "double" ||
319
- t === "double precision" ||
320
- t === "float" ||
321
- t === "float4" ||
322
- t === "float8" ||
323
- t === "numeric" ||
324
- t === "decimal" ||
325
- t === "money" ||
326
- t === "smallmoney"
327
- )
328
- return Schema.Number
329
- if (
330
- t === "text" ||
331
- t === "varchar" ||
332
- t === "char" ||
333
- t === "nchar" ||
334
- t === "nvarchar" ||
335
- t === "ntext" ||
336
- t === "character varying" ||
337
- t === "character" ||
338
- t === "bpchar" ||
339
- t === "uuid" ||
340
- t === "citext" ||
341
- t === "name" ||
342
- t === "xml"
343
- )
344
- return Schema.String
345
- if (t === "boolean" || t === "bool" || t === "bit")
346
- return Schema.Union(Schema.Boolean, Schema.Number)
347
- if (
348
- t === "timestamp" ||
349
- t === "timestamptz" ||
350
- t === "timestamp with time zone" ||
351
- t === "timestamp without time zone" ||
352
- t === "date" ||
353
- t === "datetime" ||
354
- t === "datetime2" ||
355
- t === "smalldatetime" ||
356
- t === "datetimeoffset" ||
357
- t === "time"
358
- )
359
- return Schema.String
360
- if (t === "json" || t === "jsonb") return Schema.Unknown
361
- if (t === "blob" || t === "bytea" || t === "varbinary" || t === "binary" || t === "image")
362
- return null
363
- return null
364
- }
365
-
366
- const columnToSchema = (col) => {
367
- const base = dataTypeToSchema(col.dataType)
368
- if (base === null) return null
369
- if (col.isNullable) return Schema.NullOr(base)
370
- return base
371
- }
372
-
373
- export const tableToSchema = (table) => {
374
- const fields = {}
375
- let hasFields = false
376
- for (const col of table.columns) {
377
- const s = columnToSchema(col)
378
- if (s === null) continue
379
- fields[col.columnName] = s
380
- hasFields = true
381
- }
382
- if (!hasFields) return null
383
- return {
384
- tableName: table.tableName,
385
- tableSchema: table.tableSchema,
386
- schema: Schema.Struct(fields),
387
- columns: table.columns.filter((c) => columnToSchema(c) !== null),
388
- }
389
- }
390
-
391
- export const toSchemas = (db) =>
392
- db.tables.flatMap((t) => {
393
- const s = tableToSchema(t)
394
- return s ? [s] : []
395
- })
396
-
397
- const escapeIdentifier = (id) => `"${id.replace(/"/g, '""')}"`
398
-
399
- const concatSql = (
400
- sql,
401
- fragments,
402
- ) => {
403
- const strings = []
404
- const values = []
405
- for (let i = 0; i < fragments.length; i++) {
406
- const frag = fragments[i]
407
- for (let j = 0; j < frag.strings.length; j++) {
408
- if (j === 0 && strings.length > 0) {
409
- strings[strings.length - 1] += frag.strings[j]
410
- } else {
411
- strings.push(frag.strings[j])
412
- }
413
- if (j < frag.values.length) values.push(frag.values[j])
414
- }
415
- }
416
- const tsa = Object.assign([...strings], { raw: strings })
417
- return sql(tsa, ...values)
418
- }
419
-
420
- const literal = (text) => ({ strings: [text], values: [] })
421
-
422
- const param = (value) => ({ strings: ["", ""], values: [value] })
423
-
424
- const buildWhereFragments = (
425
- filters,
426
- columnSet,
427
- ) => {
428
- const parts = []
429
- const valid = filters.filter((f) => columnSet.has(f.column))
430
- if (valid.length === 0) return parts
431
- parts.push(literal(" WHERE "))
432
- for (let i = 0; i < valid.length; i++) {
433
- if (i > 0) parts.push(literal(" AND "))
434
- const f = valid[i]
435
- const col = escapeIdentifier(f.column)
436
- if (f.value === null) {
437
- parts.push(literal(f.op === "eq" ? `${col} IS NULL` : `${col} IS NOT NULL`))
438
- } else {
439
- parts.push(literal(`${col} ${f.op === "eq" ? "=" : "!="} `))
440
- parts.push(param(f.value))
441
- }
442
- }
443
- return parts
444
- }
445
-
446
- const makeTableReader = (ts) => {
447
- const qualifiedName = ts.tableSchema
448
- ? `${escapeIdentifier(ts.tableSchema)}.${escapeIdentifier(ts.tableName)}`
449
- : escapeIdentifier(ts.tableName)
450
- const primaryKey = ts.columns.find((c) => c.isPrimaryKey)
451
- const selectCols = ts.columns.map((c) => escapeIdentifier(c.columnName)).join(", ")
452
- const columnSet = new Set(ts.columns.map((c) => c.columnName))
453
- const sortableSet = new Set(ts.columns.filter((c) => c.isSortable).map((c) => c.columnName))
454
-
455
- return {
456
- tableName: ts.tableName,
457
- tableSchema: ts.tableSchema,
458
- schema: ts.schema,
459
- columns: ts.columns,
460
- sortableColumns: Array.from(sortableSet),
461
- findAll: (options) =>
462
- Effect.gen(function* () {
463
- const sql = yield* Sql.SqlClient
464
- const fragments = [
465
- literal(`SELECT ${selectCols} FROM ${qualifiedName}`),
466
- ]
467
- if (options?.filters) {
468
- fragments.push(...buildWhereFragments(options.filters, columnSet))
469
- }
470
- if (options?.sort && options.sort.length > 0) {
471
- const sortClauses = options.sort
472
- .filter((s) => sortableSet.has(s.column))
473
- .map((s) => `${escapeIdentifier(s.column)} ${s.reverse ? "DESC" : "ASC"}`)
474
- if (sortClauses.length > 0) fragments.push(literal(` ORDER BY ${sortClauses.join(", ")}`))
475
- }
476
- if (options?.limit !== undefined)
477
- fragments.push(literal(` LIMIT ${Math.trunc(Number(options.limit))}`))
478
- if (options?.offset !== undefined)
479
- fragments.push(literal(` OFFSET ${Math.trunc(Number(options.offset))}`))
480
- return yield* concatSql(sql, fragments)
481
- }),
482
- findById: (id) =>
483
- Effect.gen(function* () {
484
- if (!primaryKey) return null
485
- const sql = yield* Sql.SqlClient
486
- const pkCol = escapeIdentifier(primaryKey.columnName)
487
- const rows = yield* concatSql(sql, [
488
- literal(`SELECT ${selectCols} FROM ${qualifiedName} WHERE ${pkCol} = `),
489
- param(id),
490
- ])
491
- return rows[0] ?? null
492
- }),
493
- count: (options) =>
494
- Effect.gen(function* () {
495
- const sql = yield* Sql.SqlClient
496
- const fragments = [
497
- literal(`SELECT COUNT(*) as count FROM ${qualifiedName}`),
498
- ]
499
- if (options?.filters) {
500
- fragments.push(...buildWhereFragments(options.filters, columnSet))
501
- }
502
- const rows = yield* concatSql(sql, fragments)
503
- return Number((rows[0]).count)
504
- }),
505
- }
506
- }
507
-
508
- export const makeDatabaseReader = (db) => {
509
- const schemas = toSchemas(db)
510
- const readers = schemas.map(makeTableReader)
511
- return {
512
- tables: readers,
513
- table: (name) => readers.find((r) => r.tableName === name),
514
- }
515
- }