libsql2 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +2340 -0
- data/Cargo.toml +7 -0
- data/LICENSE +21 -0
- data/README.md +161 -0
- data/ext/libsql2/Cargo.toml +16 -0
- data/ext/libsql2/extconf.rb +6 -0
- data/ext/libsql2/src/connection.rs +239 -0
- data/ext/libsql2/src/database.rs +241 -0
- data/ext/libsql2/src/error.rs +42 -0
- data/ext/libsql2/src/lib.rs +20 -0
- data/ext/libsql2/src/rows.rs +154 -0
- data/ext/libsql2/src/statement.rs +146 -0
- data/lib/libsql/blob.rb +10 -0
- data/lib/libsql/connection.rb +15 -0
- data/lib/libsql/database.rb +37 -0
- data/lib/libsql/version.rb +5 -0
- data/lib/libsql2.rb +7 -0
- metadata +72 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
use std::sync::OnceLock;
|
|
2
|
+
|
|
3
|
+
use magnus::{prelude::*, Error, ExceptionClass, RModule, Ruby};
|
|
4
|
+
|
|
5
|
+
/// Wrapper to allow ExceptionClass in OnceLock.
|
|
6
|
+
/// SAFETY: These are only accessed under the GVL (single-threaded Ruby execution).
|
|
7
|
+
#[derive(Debug)]
|
|
8
|
+
struct SyncExceptionClass(ExceptionClass);
|
|
9
|
+
unsafe impl Send for SyncExceptionClass {}
|
|
10
|
+
unsafe impl Sync for SyncExceptionClass {}
|
|
11
|
+
|
|
12
|
+
static ERROR_CLASS: OnceLock<SyncExceptionClass> = OnceLock::new();
|
|
13
|
+
static CLOSED_ERROR_CLASS: OnceLock<SyncExceptionClass> = OnceLock::new();
|
|
14
|
+
|
|
15
|
+
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
|
16
|
+
let error_class = module.define_error("Error", ruby.exception_runtime_error())?;
|
|
17
|
+
let closed_error_class = module.define_error("ClosedError", error_class)?;
|
|
18
|
+
|
|
19
|
+
ERROR_CLASS
|
|
20
|
+
.set(SyncExceptionClass(error_class))
|
|
21
|
+
.expect("error class already initialized");
|
|
22
|
+
CLOSED_ERROR_CLASS
|
|
23
|
+
.set(SyncExceptionClass(closed_error_class))
|
|
24
|
+
.expect("closed error class already initialized");
|
|
25
|
+
|
|
26
|
+
Ok(())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub fn libsql_error() -> ExceptionClass {
|
|
30
|
+
ERROR_CLASS.get().expect("error class not initialized").0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn closed_error() -> ExceptionClass {
|
|
34
|
+
CLOSED_ERROR_CLASS
|
|
35
|
+
.get()
|
|
36
|
+
.expect("closed error class not initialized")
|
|
37
|
+
.0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn to_error(e: libsql::Error) -> Error {
|
|
41
|
+
Error::new(libsql_error(), e.to_string())
|
|
42
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
use magnus::{Error, Ruby};
|
|
2
|
+
|
|
3
|
+
mod connection;
|
|
4
|
+
mod database;
|
|
5
|
+
mod error;
|
|
6
|
+
mod rows;
|
|
7
|
+
mod statement;
|
|
8
|
+
|
|
9
|
+
#[magnus::init]
|
|
10
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
11
|
+
let module = ruby.define_module("Libsql")?;
|
|
12
|
+
|
|
13
|
+
error::init(ruby, &module)?;
|
|
14
|
+
database::init(ruby, &module)?;
|
|
15
|
+
connection::init(ruby, &module)?;
|
|
16
|
+
rows::init(ruby, &module)?;
|
|
17
|
+
statement::init(ruby, &module)?;
|
|
18
|
+
|
|
19
|
+
Ok(())
|
|
20
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
use std::sync::OnceLock;
|
|
2
|
+
|
|
3
|
+
use magnus::prelude::*;
|
|
4
|
+
use magnus::{Error, IntoValue, RArray, RClass, RHash, RModule, Ruby, Value};
|
|
5
|
+
|
|
6
|
+
use crate::error;
|
|
7
|
+
|
|
8
|
+
/// Wrapper to allow RClass in OnceLock.
|
|
9
|
+
/// SAFETY: Only accessed under the GVL (single-threaded Ruby execution).
|
|
10
|
+
#[derive(Debug)]
|
|
11
|
+
struct SyncRClass(RClass);
|
|
12
|
+
unsafe impl Send for SyncRClass {}
|
|
13
|
+
unsafe impl Sync for SyncRClass {}
|
|
14
|
+
|
|
15
|
+
static BLOB_CLASS: OnceLock<SyncRClass> = OnceLock::new();
|
|
16
|
+
|
|
17
|
+
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
|
18
|
+
let rows_class = module.define_class("Rows", ruby.class_object())?;
|
|
19
|
+
rows_class.define_method("columns", magnus::method!(Rows::columns, 0))?;
|
|
20
|
+
rows_class.define_method("types", magnus::method!(Rows::types, 0))?;
|
|
21
|
+
rows_class.define_method("each", magnus::method!(Rows::each, 0))?;
|
|
22
|
+
rows_class.define_method("to_a", magnus::method!(Rows::to_a, 0))?;
|
|
23
|
+
rows_class.include_module(ruby.module_enumerable())?;
|
|
24
|
+
|
|
25
|
+
let blob_class: RClass = ruby.eval("Libsql::Blob")?;
|
|
26
|
+
BLOB_CLASS
|
|
27
|
+
.set(SyncRClass(blob_class))
|
|
28
|
+
.expect("Blob class already initialized");
|
|
29
|
+
|
|
30
|
+
Ok(())
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[magnus::wrap(class = "Libsql::Rows", free_immediately, size)]
|
|
34
|
+
pub struct Rows {
|
|
35
|
+
column_names: Vec<String>,
|
|
36
|
+
column_types: Vec<Option<String>>,
|
|
37
|
+
data: Vec<Vec<CellValue>>,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn blob_class() -> RClass {
|
|
41
|
+
BLOB_CLASS.get().expect("Blob class not initialized").0
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Represents a cell value from a query result row.
|
|
45
|
+
pub enum CellValue {
|
|
46
|
+
Null,
|
|
47
|
+
Integer(i64),
|
|
48
|
+
Real(f64),
|
|
49
|
+
Text(String),
|
|
50
|
+
Blob(Vec<u8>),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl From<libsql::Value> for CellValue {
|
|
54
|
+
fn from(val: libsql::Value) -> Self {
|
|
55
|
+
match val {
|
|
56
|
+
libsql::Value::Null => Self::Null,
|
|
57
|
+
libsql::Value::Integer(i) => Self::Integer(i),
|
|
58
|
+
libsql::Value::Real(f) => Self::Real(f),
|
|
59
|
+
libsql::Value::Text(s) => Self::Text(s),
|
|
60
|
+
libsql::Value::Blob(b) => Self::Blob(b),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
impl Rows {
|
|
66
|
+
pub fn new(
|
|
67
|
+
column_names: Vec<String>,
|
|
68
|
+
column_types: Vec<Option<String>>,
|
|
69
|
+
data: Vec<Vec<CellValue>>,
|
|
70
|
+
) -> Self {
|
|
71
|
+
Self {
|
|
72
|
+
column_names,
|
|
73
|
+
column_types,
|
|
74
|
+
data,
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn columns(&self) -> RArray {
|
|
79
|
+
let ruby = Ruby::get().expect("called from Ruby");
|
|
80
|
+
let ary = ruby.ary_new_capa(self.column_names.len());
|
|
81
|
+
for name in &self.column_names {
|
|
82
|
+
let _ = ary.push(ruby.str_new(name));
|
|
83
|
+
}
|
|
84
|
+
ary
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn types(&self) -> RArray {
|
|
88
|
+
let ruby = Ruby::get().expect("called from Ruby");
|
|
89
|
+
let ary = ruby.ary_new_capa(self.column_types.len());
|
|
90
|
+
for t in &self.column_types {
|
|
91
|
+
match t {
|
|
92
|
+
Some(s) => {
|
|
93
|
+
let _ = ary.push(ruby.str_new(s));
|
|
94
|
+
}
|
|
95
|
+
None => {
|
|
96
|
+
let _ = ary.push(ruby.qnil());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ary
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fn each(&self) -> Result<Value, Error> {
|
|
104
|
+
let ruby = Ruby::get().expect("called from Ruby");
|
|
105
|
+
if !ruby.block_given() {
|
|
106
|
+
// TODO: return Enumerator when no block given
|
|
107
|
+
return Err(Error::new(error::libsql_error(), "no block given (yield)"));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for row_data in &self.data {
|
|
111
|
+
let hash = self.row_to_hash(&ruby, row_data)?;
|
|
112
|
+
let _: Value = ruby.yield_value(hash)?;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Ok(ruby.qnil().into_value_with(&ruby))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
fn to_a(&self) -> Result<RArray, Error> {
|
|
119
|
+
let ruby = Ruby::get().expect("called from Ruby");
|
|
120
|
+
let ary = ruby.ary_new_capa(self.data.len());
|
|
121
|
+
for row_data in &self.data {
|
|
122
|
+
let hash = self.row_to_hash(&ruby, row_data)?;
|
|
123
|
+
let _ = ary.push(hash);
|
|
124
|
+
}
|
|
125
|
+
Ok(ary)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn row_to_hash(&self, ruby: &Ruby, row_data: &[CellValue]) -> Result<RHash, Error> {
|
|
129
|
+
let hash = ruby.hash_new();
|
|
130
|
+
for (i, cell) in row_data.iter().enumerate() {
|
|
131
|
+
let key = ruby.str_new(&self.column_names[i]);
|
|
132
|
+
let val = cell_to_ruby_value(ruby, cell)?;
|
|
133
|
+
hash.aset(key, val)?;
|
|
134
|
+
}
|
|
135
|
+
Ok(hash)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
fn cell_to_ruby_value(ruby: &Ruby, cell: &CellValue) -> Result<Value, Error> {
|
|
140
|
+
match cell {
|
|
141
|
+
CellValue::Null => Ok(ruby.qnil().into_value_with(ruby)),
|
|
142
|
+
CellValue::Integer(i) => Ok(ruby.into_value(*i)),
|
|
143
|
+
CellValue::Real(f) => Ok(ruby.into_value(*f)),
|
|
144
|
+
CellValue::Text(s) => {
|
|
145
|
+
let rstr = ruby.str_new(s);
|
|
146
|
+
Ok(rstr.into_value_with(ruby))
|
|
147
|
+
}
|
|
148
|
+
CellValue::Blob(bytes) => {
|
|
149
|
+
let rstr = ruby.str_from_slice(bytes);
|
|
150
|
+
let blob: Value = blob_class().funcall("new", (rstr,))?;
|
|
151
|
+
Ok(blob)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
use std::cell::RefCell;
|
|
2
|
+
use std::sync::Arc;
|
|
3
|
+
|
|
4
|
+
use magnus::{prelude::*, Error, RModule, Ruby, Value};
|
|
5
|
+
use tokio::runtime::Runtime;
|
|
6
|
+
|
|
7
|
+
use crate::connection::{params_to_libsql, ruby_array_to_params};
|
|
8
|
+
use crate::error;
|
|
9
|
+
use crate::rows::Rows;
|
|
10
|
+
|
|
11
|
+
pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
|
|
12
|
+
let class = module.define_class("Statement", ruby.class_object())?;
|
|
13
|
+
class.define_method("bind", magnus::method!(Statement::bind, 1))?;
|
|
14
|
+
class.define_method("execute", magnus::method!(Statement::execute, -1))?;
|
|
15
|
+
class.define_method("query", magnus::method!(Statement::query, -1))?;
|
|
16
|
+
class.define_method("reset", magnus::method!(Statement::reset, 0))?;
|
|
17
|
+
class.define_method("close", magnus::method!(Statement::close, 0))?;
|
|
18
|
+
class.define_method("closed?", magnus::method!(Statement::is_closed, 0))?;
|
|
19
|
+
|
|
20
|
+
Ok(())
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Internal state dropped together on close to release file descriptors.
|
|
24
|
+
struct StatementInner {
|
|
25
|
+
rt: Arc<Runtime>,
|
|
26
|
+
stmt: libsql::Statement,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[magnus::wrap(class = "Libsql::Statement", free_immediately, size)]
|
|
30
|
+
pub struct Statement {
|
|
31
|
+
inner: RefCell<Option<StatementInner>>,
|
|
32
|
+
column_names: Vec<String>,
|
|
33
|
+
column_types: Vec<Option<String>>,
|
|
34
|
+
bound_params: RefCell<Option<libsql::params::Params>>,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
impl Statement {
|
|
38
|
+
pub fn new(
|
|
39
|
+
rt: Arc<Runtime>,
|
|
40
|
+
stmt: libsql::Statement,
|
|
41
|
+
column_names: Vec<String>,
|
|
42
|
+
column_types: Vec<Option<String>>,
|
|
43
|
+
) -> Self {
|
|
44
|
+
Self {
|
|
45
|
+
inner: RefCell::new(Some(StatementInner { rt, stmt })),
|
|
46
|
+
column_names,
|
|
47
|
+
column_types,
|
|
48
|
+
bound_params: RefCell::new(None),
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn with_inner<F, T>(&self, f: F) -> Result<T, Error>
|
|
53
|
+
where
|
|
54
|
+
F: FnOnce(&StatementInner) -> Result<T, Error>,
|
|
55
|
+
{
|
|
56
|
+
let inner = self.inner.borrow();
|
|
57
|
+
let inner = inner
|
|
58
|
+
.as_ref()
|
|
59
|
+
.ok_or_else(|| Error::new(error::closed_error(), "statement is closed"))?;
|
|
60
|
+
f(inner)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn bind(&self, params: Value) -> Result<(), Error> {
|
|
64
|
+
let param_values = ruby_array_to_params(¶ms)?;
|
|
65
|
+
let libsql_params = params_to_libsql(¶m_values);
|
|
66
|
+
*self.bound_params.borrow_mut() = Some(libsql_params);
|
|
67
|
+
Ok(())
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn execute(&self, args: &[Value]) -> Result<u64, Error> {
|
|
71
|
+
let params = if args.is_empty() {
|
|
72
|
+
self.bound_params
|
|
73
|
+
.borrow_mut()
|
|
74
|
+
.take()
|
|
75
|
+
.unwrap_or(libsql::params::Params::None)
|
|
76
|
+
} else {
|
|
77
|
+
let param_values = ruby_array_to_params(&args[0])?;
|
|
78
|
+
params_to_libsql(¶m_values)
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
self.with_inner(|inner| {
|
|
82
|
+
// Reset before re-execution to allow statement reuse
|
|
83
|
+
inner.stmt.reset();
|
|
84
|
+
inner
|
|
85
|
+
.rt
|
|
86
|
+
.block_on(async { inner.stmt.execute(params).await })
|
|
87
|
+
.map(|n| n as u64)
|
|
88
|
+
.map_err(error::to_error)
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fn query(&self, args: &[Value]) -> Result<Rows, Error> {
|
|
93
|
+
let params = if args.is_empty() {
|
|
94
|
+
self.bound_params
|
|
95
|
+
.borrow_mut()
|
|
96
|
+
.take()
|
|
97
|
+
.unwrap_or(libsql::params::Params::None)
|
|
98
|
+
} else {
|
|
99
|
+
let param_values = ruby_array_to_params(&args[0])?;
|
|
100
|
+
params_to_libsql(¶m_values)
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
self.with_inner(|inner| {
|
|
104
|
+
// Reset before re-execution to allow statement reuse
|
|
105
|
+
inner.stmt.reset();
|
|
106
|
+
inner.rt.block_on(async {
|
|
107
|
+
let mut rows = inner.stmt.query(params).await.map_err(error::to_error)?;
|
|
108
|
+
|
|
109
|
+
let col_count = self.column_names.len();
|
|
110
|
+
let mut data = Vec::new();
|
|
111
|
+
while let Some(row) = rows.next().await.map_err(error::to_error)? {
|
|
112
|
+
let mut row_data = Vec::with_capacity(col_count);
|
|
113
|
+
for i in 0..col_count {
|
|
114
|
+
let val = row.get_value(i as i32).map_err(error::to_error)?;
|
|
115
|
+
row_data.push(val.into());
|
|
116
|
+
}
|
|
117
|
+
data.push(row_data);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Ok(Rows::new(
|
|
121
|
+
self.column_names.clone(),
|
|
122
|
+
self.column_types.clone(),
|
|
123
|
+
data,
|
|
124
|
+
))
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fn reset(&self) -> Result<(), Error> {
|
|
130
|
+
self.with_inner(|inner| {
|
|
131
|
+
inner.stmt.reset();
|
|
132
|
+
Ok(())
|
|
133
|
+
})?;
|
|
134
|
+
*self.bound_params.borrow_mut() = None;
|
|
135
|
+
Ok(())
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fn close(&self) -> Result<(), Error> {
|
|
139
|
+
let _ = self.inner.borrow_mut().take();
|
|
140
|
+
Ok(())
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
fn is_closed(&self) -> bool {
|
|
144
|
+
self.inner.borrow().is_none()
|
|
145
|
+
}
|
|
146
|
+
}
|
data/lib/libsql/blob.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Libsql
|
|
4
|
+
class Connection
|
|
5
|
+
def transaction
|
|
6
|
+
execute("BEGIN")
|
|
7
|
+
result = yield self
|
|
8
|
+
execute("COMMIT")
|
|
9
|
+
result
|
|
10
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
11
|
+
execute("ROLLBACK")
|
|
12
|
+
raise
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Libsql
|
|
4
|
+
class Database
|
|
5
|
+
class << self
|
|
6
|
+
alias _open open
|
|
7
|
+
|
|
8
|
+
def open(path, **opts)
|
|
9
|
+
db = opts.empty? ? _open(path) : _open(path, opts)
|
|
10
|
+
if block_given?
|
|
11
|
+
begin
|
|
12
|
+
yield db
|
|
13
|
+
ensure
|
|
14
|
+
db.close
|
|
15
|
+
end
|
|
16
|
+
else
|
|
17
|
+
db
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
alias _connect connect
|
|
23
|
+
|
|
24
|
+
def connect
|
|
25
|
+
conn = _connect
|
|
26
|
+
if block_given?
|
|
27
|
+
begin
|
|
28
|
+
yield conn
|
|
29
|
+
ensure
|
|
30
|
+
conn.close
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
conn
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/libsql2.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: libsql2
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- speria-jp
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rb_sys
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.9'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.9'
|
|
26
|
+
description: Native Ruby bindings for libSQL database, built with Rust (magnus + libsql
|
|
27
|
+
crate)
|
|
28
|
+
executables: []
|
|
29
|
+
extensions:
|
|
30
|
+
- ext/libsql2/extconf.rb
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- Cargo.lock
|
|
34
|
+
- Cargo.toml
|
|
35
|
+
- LICENSE
|
|
36
|
+
- README.md
|
|
37
|
+
- ext/libsql2/Cargo.toml
|
|
38
|
+
- ext/libsql2/extconf.rb
|
|
39
|
+
- ext/libsql2/src/connection.rs
|
|
40
|
+
- ext/libsql2/src/database.rs
|
|
41
|
+
- ext/libsql2/src/error.rs
|
|
42
|
+
- ext/libsql2/src/lib.rs
|
|
43
|
+
- ext/libsql2/src/rows.rs
|
|
44
|
+
- ext/libsql2/src/statement.rs
|
|
45
|
+
- lib/libsql/blob.rb
|
|
46
|
+
- lib/libsql/connection.rb
|
|
47
|
+
- lib/libsql/database.rb
|
|
48
|
+
- lib/libsql/version.rb
|
|
49
|
+
- lib/libsql2.rb
|
|
50
|
+
homepage: https://github.com/speria-jp/libsql-ruby2
|
|
51
|
+
licenses:
|
|
52
|
+
- MIT
|
|
53
|
+
metadata:
|
|
54
|
+
rubygems_mfa_required: 'true'
|
|
55
|
+
rdoc_options: []
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '3.4'
|
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
requirements: []
|
|
69
|
+
rubygems_version: 4.0.3
|
|
70
|
+
specification_version: 4
|
|
71
|
+
summary: Ruby bindings for libSQL using libsql crate + magnus
|
|
72
|
+
test_files: []
|