* Attempts to coerce a non-null value to a column's declared type. Returns the * coerced value when the value already matches or can be converted without * ambiguity (e.g. the string `"1999"` to the number `1999`), and `ok: false` * when no safe conversion exists.
( value: JsonValue, type: ColumnDefinition['type'] )
| 270 | * when no safe conversion exists. |
| 271 | */ |
| 272 | function coerceValueToColumnType( |
| 273 | value: JsonValue, |
| 274 | type: ColumnDefinition['type'] |
| 275 | ): { ok: true; value: JsonValue } | { ok: false } { |
| 276 | switch (type) { |
| 277 | case 'string': |
| 278 | if (typeof value === 'string') return { ok: true, value } |
| 279 | if (typeof value === 'number' || typeof value === 'boolean') { |
| 280 | return { ok: true, value: String(value) } |
| 281 | } |
| 282 | return { ok: false } |
| 283 | case 'number': |
| 284 | if (typeof value === 'number') { |
| 285 | return Number.isFinite(value) ? { ok: true, value } : { ok: false } |
| 286 | } |
| 287 | if (typeof value === 'string' && value.trim() !== '') { |
| 288 | const parsed = Number(value) |
| 289 | return Number.isFinite(parsed) ? { ok: true, value: parsed } : { ok: false } |
| 290 | } |
| 291 | return { ok: false } |
| 292 | case 'boolean': |
| 293 | if (typeof value === 'boolean') return { ok: true, value } |
| 294 | if (typeof value === 'string') { |
| 295 | const normalized = value.trim().toLowerCase() |
| 296 | if (normalized === 'true') return { ok: true, value: true } |
| 297 | if (normalized === 'false') return { ok: true, value: false } |
| 298 | } |
| 299 | return { ok: false } |
| 300 | case 'date': { |
| 301 | if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return { ok: true, value } |
| 302 | // Date instances and epoch numbers may still be out of the representable |
| 303 | // range (>±8.64e15ms) — guard `toISOString()`, which throws RangeError on |
| 304 | // an Invalid Date, so an over-range value degrades to `{ ok: false }` |
| 305 | // rather than crashing the write. |
| 306 | const date = |
| 307 | value instanceof Date ? value : typeof value === 'number' ? new Date(value) : null |
| 308 | if (date && !Number.isNaN(date.getTime())) return { ok: true, value: date.toISOString() } |
| 309 | return { ok: false } |
| 310 | } |
| 311 | default: |
| 312 | return { ok: true, value } |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | /** |
| 317 | * Coerces each present value in `data` toward its column's declared type **in |
no test coverage detected