211 lines
7.3 KiB
Plaintext
211 lines
7.3 KiB
Plaintext
package lyng.io.db
|
|
|
|
/*
|
|
Portable value categories exposed by the Lyng SQL layer and used in
|
|
`SqlColumn`.
|
|
*/
|
|
enum SqlType {
|
|
Binary, String, Int, Double, Decimal,
|
|
Bool, Instant, Date, DateTime
|
|
}
|
|
|
|
extern class SqlColumn {
|
|
val name: String
|
|
val sqlType: SqlType
|
|
val nullable: Bool
|
|
/*
|
|
Original database type name as reported by the backend, such as
|
|
VARCHAR, TEXT, INT8, TIMESTAMPTZ, or BYTEA.
|
|
*/
|
|
val nativeType: String
|
|
}
|
|
|
|
extern class SqlRow {
|
|
/* Number of columns in the row */
|
|
val size: Int
|
|
val values: List<Object?>
|
|
|
|
/*
|
|
Return the already converted Lyng value for a column addressed by
|
|
index or output column label. SQL NULL is returned as null.
|
|
|
|
Name lookup uses result-column labels. If several columns share the same
|
|
label, name-based access is ambiguous and should fail. Missing column
|
|
names and invalid indexes should also fail.
|
|
*/
|
|
override fun getAt(indexOrName: String | Int): Object?
|
|
}
|
|
|
|
/*
|
|
A result set is valid only while its owning transaction is active.
|
|
|
|
Implementations may stream rows or buffer them internally, but:
|
|
- rows must be exposed through normal iteration
|
|
- iteration to the end or canceled iteration should close the underlying
|
|
resources automatically
|
|
- using the result set after its transaction ends is invalid
|
|
- rows obtained from the result set stay usable after the owning
|
|
transaction ends once they have been materialized
|
|
|
|
Calling `toList()` while the transaction is active is the normal way to
|
|
detach rows for use after the transaction block returns.
|
|
*/
|
|
extern class ResultSet : Iterable<SqlRow> {
|
|
/*
|
|
Column metadata for the result rows, in positional order.
|
|
*/
|
|
val columns: List<SqlColumn>
|
|
|
|
/*
|
|
Number of rows if the implementation can determine it. Implementations
|
|
may need to consume or buffer the whole result in order to answer, but
|
|
this must not change visible later iteration behavior.
|
|
*/
|
|
fun size(): Int
|
|
|
|
/*
|
|
Fast emptiness check when the implementation can provide it without
|
|
consuming the result. Implementations may still peek or buffer
|
|
internally, but this must not change visible later iteration behavior.
|
|
*/
|
|
override fun isEmpty(): Bool
|
|
}
|
|
|
|
extern class ExecutionResult {
|
|
val affectedRowsCount: Int
|
|
|
|
/*
|
|
Return implementation-supported auto-generated values produced by
|
|
`execute`. This is intentionally stricter than arbitrary SQL result
|
|
sets: statements such as INSERT/UPDATE/DELETE ... RETURNING should be
|
|
executed with `select`, not exposed here.
|
|
|
|
The returned result set has the same transaction-scoped lifetime as any
|
|
other result set.
|
|
|
|
If the statement produced no generated values, the returned result set
|
|
is empty. Call `toList()` if generated-key rows must outlive the
|
|
transaction.
|
|
*/
|
|
fun getGeneratedKeys(): ResultSet
|
|
}
|
|
|
|
extern class DatabaseException: Exception
|
|
extern class SqlExecutionException: DatabaseException
|
|
extern class SqlConstraintException: SqlExecutionException
|
|
extern class SqlUsageException: DatabaseException
|
|
|
|
/*
|
|
Special exception to be thrown from `SqlTransaction.transaction` when an
|
|
intentional rollback is requested without treating it as a backend failure.
|
|
|
|
It causes rollback and is propagated to the caller, but should not be
|
|
treated as a backend/driver failure.
|
|
|
|
If rollback itself fails, that rollback failure becomes the primary backend
|
|
error instead.
|
|
*/
|
|
extern class RollbackException: Exception
|
|
|
|
/*
|
|
Transaction represents a database transaction.
|
|
|
|
Important: a transaction has no explicit commit; instead it commits when
|
|
leaving the transaction block normally.
|
|
|
|
If the transaction block throws any exception not caught inside the calling
|
|
code, it will be rolled back.
|
|
*/
|
|
extern class SqlTransaction {
|
|
/*
|
|
Execute a SQL statement that returns rows. This includes plain SELECT
|
|
queries and database-specific DML statements with row-returning clauses
|
|
such as RETURNING or OUTPUT.
|
|
|
|
Portable SQL uses positional `?` placeholders only.
|
|
|
|
Portable bindable values are:
|
|
- null
|
|
- Bool
|
|
- Int, Double, Decimal
|
|
- String
|
|
- Buffer
|
|
- Date, DateTime, Instant
|
|
|
|
Unsupported parameter values should fail with `SqlUsageException`.
|
|
*/
|
|
fun select(clause: String, params...): ResultSet
|
|
|
|
/*
|
|
Execute a SQL statement for side effects. Use `select` for any statement
|
|
whose primary result is a row set.
|
|
|
|
Parameters follow the same binding rules as `select`.
|
|
*/
|
|
fun execute(clause: String, params...): ExecutionResult
|
|
|
|
/*
|
|
Create a nested transaction with real nested semantics, typically using
|
|
database savepoints.
|
|
|
|
If the backend cannot provide real nested transaction semantics, this
|
|
call should fail with `SqlUsageException` rather than flattening into
|
|
the outer transaction.
|
|
|
|
Failure inside the nested transaction rolls back only the nested scope;
|
|
the outer transaction remains active unless the exception is allowed to
|
|
propagate further.
|
|
*/
|
|
fun transaction<T>(block: (SqlTransaction) -> T): T
|
|
}
|
|
|
|
extern class Database {
|
|
/*
|
|
Open a transaction. Any pooling, physical connection lifecycle, and
|
|
implementation-specific configuration are owned by the database
|
|
implementation and hidden from the user.
|
|
|
|
The transaction commits when the block finishes normally,
|
|
and rolls back if the block exits with an uncaught exception.
|
|
|
|
Failure precedence is:
|
|
- user exception + successful rollback -> original exception escapes
|
|
- user exception + rollback failure -> original exception stays primary
|
|
- RollbackException + rollback failure -> rollback failure is primary
|
|
- commit failure after normal completion -> commit failure is primary
|
|
*/
|
|
fun transaction<T>(block: (SqlTransaction) -> T): T
|
|
}
|
|
|
|
/*
|
|
Register a database provider for a URL scheme.
|
|
|
|
Provider modules should call this during module initialization when first
|
|
imported. Scheme matching is case-insensitive and normalized to lowercase.
|
|
|
|
Registering the same scheme more than once should fail.
|
|
*/
|
|
extern fun registerDatabaseProvider(
|
|
scheme: String,
|
|
opener: (String, Map<String, Object?>) -> Database
|
|
)
|
|
|
|
/*
|
|
The mandatory generic entry point for all providers. It opens a database
|
|
handle from a provider-specific connection URL plus extra parameters.
|
|
|
|
Providers may expose additional typed constructors such as `openSqlite(...)`
|
|
or `openPostgres(...)`, but `openDatabase(...)` should remain available for
|
|
configuration-driven usage.
|
|
|
|
It should throw IllegalArgumentException for malformed connection URLs or
|
|
invalid extra parameter shapes detected before opening the backend.
|
|
Runtime opening failures such as authentication, connectivity, or provider
|
|
initialization errors should be reported as DatabaseException.
|
|
|
|
The matching provider must already be registered, normally because its
|
|
module was imported and executed. Unknown schemes or missing providers
|
|
should fail with DatabaseException.
|
|
*/
|
|
extern fun openDatabase(connectionUrl: String, extraParams: Map<String, Object?>): Database
|