sqlite

    libsqlite3 bindings for MoonBit

    native
    sqlite
    js
    Download zip
    Author
    Version
    0.3.1
    License
    MIT
    Last updated
    4 months ago
    Downloads
    9K

    Dependencies

    #sqlite.mbt

    SQLite database bindings for MoonBit - supports both native (C FFI) and JavaScript (Node.js) targets.

    #Features

    • Database management (open, close)
    • SQL execution
    • Type-safe prepared statements with SqlValue enum
    • Array-based parameter binding with bind_all()
    • Iterator-based query results with iter()
    • Transaction support (BEGIN, COMMIT, ROLLBACK, SAVEPOINT)
    • UTF-8 text encoding
    • Cross-target compatibility (native and js)

    #Requirements

    #Native target

    • libsqlite3
      • Ubuntu: apt install libsqlite3-dev
      • macOS: Pre-installed

    #JavaScript target

    • Node.js 22.5.0+ (requires node:sqlite built-in module)

    #Installation

    moon add mizchi/sqlite

    Add to your moon.pkg.json:

    { "import": ["mizchi/sqlite"], "link": { "native": { "cc-link-flags": "-lsqlite3" } } }

    #Usage

    let db = match @sqlite.Database::open(":memory:") {
    Some(d) => d
    None => {
    println("Failed to open database")
    return
    }
    }

    // Create table
    db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")

    // Insert data with bind_all()
    match db.prepare("INSERT INTO users (name, age) VALUES (?, ?)") {
    Some(stmt) => {
    stmt.bind_all([Text(string_to_bytes("Alice")), Int(30)]) |> ignore
    stmt.execute() |> ignore
    stmt.finalize()
    }
    None => println("Failed to prepare statement")
    }

    // Query with iterator
    match db.query("SELECT id, name, age FROM users") {
    Some(stmt) => {
    for row in stmt.iter() {
    let id = row.column_int(0)
    let age = row.column_int(2)
    println("id=\{id}, age=\{age}")
    }
    stmt.finalize()
    }
    None => println("Failed to prepare statement")
    }

    db.close()

    #Build & Test

    # Native target moon build --target native moon test --target native # JavaScript target moon build --target js moon test --target js

    #API

    #High-level API

    Database operations:
    • Database::open(path: String) -> Database? - Open database
    • Database::close(self) - Close database
    • Database::exec(self, sql: String) -> Bool - Execute SQL
    • Database::prepare(self, sql: String) -> Statement? - Prepare statement
    • Database::query(self, sql: String) -> Statement? - Prepare SELECT statement

    Transaction API:
    • Database::begin(self) -> Bool - Begin transaction
    • Database::begin_immediate(self) -> Bool - Begin immediate transaction
    • Database::begin_exclusive(self) -> Bool - Begin exclusive transaction
    • Database::commit(self) -> Bool - Commit transaction
    • Database::rollback(self) -> Bool - Rollback transaction
    • Database::savepoint(self, name: String) -> Bool - Create savepoint
    • Database::release(self, name: String) -> Bool - Release savepoint
    • Database::rollback_to(self, name: String) -> Bool - Rollback to savepoint

    Statement operations:
    • Statement::bind(idx: Int, value: SqlValue) -> Bool - Bind single parameter
    • Statement::bind_all(values: Array[SqlValue]) -> Bool - Bind all parameters at once
    • Statement::execute() -> Bool - Execute INSERT/UPDATE/DELETE
    • Statement::step() -> Bool - Step to next row (for SELECT)
    • Statement::column(col: Int) -> SqlValue - Get column value as SqlValue
    • Statement::column_int(col: Int) -> Int - Get column as Int
    • Statement::column_text(col: Int) -> Bytes - Get column as Bytes
    • Statement::column_count() -> Int - Get number of columns
    • Statement::iter() -> Iter[Statement] - Create iterator for query results
    • Statement::reset() - Reset statement
    • Statement::finalize() - Finalize statement

    SqlValue enum:
    pub enum SqlValue {
    Null
    Int(Int)
    Int64(Int64)
    Double(Double)
    Text(Bytes)
    Blob(Bytes)
    }

    #Target Compatibility

    APINativeJSNotes
    Database::open
    Database::close
    Database::exec
    Database::prepare
    Database::query
    Database::begin
    Database::commit
    Database::rollback
    Database::savepoint
    Database::changesJS uses SELECT changes()
    Database::last_insert_rowidJS uses SELECT last_insert_rowid()
    Database::total_changesJS uses SELECT total_changes()
    Database::errcode⚠️JS always returns 0
    Database::errmsg⚠️JS always returns empty
    Database::extended_errcode⚠️JS always returns 0
    Database::busy_timeout⚠️JS always returns false
    Database::get_autocommit⚠️JS always returns true
    Statement::bind
    Statement::bind_all
    Statement::execute
    Statement::step
    Statement::columnInteger type differs (see below)
    Statement::column_int
    Statement::column_text
    Statement::column_count
    Statement::iter
    Statement::reset
    Statement::finalize

    #Known Differences

    1. Integer column type: Native returns Int64, JS returns Int for integer columns via column().

    2. Int64 binding: Node.js SQLite doesn't support BigInt as bind parameter. Int64 values are converted to Number (may lose precision for very large integers).

    3. Error handling: JS target has limited error information. Use try-catch for JS error handling.

    4. Low-level API: Native target exposes low-level C FFI functions (e.g., sqlite_*). These are not available on JS target.

    #License

    MIT License

    Database

    pub struct Database {
    // private fields
    }

    Database::begin

    fn Database::begin(self : Database) -> Bool

    Database::begin_exclusive

    fn Database::begin_exclusive(self : Database) -> Bool

    Database::begin_immediate

    fn Database::begin_immediate(self : Database) -> Bool

    Database::busy_timeout

    fn Database::busy_timeout(self : Database, ms : Int) -> Bool

    Database::changes

    fn Database::changes(self : Database) -> Int

    Database::close

    fn Database::close(self : Database) -> Unit

    Database::commit

    fn Database::commit(self : Database) -> Bool

    Database::errcode

    fn Database::errcode(self : Database) -> Int

    Database::errmsg

    fn Database::errmsg(self : Database) -> Bytes

    Database::exec

    fn Database::exec(self : Database, sql : String) -> Bool

    Database::extended_errcode

    fn Database::extended_errcode(self : Database) -> Int

    Database::get_autocommit

    fn Database::get_autocommit(self : Database) -> Bool

    Database::last_insert_rowid

    fn Database::last_insert_rowid(self : Database) -> Int64

    Database::open

    fn Database::open(path : String) -> Database?

    Database::prepare

    fn Database::prepare(self : Database, sql : String) -> Statement?

    Database::query

    fn Database::query(self : Database, sql : String) -> Statement?

    Database::release

    fn Database::release(self : Database, name : String) -> Bool

    Database::rollback

    fn Database::rollback(self : Database) -> Bool

    Database::rollback_to

    fn Database::rollback_to(self : Database, name : String) -> Bool

    Database::savepoint

    fn Database::savepoint(self : Database, name : String) -> Bool

    Database::total_changes

    fn Database::total_changes(self : Database) -> Int

    SqlValue

    pub(all) enum SqlValue {
    Null
    Int(Int)
    Int64(Int64)
    Double(Double)
    Text(Bytes)
    Blob(Bytes)
    }

    Sqlite3

    type Sqlite3

    Sqlite3Stmt

    type Sqlite3Stmt

    Statement

    pub struct Statement {
    // private fields
    }

    Statement::bind

    fn Statement::bind(self : Statement, idx : Int, value : SqlValue) -> Bool

    Statement::bind_all

    fn Statement::bind_all(self : Statement, values : Array[SqlValue]) -> Bool

    Statement::column

    fn Statement::column(self : Statement, col : Int) -> SqlValue

    Statement::column_count

    fn Statement::column_count(self : Statement) -> Int

    Statement::column_int

    fn Statement::column_int(self : Statement, col : Int) -> Int

    Statement::column_name

    fn Statement::column_name(self : Statement, col : Int) -> String

    Return the declared name of the col-th column in the result set. Returns "" when col is out of range. Mirrors sqlite3_column_name.

    Statement::column_text

    fn Statement::column_text(self : Statement, col : Int) -> Bytes

    Statement::execute

    fn Statement::execute(self : Statement) -> Bool

    Statement::finalize

    fn Statement::finalize(self : Statement) -> Unit

    Statement::iter

    fn Statement::iter(self : Statement) -> Iter[Statement]

    Statement::reset

    fn Statement::reset(self : Statement) -> Unit

    Statement::step

    fn Statement::step(self : Statement) -> Bool

    SQLITE_BLOB

    let SQLITE_BLOB : Int

    SQLITE_DONE

    let SQLITE_DONE : Int

    SQLITE_FLOAT

    let SQLITE_FLOAT : Int

    SQLITE_INTEGER

    let SQLITE_INTEGER : Int

    SQLITE_LIMIT_ATTACHED

    let SQLITE_LIMIT_ATTACHED : Int

    SQLITE_LIMIT_COLUMN

    let SQLITE_LIMIT_COLUMN : Int

    SQLITE_LIMIT_COMPOUND_SELECT

    let SQLITE_LIMIT_COMPOUND_SELECT : Int

    SQLITE_LIMIT_EXPR_DEPTH

    let SQLITE_LIMIT_EXPR_DEPTH : Int

    SQLITE_LIMIT_FUNCTION_ARG

    let SQLITE_LIMIT_FUNCTION_ARG : Int

    SQLITE_LIMIT_LENGTH

    let SQLITE_LIMIT_LENGTH : Int

    SQLITE_LIMIT_LIKE_PATTERN_LENGTH

    let SQLITE_LIMIT_LIKE_PATTERN_LENGTH : Int

    SQLITE_LIMIT_SQL_LENGTH

    let SQLITE_LIMIT_SQL_LENGTH : Int

    SQLITE_LIMIT_TRIGGER_DEPTH

    let SQLITE_LIMIT_TRIGGER_DEPTH : Int

    SQLITE_LIMIT_VARIABLE_NUMBER

    let SQLITE_LIMIT_VARIABLE_NUMBER : Int

    SQLITE_LIMIT_VDBE_OP

    let SQLITE_LIMIT_VDBE_OP : Int

    SQLITE_NULL

    let SQLITE_NULL : Int

    SQLITE_OPEN_CREATE

    let SQLITE_OPEN_CREATE : Int

    SQLITE_OPEN_FULLMUTEX

    let SQLITE_OPEN_FULLMUTEX : Int

    SQLITE_OPEN_MEMORY

    let SQLITE_OPEN_MEMORY : Int

    SQLITE_OPEN_NOMUTEX

    let SQLITE_OPEN_NOMUTEX : Int

    SQLITE_OPEN_READONLY

    let SQLITE_OPEN_READONLY : Int

    SQLITE_OPEN_READWRITE

    let SQLITE_OPEN_READWRITE : Int

    SQLITE_ROW

    let SQLITE_ROW : Int

    SQLITE_TEXT

    let SQLITE_TEXT : Int

    sqlite_bind_blob

    fn sqlite_bind_blob(stmt : Sqlite3Stmt, idx : Int, blob : Bytes) -> Int

    sqlite_bind_double

    fn sqlite_bind_double(stmt : Sqlite3Stmt, idx : Int, value : Double) -> Int

    sqlite_bind_int

    fn sqlite_bind_int(stmt : Sqlite3Stmt, idx : Int, value : Int) -> Int

    sqlite_bind_int64

    fn sqlite_bind_int64(stmt : Sqlite3Stmt, idx : Int, value : Int64) -> Int

    sqlite_bind_null

    fn sqlite_bind_null(stmt : Sqlite3Stmt, idx : Int) -> Int

    sqlite_bind_parameter_count

    fn sqlite_bind_parameter_count(stmt : Sqlite3Stmt) -> Int

    sqlite_bind_parameter_index

    fn sqlite_bind_parameter_index(stmt : Sqlite3Stmt, name : Bytes) -> Int

    sqlite_bind_parameter_name

    fn sqlite_bind_parameter_name(stmt : Sqlite3Stmt, idx : Int) -> Bytes

    sqlite_bind_text

    fn sqlite_bind_text(stmt : Sqlite3Stmt, idx : Int, text : Bytes) -> Int

    sqlite_busy_timeout

    fn sqlite_busy_timeout(db : Sqlite3, ms : Int) -> Int

    sqlite_changes

    fn sqlite_changes(db : Sqlite3) -> Int

    sqlite_clear_bindings

    fn sqlite_clear_bindings(stmt : Sqlite3Stmt) -> Int

    sqlite_column_blob

    fn sqlite_column_blob(stmt : Sqlite3Stmt, col : Int) -> Bytes

    sqlite_column_bytes

    fn sqlite_column_bytes(stmt : Sqlite3Stmt, col : Int) -> Int

    sqlite_column_count

    fn sqlite_column_count(stmt : Sqlite3Stmt) -> Int

    sqlite_column_double

    fn sqlite_column_double(stmt : Sqlite3Stmt, col : Int) -> Double

    sqlite_column_int

    fn sqlite_column_int(stmt : Sqlite3Stmt, col : Int) -> Int

    sqlite_column_int64

    fn sqlite_column_int64(stmt : Sqlite3Stmt, col : Int) -> Int64

    sqlite_column_name

    fn sqlite_column_name(stmt : Sqlite3Stmt, col : Int) -> Bytes

    sqlite_column_text

    fn sqlite_column_text(stmt : Sqlite3Stmt, col : Int) -> Bytes

    sqlite_column_type

    fn sqlite_column_type(stmt : Sqlite3Stmt, col : Int) -> Int

    sqlite_db_filename

    fn sqlite_db_filename(db : Sqlite3, dbname : Bytes) -> Bytes

    sqlite_db_readonly

    fn sqlite_db_readonly(db : Sqlite3, dbname : Bytes) -> Int

    sqlite_errcode

    fn sqlite_errcode(db : Sqlite3) -> Int

    sqlite_errmsg

    fn sqlite_errmsg(db : Sqlite3) -> Bytes

    sqlite_errstr

    fn sqlite_errstr(errcode : Int) -> Bytes

    sqlite_expanded_sql

    fn sqlite_expanded_sql(stmt : Sqlite3Stmt) -> Bytes

    sqlite_extended_errcode

    fn sqlite_extended_errcode(db : Sqlite3) -> Int

    sqlite_finalize

    fn sqlite_finalize(stmt : Sqlite3Stmt) -> Unit

    sqlite_get_autocommit

    fn sqlite_get_autocommit(db : Sqlite3) -> Int

    sqlite_interrupt

    fn sqlite_interrupt(db : Sqlite3) -> Unit

    sqlite_last_insert_rowid

    fn sqlite_last_insert_rowid(db : Sqlite3) -> Int64

    sqlite_limit

    fn sqlite_limit(db : Sqlite3, id : Int, newVal : Int) -> Int

    sqlite_open_v2

    fn sqlite_open_v2(filename : Bytes, flags : Int, vfs : Bytes) -> Sqlite3

    sqlite_prepare

    fn sqlite_prepare(db : Sqlite3, sql : Bytes) -> Sqlite3Stmt

    sqlite_sql

    fn sqlite_sql(stmt : Sqlite3Stmt) -> Bytes

    sqlite_step

    fn sqlite_step(stmt : Sqlite3Stmt) -> Int

    sqlite_stmt_is_null

    fn sqlite_stmt_is_null(stmt : Sqlite3Stmt) -> Int

    sqlite_stmt_readonly

    fn sqlite_stmt_readonly(stmt : Sqlite3Stmt) -> Int

    sqlite_total_changes

    fn sqlite_total_changes(db : Sqlite3) -> Int