add more methods for statements

This commit is contained in:
Ugric committed 2026-08-01 20:20:58 +01:00
1 parent cf9af57161
commit dfb8a5b738
3 files changed
+125 -18

No files matched your search

+40 -9
View File
@@ -2,9 +2,9 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
import "src" expose sqlite, sql
import "src" expose Sqlite, sql
let db = sqlite("test.db")
let db = Sqlite("test.db")
# Create table if it doesn't exist
@@ -25,13 +25,14 @@ let some_email = "william@wbell.dev"
let some_phone = "573403287534893278537592387958723"
# Insert rows
db.execute(sql`BEGIN TRANSACTION;`)
for (i in 0 until 1e2) do
db.execute(sql`
INSERT INTO contacts (first_name, last_name, email, phone)
VALUES ($(some_first_name), $(some_last_name), $(some_email), $(i))
`)
db.execute(sql`COMMIT;`)
# db.execute(sql`BEGIN TRANSACTION;`)
# for (i in 0 until 1e2) do
# db.execute(sql`
# INSERT INTO contacts (first_name, last_name, email, phone)
# VALUES ($(some_first_name), $(some_last_name), $(some_email), $(i))
# `)
# db.execute(sql`COMMIT;`)
for (row in db.execute(sql`
SELECT *
@@ -40,4 +41,34 @@ for (row in db.execute(sql`
`)) do
term.log(row)
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`).many())
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`))
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`).one())
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`).maybe_one())
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`).one_first())
term.log(db.execute(sql`
SELECT *
FROM contacts
WHERE email=$(some_email)
`).maybe_one_first())
db.close()
+26 -9
View File
@@ -8,36 +8,53 @@ let __native__ = load_native_code(`$(program.file.directory)native/bin/$(platfor
class SqliteError(Exception) null
class execute do
class Statement do
this.__init__(self, db, stmt, values) = do
self.__db__ = db
self.__stmt__ = stmt
__native__.execute_statement(db, stmt, values, SqliteError)
this.__iter__(self) = self
this.__next__(self) = __native__.statement_fetch(self.__db__, self.__stmt__, SqliteError)
this.fetch_one(self) = do
this.one(self) = do
try do
return self.__next__()
catch (StopIteration) do
throw SqliteError("out of rows")
this.fetch_many(self) = do
let result = []
for (row in self) do
result.append(row)
return result
this.one_first(self) = do
try do
return __native__.statement_fetch_first(self.__db__, self.__stmt__, SqliteError)
catch (StopIteration) do
throw SqliteError("out of rows")
class sqlite do
this.maybe_one(self) = do
try do
return self.__next__()
catch (StopIteration) do
return null
this.maybe_one_first(self) = do
try do
return __native__.statement_fetch_first(self.__db__, self.__stmt__, SqliteError)
catch (StopIteration) do
return null
this.many(self) = array(self)
class Sqlite do
this.__init__(self, path) = do
self.__stmt_cache__ = {}
self.__db_path__ = path
self.__db__ = __native__.connect_database(path, SqliteError)
this.execute(self, query) = do
if (!is_instance(query, SQL_QUERY)) throw TypeError("expects an sql query object")
let stmt
if (query.__statement__ in self.__stmt_cache__) stmt = self.__stmt_cache__[query.__statement__]
else self.__stmt_cache__[query.__statement__] = stmt = __native__.new_statement(self.__db__, query.__statement__, SqliteError)
return execute(self.__db__, stmt, query.__values__)
return Statement(self.__db__, stmt, query.__values__)
this.close(self) = do
for (x in self.__stmt_cache__) do
+59
View File
@@ -290,6 +290,64 @@ ARGON_FUNCTION(statement_fetch, {
}
return api->throw_argon_signal(err, api->SignalStopIteration);
})
ARGON_FUNCTION(statement_fetch_first, {
if (api->fix_to_arg_size(3, argc, err)) {
return api->ARGON_NULL;
}
struct buffer db_buffer = api->argon_buffer_to_buffer(argv[0], err);
if (api->is_error(err))
return api->ARGON_NULL;
struct buffer statment = api->argon_buffer_to_buffer(argv[1], err);
if (api->is_error(err))
return api->ARGON_NULL;
sqlite3 **db = (sqlite3 **)db_buffer.data;
sqlite3_stmt **stmt = (sqlite3_stmt **)statment.data;
int rc = sqlite3_step(*stmt);
if (rc == SQLITE_ROW) {
int num_cols = sqlite3_column_count(*stmt);
if (num_cols) {
int col_type = sqlite3_column_type(*stmt, 0);
switch (col_type) {
case SQLITE_INTEGER:
return api->i64_to_argon(sqlite3_column_int64(*stmt, 0));
case SQLITE_FLOAT:
return api->double_to_argon(sqlite3_column_double(*stmt, 0));
case SQLITE_TEXT: {
char *str = (char *)sqlite3_column_text(*stmt, 0);
return api->string_to_argon((struct string){str, strlen(str)});
}
case SQLITE_BLOB: {
size_t size = sqlite3_column_bytes(*stmt, 0);
ArgonObject *buffer_obj = api->create_argon_buffer(size);
struct buffer buf = api->argon_buffer_to_buffer(buffer_obj, err);
if (api->is_error(err))
break;
const void *blob_buf = sqlite3_column_blob(*stmt, 0);
memcpy(buf.data, blob_buf, size);
return buffer_obj;
}
case SQLITE_NULL:
return api->ARGON_NULL;
default:
return api->throw_argon_error(err, argv[2], "unknown type %d",
col_type);
}
} else {
return api->throw_argon_error(err, argv[2], "row has no columns");
}
} else if (rc != SQLITE_DONE) {
return api->throw_argon_error(err, argv[2], "%s", sqlite3_errmsg(*db));
}
return api->throw_argon_signal(err, api->SignalStopIteration);
})
INIT_ARGON_MODULE({
REGISTER_ARGON_FUNCTION(connect_database);
@@ -298,4 +356,5 @@ INIT_ARGON_MODULE({
REGISTER_ARGON_FUNCTION(finalise_statement);
REGISTER_ARGON_FUNCTION(execute_statement);
REGISTER_ARGON_FUNCTION(statement_fetch);
REGISTER_ARGON_FUNCTION(statement_fetch_first);
})