Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sqlite support #171

Merged
merged 2 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
uses: engineerd/configurator@v0.0.8
with:
name: "spin"
url: "https://github.com/fermyon/spin/releases/download/v0.9.0/spin-v0.9.0-linux-amd64.tar.gz"
url: "https://github.com/fermyon/spin/releases/download/v1.3.0/spin-v1.3.0-linux-amd64.tar.gz"
pathInArchive: "spin"

- name: Run Test
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/spin-js-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ quickjs-wasm-rs = "0.1.4"
quickjs-wasm-sys = "0.1.2"
once_cell = "1.4.0"
serde_json = "1.0.87"
spin-sdk = { git = "https://github.com/fermyon/spin", rev = "b684de662ceb1138f050bc82d054806c55a33fc7", default-features = false }
spin-sdk = { git = "https://github.com/fermyon/spin", rev = "d092cf40582a707066768737f13ad0b9b8c5cff3", default-features = false, features=["experimental"] }
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "dde4694aaa6acf9370206527a798ac4ba6a8c5b8" }
rand = "0.8.5"
serde = "1.0.137"
Expand Down
88 changes: 87 additions & 1 deletion crates/spin-js-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use {
key_value::Store,
mysql, outbound_http, pg,
redis::{self, RedisResult},
sqlite,
},
std::{
collections::HashMap,
Expand Down Expand Up @@ -696,6 +697,86 @@ fn open_kv(context: &Context, _this: &Value, args: &[Value]) -> Result<Value> {
}
}

fn open_sqlite(context: &Context, _this: &Value, args: &[Value]) -> Result<Value> {
let implementation = match args {
[] => sqlite::Connection::open_default()?,
[name] => sqlite::Connection::open(&deserialize_helper(name)?)?,
_ => bail!("expected one argument (name) got {} arguments", args.len()),
};
let connection = context.object_value()?;

connection.set_property(
"execute",
context.wrap_callback({
move |context, _this: &Value, args: &[Value]| {
let (query, js_parameters) = match args {
[js_query] => (deserialize_helper(js_query)?, Vec::new()),
[js_query, js_parameters, ..] => {
let mut props = js_parameters.properties()?;
let mut parameters = Vec::new();
while props.next_key()?.is_some() {
parameters.push(props.next_value()?);
}

(deserialize_helper(js_query)?, parameters)
}
[] => bail!("expected arguments to the `query` function but got none"),
};
let parameters = js_parameters
.iter()
.map(|v| {
let p = if v.is_null() {
sqlite::ValueParam::Null
} else if v.is_repr_as_i32() {
let deserializer = &mut Deserializer::from(v.clone());
sqlite::ValueParam::Integer(i64::deserialize(deserializer)?)
} else if let Ok(s) = v.as_str() {
sqlite::ValueParam::Text(s)
} else if let Ok(s) = v.as_bytes() {
sqlite::ValueParam::Blob(s)
} else if let Ok(f) = v.as_f64() {
sqlite::ValueParam::Real(f)
} else {
bail!("invalid argument type for `parameters` argument to `execute` function: {:?}", v)
};
Ok(p)
})
.collect::<anyhow::Result<Vec<_>>>()?;
let result = implementation.execute(&query, &parameters)?;

let mut serializer = Serializer::from_context(context)?;
let columns = result.columns;
columns.serialize(&mut serializer)?;
let js_columns = serializer.value;

let js_rows = context.array_value()?;
for row in result.rows {
let js_row = context.array_value()?;
for value in row.values {
let js_value = match value {
sqlite::ValueResult::Null => context.null_value()?,
sqlite::ValueResult::Integer(i) => context.value_from_i64(i)?,
sqlite::ValueResult::Real(r) => context.value_from_f64(r)?,
sqlite::ValueResult::Text(s) => context.value_from_str(&s)?,
sqlite::ValueResult::Blob(b) => context.array_buffer_value(&b)?,
};
js_row.append_property(js_value)?;
}
js_rows.append_property(js_row)?;
}

let result = context.object_value()?;
result.set_property("columns", js_columns)?;
result.set_property("rows", js_rows)?;

Ok(result)
}
})?,
)?;

Ok(connection)
}

enum RdbmsParameter {
Boolean(bool),
Int32(i32),
Expand Down Expand Up @@ -1035,13 +1116,18 @@ fn do_init() -> Result<()> {
kv.set_property("open", context.wrap_callback(open_kv)?)?;
kv.set_property("openDefault", context.wrap_callback(open_kv)?)?;

let sqlite = context.object_value()?;
sqlite.set_property("open", context.wrap_callback(open_sqlite)?)?;
sqlite.set_property("openDefault", context.wrap_callback(open_sqlite)?)?;

let spin_sdk = context.object_value()?;
spin_sdk.set_property("config", config)?;
spin_sdk.set_property("http", http)?;
spin_sdk.set_property("redis", redis)?;
spin_sdk.set_property("mysql", mysql)?;
spin_sdk.set_property("pg", postgres)?;
spin_sdk.set_property("kv", kv)?;
spin_sdk.set_property("sqlite", sqlite)?;

let _glob = context.object_value()?;
_glob.set_property("get", context.wrap_callback(get_glob)?)?;
Expand Down Expand Up @@ -1188,6 +1274,6 @@ fn deserialize_helper(value: &Value) -> Result<String> {
let result = String::deserialize(deserializer);
match result {
Ok(value) => Ok(value),
_ => bail!("failed to deserialize string"),
_ => bail!("failed to deserialize value '{value:?}' as string"),
}
}
4 changes: 4 additions & 0 deletions examples/javascript/sqlite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
target
.spin/
11 changes: 11 additions & 0 deletions examples/javascript/sqlite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SQLite

This is a simple showcase of the SQLite feature in the Spin JS SDK.

## Running

Run the following:

```bash
spin build -u --sqlite @migration.sql
```
7 changes: 7 additions & 0 deletions examples/javascript/sqlite/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
due_date DATE,
starred BOOLEAN DEFAULT 0,
is_completed BOOLEAN DEFAULT 0
);
Loading