add more methods for statements
This commit is contained in:
1 parent
cf9af57161
commit
dfb8a5b738
3 files changed
+125
-18
No files matched your search
+40
-9
@@ -2,9 +2,9 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# 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
|
# Create table if it doesn't exist
|
||||||
|
|
||||||
@@ -25,13 +25,14 @@ let some_email = "william@wbell.dev"
|
|||||||
let some_phone = "573403287534893278537592387958723"
|
let some_phone = "573403287534893278537592387958723"
|
||||||
|
|
||||||
# Insert rows
|
# Insert rows
|
||||||
db.execute(sql`BEGIN TRANSACTION;`)
|
# db.execute(sql`BEGIN TRANSACTION;`)
|
||||||
for (i in 0 until 1e2) do
|
# for (i in 0 until 1e2) do
|
||||||
db.execute(sql`
|
# db.execute(sql`
|
||||||
INSERT INTO contacts (first_name, last_name, email, phone)
|
# INSERT INTO contacts (first_name, last_name, email, phone)
|
||||||
VALUES ($(some_first_name), $(some_last_name), $(some_email), $(i))
|
# VALUES ($(some_first_name), $(some_last_name), $(some_email), $(i))
|
||||||
`)
|
# `)
|
||||||
db.execute(sql`COMMIT;`)
|
# db.execute(sql`COMMIT;`)
|
||||||
|
|
||||||
|
|
||||||
for (row in db.execute(sql`
|
for (row in db.execute(sql`
|
||||||
SELECT *
|
SELECT *
|
||||||
@@ -40,4 +41,34 @@ for (row in db.execute(sql`
|
|||||||
`)) do
|
`)) do
|
||||||
term.log(row)
|
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()
|
db.close()
|
||||||
+26
-9
@@ -8,36 +8,53 @@ let __native__ = load_native_code(`$(program.file.directory)native/bin/$(platfor
|
|||||||
|
|
||||||
class SqliteError(Exception) null
|
class SqliteError(Exception) null
|
||||||
|
|
||||||
class execute do
|
class Statement do
|
||||||
this.__init__(self, db, stmt, values) = do
|
this.__init__(self, db, stmt, values) = do
|
||||||
self.__db__ = db
|
self.__db__ = db
|
||||||
self.__stmt__ = stmt
|
self.__stmt__ = stmt
|
||||||
__native__.execute_statement(db, stmt, values, SqliteError)
|
__native__.execute_statement(db, stmt, values, SqliteError)
|
||||||
this.__iter__(self) = self
|
this.__iter__(self) = self
|
||||||
this.__next__(self) = __native__.statement_fetch(self.__db__, self.__stmt__, SqliteError)
|
this.__next__(self) = __native__.statement_fetch(self.__db__, self.__stmt__, SqliteError)
|
||||||
this.fetch_one(self) = do
|
|
||||||
|
this.one(self) = do
|
||||||
try do
|
try do
|
||||||
return self.__next__()
|
return self.__next__()
|
||||||
catch (StopIteration) do
|
catch (StopIteration) do
|
||||||
throw SqliteError("out of rows")
|
throw SqliteError("out of rows")
|
||||||
this.fetch_many(self) = do
|
this.one_first(self) = do
|
||||||
let result = []
|
try do
|
||||||
for (row in self) do
|
return __native__.statement_fetch_first(self.__db__, self.__stmt__, SqliteError)
|
||||||
result.append(row)
|
catch (StopIteration) do
|
||||||
return result
|
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
|
this.__init__(self, path) = do
|
||||||
self.__stmt_cache__ = {}
|
self.__stmt_cache__ = {}
|
||||||
self.__db_path__ = path
|
self.__db_path__ = path
|
||||||
self.__db__ = __native__.connect_database(path, SqliteError)
|
self.__db__ = __native__.connect_database(path, SqliteError)
|
||||||
|
|
||||||
this.execute(self, query) = do
|
this.execute(self, query) = do
|
||||||
|
if (!is_instance(query, SQL_QUERY)) throw TypeError("expects an sql query object")
|
||||||
let stmt
|
let stmt
|
||||||
if (query.__statement__ in self.__stmt_cache__) stmt = self.__stmt_cache__[query.__statement__]
|
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)
|
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
|
this.close(self) = do
|
||||||
for (x in self.__stmt_cache__) do
|
for (x in self.__stmt_cache__) do
|
||||||
|
|||||||
@@ -290,6 +290,64 @@ ARGON_FUNCTION(statement_fetch, {
|
|||||||
}
|
}
|
||||||
return api->throw_argon_signal(err, api->SignalStopIteration);
|
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({
|
INIT_ARGON_MODULE({
|
||||||
REGISTER_ARGON_FUNCTION(connect_database);
|
REGISTER_ARGON_FUNCTION(connect_database);
|
||||||
@@ -298,4 +356,5 @@ INIT_ARGON_MODULE({
|
|||||||
REGISTER_ARGON_FUNCTION(finalise_statement);
|
REGISTER_ARGON_FUNCTION(finalise_statement);
|
||||||
REGISTER_ARGON_FUNCTION(execute_statement);
|
REGISTER_ARGON_FUNCTION(execute_statement);
|
||||||
REGISTER_ARGON_FUNCTION(statement_fetch);
|
REGISTER_ARGON_FUNCTION(statement_fetch);
|
||||||
|
REGISTER_ARGON_FUNCTION(statement_fetch_first);
|
||||||
})
|
})
|
||||||
Reference in new issue
Block a user