5.3 KiB
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.
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:
TIMEmappings in v1 should stay textual. A SQL time-of-day value has no date component, so mapping it toDateTimewould require inventing one, and mapping it toInstantwould incorrectly assign absolute-time semantics.- Because of that,
TIMEandTIME WITH TIME ZONEshould be exposed asStringin portable code. The original backend type is still available throughSqlColumn.nativeType. - Name-based
SqlRowaccess uses result-column labels and should fail on missing or ambiguous names. SqlColumnshould expose both the normalized portableSqlTypeand 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 advertiseSqlType.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
SqlExecutionExceptionrather than silently degrading to some other visible type. ResultSetshould stay iterable, but also exposeisEmpty()for cheap emptiness checks where possible andsize()as a separate operation.ResultSetis valid only while the owning transaction is active.- Materialized
SqlRowvalues should be detached snapshots, sotransaction { 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, andInstant. - Lyng has a single integer type,
Int, with 64-bit range. Portable SQL integer values should therefore normalize toIntrather than exposing separateShort/Int/Longcategories. - Portable SQL placeholder syntax is positional
?only. - The core exception model should stay small:
DatabaseException,SqlExecutionException,SqlConstraintException, andSqlUsageException, plus propagatedRollbackException. openDatabase(...)should useIllegalArgumentExceptionfor malformed arguments detected before opening, andDatabaseExceptionfor 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 throwSqlUsageException. - 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
RollbackExceptionwas 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.