# Lyng.io.db Core level interface to SQL implementations. Pooling, physical connections, and implementation-specific configuration are hidden behind the opened database handle. All providers should support the generic `openDatabase(connectionUrl, extraParams)` entry point for configuration-driven usage. Providers may also expose typed helpers such as `openSqlite(...)` or `openPostgres(...)`. Provider modules should register their URL schemes when first imported. The generic `openDatabase(...)` then dispatches by normalized URL scheme to the registered provider. See [db definitions](lyngdb.lyng). ## Platforms support: | DB | JVM | Native | |----------|-----|--------| | Postgres | + | ? | | H2 | + | + | | SQLITE | + | + | Question for the future: what to do on JS platforms? Browsers have their crazy own storages, bit it is not SQL. Probably for this case we need some simpler standard compatible with browsers and with special implementation on JVM. ## Proposed type mapping: | SQL | Lyng | comments | |--------------------------------------------|----------|----------| | SMALLINT | Int | Lyng `Int` is already 64-bit | | INTEGER / INT | Int | | | BIGINT | Int | Lyng `Int` is already 64-bit | | REAL / FLOAT / DOUBLE PRECISION | Double | | | DECIMAL / NUMERIC | Decimal | exact numeric | | BOOLEAN / BOOL | Bool | | | CHAR / VARCHAR / TEXT | String | | | BINARY / VARBINARY / BLOB / BYTEA | Buffer | | | DATE | Date | calendar date | | TIME / TIME WITHOUT TIME ZONE | String | v1: no standalone Lyng `Time` type yet | | TIMESTAMP / TIMESTAMP WITHOUT TIME ZONE | DateTime | local calendar-dependent timestamp | | TIME WITH TIME ZONE | String | v1: preserve exact value textually | | TIMESTAMP WITH TIME ZONE | Instant | absolute point in time | Notes: - `TIME` mappings in v1 should stay textual. A SQL time-of-day value has no date component, so mapping it to `DateTime` would require inventing one, and mapping it to `Instant` would incorrectly assign absolute-time semantics. - Because of that, `TIME` and `TIME WITH TIME ZONE` should be exposed as `String` in portable code. The original backend type is still available through `SqlColumn.nativeType`. - Name-based `SqlRow` access uses result-column labels and should fail on missing or ambiguous names. - `SqlColumn` should expose both the normalized portable `SqlType` and the original backend-reported type name. - For any non-null cell, the converted row value should match the column's portable `SqlType`. Providers should not advertise `SqlType.Date`, `SqlType.Decimal`, etc. and then return mismatched raw values for those columns. - If a backend-reported value cannot be converted to the advertised Lyng value type for that column, row production should fail with `SqlExecutionException` rather than silently degrading to some other visible type. - `ResultSet` should stay iterable, but also expose `isEmpty()` for cheap emptiness checks where possible and `size()` as a separate operation. - `ResultSet` is valid only while the owning transaction is active. - Materialized `SqlRow` values should be detached snapshots, so `transaction { tx.select(...).toList() }` is a valid pattern and the rows remain usable after transaction end. - Portable SQL parameter values should match the row conversion set: `null`, `Bool`, `Int`, `Double`, `Decimal`, `String`, `Buffer`, `Date`, `DateTime`, and `Instant`. - Lyng has a single integer type, `Int`, with 64-bit range. Portable SQL integer values should therefore normalize to `Int` rather than exposing separate `Short` / `Int` / `Long` categories. - Portable SQL placeholder syntax is positional `?` only. - The core exception model should stay small: `DatabaseException`, `SqlExecutionException`, `SqlConstraintException`, and `SqlUsageException`, plus propagated `RollbackException`. - `openDatabase(...)` should use `IllegalArgumentException` for malformed arguments detected before opening, and `DatabaseException` for runtime open failures such as authentication, connectivity, or provider initialization. - Nested `SqlTransaction.transaction {}` must provide real nested transaction semantics, usually via savepoints. If the backend cannot support this, it should throw `SqlUsageException`. - Transaction failure precedence should be: - if user code throws and rollback succeeds, rethrow the original exception - if user code throws and rollback fails, the original exception stays primary and the rollback failure is secondary/suppressed where possible - if `RollbackException` was used intentionally and rollback itself fails, the rollback failure becomes primary - if commit fails after normal block completion, the commit failure is primary - Provider URL schemes should be matched case-insensitively. Duplicate scheme registration should fail. Unknown schemes or missing providers should fail with `DatabaseException`.