///|
fn[T : ToJson] write_json_show(value : T, logger : &Logger) -> Unit {
logger.write_string(value.to_json().stringify())
}
///|
pub fn bytes_to_hex(data : Bytes) -> String {
let out = StringBuilder(size_hint=data.length() * 2)
let digit = fn(v : Int) -> Char {
if v < 10 {
(48 + v).unsafe_to_char()
} else {
(87 + v).unsafe_to_char()
}
}
for b in data {
let v = b.to_int()
let hi = (v >> 4) & 0x0f
let lo = v & 0x0f
out.write_char(digit(hi))
out.write_char(digit(lo))
}
out.to_string()
}
///|
pub fn decode_json_column(
value : Json,
storage : String,
) -> Json raise ParamDecodeError {
match storage {
"bson" =>
match @bson.json_bytes_to_bytes(value) {
Some(data) =>
@bson.from_bytes(data) catch {
BsonError(msg) =>
raise ParamDecodeError("BSON decode error: \{msg}")
}
None => value
}
_ => value
}
}
///|
pub fn param_row_from_json(row : Json) -> Map[String, Param] {
let out : Map[String, Param] = Map([])
if row is Object(obj) {
for key in obj.keys() {
if obj.get(key) is Some(value) {
out.set(key, to_param(value))
}
}
}
out
}
///|
pub(all) enum WhereType {
Eq
Ne
Gt
Lt
Gte
Lte
Like
} derive(Eq, ToJson, FromJson)
///|
pub impl Show for WhereType with fn output(self : WhereType, logger : &Logger) {
write_json_show(self, logger)
}
///|
pub(all) struct Where {
col : String
value : Param
ty : WhereType
} derive(Eq, ToJson, FromJson)
///|
pub impl Show for Where with fn output(self : Where, logger : &Logger) {
write_json_show(self, logger)
}
///|
pub(all) enum OrderBy {
Asc(String)
Desc(String)
} derive(Eq, ToJson, FromJson)
///|
pub impl Show for OrderBy with fn output(self : OrderBy, logger : &Logger) {
write_json_show(self, logger)
}
///|
pub(all) enum SortDirection {
Asc
Desc
} derive(Debug, Eq, ToJson, FromJson)
///|
pub impl Show for SortDirection with fn output(
self : SortDirection,
logger : &Logger,
) {
match self {
Asc => logger.write_string("Asc")
Desc => logger.write_string("Desc")
}
}
///|
pub(all) struct Sort {
property : String
direction : SortDirection
} derive(Debug, Eq, ToJson, FromJson)
///|
pub impl Show for Sort with fn output(self : Sort, logger : &Logger) {
match self.direction {
Asc => logger.write_string("Sort(\{self.property} Asc)")
Desc => logger.write_string("Sort(\{self.property} Desc)")
}
}
///|
pub(all) struct Pageable {
page : Int
size : Int
sort : Sort?
} derive(Debug, Eq, ToJson, FromJson)
///|
pub impl Show for Pageable with fn output(self : Pageable, logger : &Logger) {
match self.sort {
Some(s) =>
logger.write_string(
"Pageable(page=\{self.page}, size=\{self.size}, sort=\{s})",
)
None =>
logger.write_string("Pageable(page=\{self.page}, size=\{self.size})")
}
}
///|
pub(all) struct Page[T] {
content : FixedArray[T]
total_elements : Int
total_pages : Int
number : Int
size : Int
first : Bool
last : Bool
empty : Bool
} derive(Eq, ToJson, FromJson)
///|
pub impl[T] Show for Page[T] with fn output(self, logger) {
logger.write_string(
"Page(content=\{self.content.length()}, total_elements=\{self.total_elements}, total_pages=\{self.total_pages}, number=\{self.number}, size=\{self.size})",
)
}
///|
pub(all) struct Set {
col : String
value : Param
} derive(Eq, ToJson, FromJson)
///|
pub impl Show for Set with fn output(self : Set, logger : &Logger) {
write_json_show(self, logger)
}
///|
pub(open) trait QueryBuilder {
fn to_query(Self) -> Query
}
///|
pub(open) trait Engine {
async fn page(Self, query : &QueryBuilder, pageable : Pageable) -> QueryResult
async fn page_raw(
Self,
sql : String,
params : FixedArray[Param],
pageable : Pageable,
) -> QueryResult
/// Execute a normalized query model (statement/raw/transaction).
async fn exec(Self, query : &QueryBuilder) -> QueryResult
///|
/// Convenience wrapper for raw SQL; internally equivalent to exec(QueryRaw(...)).
async fn exec_raw(Self, sql : String, params : FixedArray[Param]) -> QueryResult
///|
/// Apply table migration from schema model.
async fn migrate_table(Self, table_schema : @table.Table) -> QueryResult
///|
/// Close the database connection.
fn close(Self) -> Unit
}