1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-10 01:02:56 +03:00
Files
sqlite/ext/fiddle/sqlite3-api.js
stephan d60b7275c3 WASM OO wrapper #1: prepare() and bind() APIs are in place but are untested, pending fetch/get APIs.
FossilOrigin-Name: 84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39
2022-05-22 14:07:44 +00:00

167 lines
7.6 KiB
JavaScript

/*
2022-05-22
The author disclaims copyright to this source code. In place of a
legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
***********************************************************************
This file is intended to be loaded after loading
sqlite3-module.wasm. It sets one of any number of potential
bindings using that API, this one as closely matching the C-native
API as is feasible.
Note that this file is not named sqlite3.js because that file gets
generated by emscripten as the JS-glue counterpart of sqlite3.wasm.
The API gets installed as self.sqlite3, where self is expected to be
either the global window or Worker object.
Because using this API properly requires some degree of WASM-related
magic, it is not recommended that this API be used as-is in
client-level code, but instead is intended to be used as a basis for
APIs more appropriate for high-level client code.
This file installs namespace.sqlite3, where namespace is `self`,
meaning either the global window or worker, depending on where this
is loaded from.
*/
(function(namespace){
/* For reference: sql.js does essentially everything we want and
it solves much of the wasm-related voodoo, but we'll need a
different structure because we want the db connection to run in
a worker thread and feed data back into the main
thread. Regardless of those differences, it makes a great point
of reference:
https://github.com/sql-js/sql.js
Some of the specific design goals here:
- Bind a low-level sqlite3 API which is close to the native one
in terms of usage.
- Create a higher-level one, more akin to sql.js and
node.js-style implementations. This one would speak directly
to the low-level API. This API could be used by clients who
import the low-level API directly into their main thread
(which we don't want to recommend but also don't want to
outright forbid).
- Create a second higher-level one which speaks to the
low-level API via worker messages. This one would be intended
for use in the main thread, talking to the low-level UI via
worker messages. Because workers have only a single message
channel, some acrobatics will be needed here to feed async
work results back into client-side callbacks (as those
callbacks cannot simply be passed to the worker). Exactly
what those acrobatics should look like is not yet entirely
clear and much experimentation is pending.
*/
/**
Set up the main sqlite3 binding API here, mimicking the C API as
closely as we can.
Attribution: though not a direct copy/paste, much of what
follows is strongly influenced by the sql.js implementation.
*/
const api = {
/* It is important that the following integer values match
those from the C code. Ideally we could fetch them from the
C API, e.g., in the form of a JSON object, but getting that
JSON string constructed within our current confised is
currently not worth the effort. */
/* Minimum subset of sqlite result codes we'll need. */
SQLITE_OK: 0,
SQLITE_ROW: 100,
SQLITE_DONE: 101,
/* sqlite data types */
SQLITE_INTEGER: 1,
SQLITE_FLOAT: 2,
SQLITE_TEXT: 3,
SQLITE_BLOB: 4,
SQLITE_NULL: 5,
/* sqlite encodings, used for creating UDFs, noting that we
will only support UTF8. */
SQLITE_UTF8: 1
};
const cwrap = Module.cwrap;
[/* C-side functions to bind. Each entry is an array with 3 or 4
elements:
["c-side name",
"result type" (cwrap() syntax),
[arg types in cwrap() syntax]
]
If it has 4 elements, the first one is an alternate name to
use for the JS-side binding. That's required when overloading
a binding for two different uses.
*/
["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]],
["sqlite3_bind_double","number",["number", "number", "number"]],
["sqlite3_bind_int","number",["number", "number", "number"]],
["sqlite3_bind_int64","number",["number", "number", "number"]],
["sqlite3_bind_null","void",["number"]],
["sqlite3_bind_parameter_index","number",["number", "string"]],
["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]],
["sqlite3_changes", "number", ["number"]],
["sqlite3_clear_bindings","number",["number"]],
["sqlite3_close_v2", "number", ["number"]],
["sqlite3_column_blob","number", ["number", "number"]],
["sqlite3_column_bytes","number",["number", "number"]],
["sqlite3_column_count", "number", ["number"]],
["sqlite3_column_count","number",["number"]],
["sqlite3_column_double","number",["number", "number"]],
["sqlite3_column_name","string",["number", "number"]],
["sqlite3_column_text","string",["number", "number"]],
["sqlite3_column_type","number",["number", "number"]],
["sqlite3_create_function_v2", "number",
["number", "string", "number", "number","number",
"number", "number", "number", "number"]],
["sqlite3_data_count", "number", ["number"]],
["sqlite3_db_filename", "string", ["number", "string"]],
["sqlite3_errmsg", "string", ["number"]],
["sqlite3_exec", "number", ["number", "string", "number", "number", "number"]],
["sqlite3_finalize", "number", ["number"]],
["sqlite3_interrupt", "void", ["number"]],
["sqlite3_libversion", "string", []],
["sqlite3_open", "number", ["string", "number"]],
["sqlite3_prepare_v2", "number", ["number", "string", "number", "number", "number"]],
["sqlite3_prepare_v2_sqlptr", "sqlite3_prepare_v2",
/* Impl which requires that the 2nd argument be a pointer to
the SQL, instead of a string. This is used for cases where
we require a non-NULL value for the final argument. We may
or may not need this, depending on how our higher-level
API shapes up, but this code's spiritual guide (sql.js)
uses it we we'll include it. */
"number", ["number", "number", "number", "number", "number"]],
["sqlite3_reset", "number", ["number"]],
["sqlite3_result_blob",null,["number", "number", "number", "number"]],
["sqlite3_result_double",null,["number", "number"]],
["sqlite3_result_error",null,["number", "string", "number"]],
["sqlite3_result_int",null,["number", "number"]],
["sqlite3_result_null",null,["number"]],
["sqlite3_result_text",null,["number", "string", "number", "number"]],
["sqlite3_sourceid", "string", []],
["sqlite3_step", "number", ["number"]],
["sqlite3_value_blob", "number", ["number"]],
["sqlite3_value_bytes","number",["number"]],
["sqlite3_value_double","number",["number"]],
["sqlite3_value_text", "string", ["number"]],
["sqlite3_value_type", "number", ["number"]]
//["sqlite3_sql", "string", ["number"]],
//["sqlite3_normalized_sql", "string", ["number"]]
].forEach(function(a){
const k = (4==a.length) ? a.shift() : a[0];
api[k] = cwrap.apply(this, a);
});
//console.debug("libversion =",api.sqlite3_libversion());
namespace.sqlite3 = api;
})(self/*worker or window*/);