turso_libsql 0.0.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
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6fafb9e0e973d8423ef2dd4962d955993e41a2fad35b6944586029baafb7b1c5
|
4
|
+
data.tar.gz: 31ce80e48a0d003f909904a01042f117d4886a3f35f1a42f83fed6b91d55534a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 75e05163dc75b52ebd907ca253cac6458c192e74e3c1f06fdb29ee78e387ac4ddaca0297006c47e3745843cc5457d3a9f587b3cbe0c2af50f5f0aa29d4c1de37
|
7
|
+
data.tar.gz: 62d68206b0c7ae11e4fa084d87c2d84710950af5eb415d1d6438a9b467f1527264fa64c811dbe9df5cebcfa6913e728e81ea5d3ca9054d81dfb4f6b782c8eb97
|
Binary file
|
Binary file
|
Binary file
|
data/lib/libsql.rb
ADDED
@@ -0,0 +1,443 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module CLibsql # :nodoc:
|
4
|
+
extend FFI::Library
|
5
|
+
|
6
|
+
file =
|
7
|
+
case RUBY_PLATFORM
|
8
|
+
in /darwin/ then 'universal2-apple-darwin/liblibsql.dylib'
|
9
|
+
in /x86_64-linux/ then 'x86_64-unknown-linux-gnu/liblibsql.so'
|
10
|
+
in /arm64-linux/ then 'aarch64-unknown-linux-gnu/liblibsql.so'
|
11
|
+
end
|
12
|
+
|
13
|
+
ffi_lib File.expand_path("lib/#{file}", __dir__)
|
14
|
+
|
15
|
+
Cypher = enum(:default, :aes256)
|
16
|
+
Type = enum(
|
17
|
+
:integer, 1,
|
18
|
+
:real, 2,
|
19
|
+
:text, 3,
|
20
|
+
:blob, 4,
|
21
|
+
:null, 5
|
22
|
+
)
|
23
|
+
|
24
|
+
module Verify # :nodoc:
|
25
|
+
def verify
|
26
|
+
return if self[:err].null?
|
27
|
+
|
28
|
+
s = CLibsql.libsql_error_message self[:err]
|
29
|
+
CLibsql.libsql_error_deinit self[:err]
|
30
|
+
raise CLibsql.libsql_error_message s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Database < FFI::Struct # :nodoc:
|
35
|
+
include Verify
|
36
|
+
|
37
|
+
layout err: :pointer,
|
38
|
+
inner: :pointer
|
39
|
+
|
40
|
+
def self.init(desc) = CLibsql.libsql_database_init(desc).tap(&:verify)
|
41
|
+
def sync = CLibsql.libsql_database_sync(self).tap(&:verify)
|
42
|
+
def connect = CLibsql.libsql_database_connect(self).tap(&:verify)
|
43
|
+
def deinit = CLibsql.libsql_database_deinit self
|
44
|
+
end
|
45
|
+
|
46
|
+
class Connection < FFI::Struct # :nodoc:
|
47
|
+
include Verify
|
48
|
+
|
49
|
+
layout err: :pointer,
|
50
|
+
inner: :pointer
|
51
|
+
|
52
|
+
def transaction = CLibsql.libsql_connection_transaction(self).tap(&:verify)
|
53
|
+
def prepare(sql) = CLibsql.libsql_connection_prepare(self, sql).tap(&:verify)
|
54
|
+
def execute_batch(sql) = CLibsql.libsql_connection_batch(self, sql).tap(&:verify)
|
55
|
+
def deinit = CLibsql.libsql_connection_deinit self
|
56
|
+
end
|
57
|
+
|
58
|
+
class Transaction < FFI::Struct # :nodoc:
|
59
|
+
include Verify
|
60
|
+
|
61
|
+
layout err: :pointer,
|
62
|
+
inner: :pointer
|
63
|
+
|
64
|
+
def commit = CLibsql.libsql_transaction_commit(self)
|
65
|
+
def rollback = CLibsql.libsql_transaction_rollback(self)
|
66
|
+
def prepare(sql) = CLibsql.libsql_transaction_prepare(self, sql).tap(&:verify)
|
67
|
+
def execute_batch(sql) = CLibsql.libsql_transaction_batch(self, sql).tap(&:verify)
|
68
|
+
def deinit = CLibsql.libsql_transaction_deinit self
|
69
|
+
end
|
70
|
+
|
71
|
+
class Statement < FFI::Struct # :nodoc:
|
72
|
+
include Verify
|
73
|
+
|
74
|
+
layout err: :pointer,
|
75
|
+
inner: :pointer
|
76
|
+
|
77
|
+
def bind_value(value) = CLibsql.libsql_statement_bind_value(self, value).tap(&:verify)
|
78
|
+
def bind_named(name, value) = CLibsql.libsql_statement_bind_named(self, name, value).tap(&:verify)
|
79
|
+
def query = CLibsql.libsql_statement_query(self).tap(&:verify)
|
80
|
+
def execute = CLibsql.libsql_statement_execute(self).tap(&:verify)
|
81
|
+
def deinit = CLibsql.libsql_statement_deinit self
|
82
|
+
end
|
83
|
+
|
84
|
+
class Rows < FFI::Struct # :nodoc:
|
85
|
+
include Verify
|
86
|
+
|
87
|
+
layout err: :pointer,
|
88
|
+
inner: :pointer
|
89
|
+
|
90
|
+
def next = CLibsql.libsql_rows_next(self).tap(&:verify)
|
91
|
+
def deinit = CLibsql.libsql_rows_deinit(self)
|
92
|
+
end
|
93
|
+
|
94
|
+
class Row < FFI::Struct # :nodoc:
|
95
|
+
include Verify
|
96
|
+
|
97
|
+
layout err: :pointer,
|
98
|
+
inner: :pointer
|
99
|
+
|
100
|
+
def value_at(index) = CLibsql.libsql_row_value(self, index).tap(&:verify)
|
101
|
+
def name_at(index) = CLibsql.libsql_row_name(self, index)
|
102
|
+
def length = CLibsql.libsql_row_length(self)
|
103
|
+
def empty? = CLibsql.libsql_row_empty(self)
|
104
|
+
def deinit = CLibsql.libsql_row_deinit(self)
|
105
|
+
end
|
106
|
+
|
107
|
+
class DatabaseDesc < FFI::Struct # :nodoc:
|
108
|
+
layout url: :pointer,
|
109
|
+
path: :pointer,
|
110
|
+
auth_token: :pointer,
|
111
|
+
encryption_key: :pointer,
|
112
|
+
sync_interval: :uint64,
|
113
|
+
cypher: Cypher,
|
114
|
+
disable_read_your_writes: :bool,
|
115
|
+
webpki: :bool
|
116
|
+
end
|
117
|
+
|
118
|
+
class Bind < FFI::Struct # :nodoc:
|
119
|
+
include Verify
|
120
|
+
|
121
|
+
layout err: :pointer
|
122
|
+
end
|
123
|
+
|
124
|
+
class Batch < FFI::Struct # :nodoc:
|
125
|
+
include Verify
|
126
|
+
|
127
|
+
layout err: :pointer
|
128
|
+
end
|
129
|
+
|
130
|
+
class Sync < FFI::Struct # :nodoc:
|
131
|
+
include Verify
|
132
|
+
|
133
|
+
layout err: :pointer,
|
134
|
+
frame_no: :uint64,
|
135
|
+
frames_synced: :uint64
|
136
|
+
end
|
137
|
+
|
138
|
+
class Execute < FFI::Struct # :nodoc:
|
139
|
+
include Verify
|
140
|
+
|
141
|
+
layout err: :pointer,
|
142
|
+
rows_changed: :uint64
|
143
|
+
end
|
144
|
+
|
145
|
+
class Slice < FFI::Struct # :nodoc:
|
146
|
+
layout ptr: :pointer,
|
147
|
+
len: :size_t
|
148
|
+
|
149
|
+
def to_blob
|
150
|
+
b = Blob.new self[:ptr].read_string self[:len]
|
151
|
+
deinit
|
152
|
+
b
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_s
|
156
|
+
s = self[:ptr].read_string
|
157
|
+
deinit
|
158
|
+
s
|
159
|
+
end
|
160
|
+
|
161
|
+
def deinit = CLibsql.libsql_slice_deinit self
|
162
|
+
end
|
163
|
+
|
164
|
+
class ValueUnion < FFI::Union # :nodoc:
|
165
|
+
layout integer: :uint64,
|
166
|
+
real: :double,
|
167
|
+
text: Slice.by_value,
|
168
|
+
blob: Slice.by_value
|
169
|
+
end
|
170
|
+
|
171
|
+
class Value < FFI::Struct # :nodoc:
|
172
|
+
layout value: ValueUnion.by_value,
|
173
|
+
type: Type
|
174
|
+
|
175
|
+
def convert
|
176
|
+
case self[:type]
|
177
|
+
in :null then nil
|
178
|
+
in :integer then self[:value][:integer]
|
179
|
+
in :real then self[:value][:real]
|
180
|
+
in :text then self[:value][:text].to_s
|
181
|
+
in :blob then self[:value][:blob].to_blob
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class ResultValue < FFI::Struct # :nodoc:
|
187
|
+
include Verify
|
188
|
+
|
189
|
+
layout err: :pointer,
|
190
|
+
ok: Value.by_value
|
191
|
+
end
|
192
|
+
|
193
|
+
class Config < FFI::Struct # :nodoc:
|
194
|
+
include Verify
|
195
|
+
|
196
|
+
layout logger: :pointer,
|
197
|
+
version: :pointer
|
198
|
+
end
|
199
|
+
|
200
|
+
attach_function :libsql_setup, [Config.by_value], :pointer
|
201
|
+
|
202
|
+
attach_function :libsql_database_init, [DatabaseDesc.by_value], Database.by_value
|
203
|
+
attach_function :libsql_database_sync, [Database.by_value], Sync.by_value
|
204
|
+
attach_function :libsql_database_connect, [Database.by_value], Connection.by_value
|
205
|
+
|
206
|
+
attach_function :libsql_connection_transaction, [Connection.by_value], Transaction.by_value
|
207
|
+
attach_function :libsql_connection_prepare, [Connection.by_value, :string], Statement.by_value
|
208
|
+
attach_function :libsql_connection_batch, [Connection.by_value, :string], Batch.by_value
|
209
|
+
|
210
|
+
attach_function :libsql_transaction_prepare, [Transaction.by_value, :string], Statement.by_value
|
211
|
+
attach_function :libsql_transaction_commit, [Transaction.by_value], :void
|
212
|
+
attach_function :libsql_transaction_rollback, [Transaction.by_value], :void
|
213
|
+
attach_function :libsql_transaction_batch, [Transaction.by_value, :string], Batch.by_value
|
214
|
+
|
215
|
+
attach_function :libsql_statement_bind_value, [Statement.by_value, Value.by_value], Bind.by_value
|
216
|
+
attach_function :libsql_statement_bind_named, [Statement.by_value, :string, Value.by_value], Bind.by_value
|
217
|
+
attach_function :libsql_statement_query, [Statement.by_value], Rows.by_value
|
218
|
+
attach_function :libsql_statement_execute, [Statement.by_value], Execute.by_value
|
219
|
+
|
220
|
+
attach_function :libsql_rows_next, [Rows.by_value], Row.by_value
|
221
|
+
|
222
|
+
attach_function :libsql_row_empty, [Row.by_value], :bool
|
223
|
+
attach_function :libsql_row_value, [Row.by_value, :uint32], ResultValue.by_value
|
224
|
+
attach_function :libsql_row_name, [Row.by_value, :uint32], Slice.by_value
|
225
|
+
attach_function :libsql_row_length, [Row.by_value], :uint32
|
226
|
+
|
227
|
+
attach_function :libsql_integer, [:int64], Value.by_value
|
228
|
+
attach_function :libsql_real, [:double], Value.by_value
|
229
|
+
attach_function :libsql_text, %i[pointer size_t], Value.by_value
|
230
|
+
attach_function :libsql_blob, %i[pointer size_t], Value.by_value
|
231
|
+
attach_function :libsql_null, [], Value.by_value
|
232
|
+
|
233
|
+
attach_function :libsql_error_message, [:pointer], :string
|
234
|
+
|
235
|
+
attach_function :libsql_error_deinit, [:pointer], :void
|
236
|
+
attach_function :libsql_slice_deinit, [Row.by_value], :void
|
237
|
+
attach_function :libsql_row_deinit, [Row.by_value], :void
|
238
|
+
attach_function :libsql_rows_deinit, [Rows.by_value], :void
|
239
|
+
attach_function :libsql_statement_deinit, [Statement.by_value], :void
|
240
|
+
attach_function :libsql_connection_deinit, [Connection.by_value], :void
|
241
|
+
attach_function :libsql_database_deinit, [Database.by_value], :void
|
242
|
+
end
|
243
|
+
|
244
|
+
module Libsql
|
245
|
+
class Blob < String; end
|
246
|
+
|
247
|
+
module Prepareable
|
248
|
+
def execute(sql, params = [])
|
249
|
+
prepare(sql) { |stmt| stmt.execute(params) }
|
250
|
+
end
|
251
|
+
|
252
|
+
def query(sql, params = [])
|
253
|
+
prepare(sql) { |stmt| stmt.query(params) }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class Row
|
258
|
+
include Enumerable
|
259
|
+
|
260
|
+
def initialize(inner)
|
261
|
+
@inner = inner
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_h = columns.zip(to_a).to_h
|
265
|
+
def length = @inner.length
|
266
|
+
def columns = (0...length).map { |i| @inner.name_at(i).to_s }
|
267
|
+
def each = (0...length).each { |i| yield self[i] }
|
268
|
+
|
269
|
+
def [](index)
|
270
|
+
case index
|
271
|
+
in Integer then @inner.value_at(index)[:ok].convert
|
272
|
+
in String
|
273
|
+
at = columns.index(index)
|
274
|
+
return self[at] unless at.nil?
|
275
|
+
|
276
|
+
raise "#{index} is not a valid row column"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def close = @inner.deinit
|
281
|
+
end
|
282
|
+
|
283
|
+
class Rows
|
284
|
+
include Enumerable
|
285
|
+
|
286
|
+
def initialize(inner)
|
287
|
+
@inner = inner
|
288
|
+
end
|
289
|
+
|
290
|
+
def to_a
|
291
|
+
map(&:to_h)
|
292
|
+
end
|
293
|
+
|
294
|
+
def next
|
295
|
+
row = @inner.next
|
296
|
+
Row.new row unless row.empty?
|
297
|
+
end
|
298
|
+
|
299
|
+
def each
|
300
|
+
while (row = self.next)
|
301
|
+
yield row
|
302
|
+
row.close
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def close = @inner.deinit
|
307
|
+
end
|
308
|
+
|
309
|
+
class Statement
|
310
|
+
def initialize(inner)
|
311
|
+
@inner = inner
|
312
|
+
end
|
313
|
+
|
314
|
+
def bind(params)
|
315
|
+
case params
|
316
|
+
in Array then params.each { |v| @inner.bind_value convert(v) }
|
317
|
+
in Hash
|
318
|
+
params.each do |k, v|
|
319
|
+
@inner.bind_named case k when Symbol then ":#{k}" else k end, convert(v)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def execute(params = [])
|
325
|
+
bind params
|
326
|
+
@inner.execute
|
327
|
+
end
|
328
|
+
|
329
|
+
def query(params = [])
|
330
|
+
bind params
|
331
|
+
rows = Rows.new @inner.query
|
332
|
+
return rows unless block_given?
|
333
|
+
|
334
|
+
begin yield rows ensure fows.close end
|
335
|
+
end
|
336
|
+
|
337
|
+
def close = @inner.deinit
|
338
|
+
|
339
|
+
private
|
340
|
+
|
341
|
+
def convert(value)
|
342
|
+
case value
|
343
|
+
in nil then CLibsql.libsql_null
|
344
|
+
in Integer then CLibsql.libsql_integer value
|
345
|
+
in Float then CLibsql.libsql_real value
|
346
|
+
in String then CLibsql.libsql_text value, value.length
|
347
|
+
in Blob then CLibsql.libsql_blob value, value.length
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
class Transaction
|
353
|
+
include Prepareable
|
354
|
+
|
355
|
+
def initialize(inner)
|
356
|
+
@inner = inner
|
357
|
+
end
|
358
|
+
|
359
|
+
def prepare(sql)
|
360
|
+
stmt = Statement.new @inner.prepare sql
|
361
|
+
return stmt unless block_given?
|
362
|
+
|
363
|
+
begin yield stmt ensure stmt.close end
|
364
|
+
end
|
365
|
+
|
366
|
+
def execute_batch(sql) = @inner.execute_batch(sql)
|
367
|
+
|
368
|
+
def rollback = @inner.rollback
|
369
|
+
def commit = @inner.commit
|
370
|
+
end
|
371
|
+
|
372
|
+
class Connection
|
373
|
+
include Prepareable
|
374
|
+
|
375
|
+
def initialize(inner)
|
376
|
+
@inner = inner
|
377
|
+
end
|
378
|
+
|
379
|
+
def transaction
|
380
|
+
tx = Transaction.new @inner.transaction
|
381
|
+
return tx unless block_given?
|
382
|
+
|
383
|
+
abort = false
|
384
|
+
begin
|
385
|
+
yield self
|
386
|
+
rescue StandardError
|
387
|
+
abort = true
|
388
|
+
raise
|
389
|
+
ensure
|
390
|
+
abort and tx.rollback or tx.commit
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def prepare(sql)
|
395
|
+
stmt = Statement.new @inner.prepare sql
|
396
|
+
|
397
|
+
return stmt unless block_given?
|
398
|
+
|
399
|
+
begin yield stmt ensure stmt.close end
|
400
|
+
end
|
401
|
+
|
402
|
+
def execute_batch(sql) = @inner.execute_batch(sql)
|
403
|
+
|
404
|
+
def close = @inner.deinit
|
405
|
+
end
|
406
|
+
|
407
|
+
class Database
|
408
|
+
def initialize(options = {})
|
409
|
+
desc = CLibsql::DatabaseDesc.new
|
410
|
+
|
411
|
+
%i[path url auth_token encryption_key].each do |sym|
|
412
|
+
desc[sym] = FFI::MemoryPointer.from_string options[sym] unless options[sym].nil?
|
413
|
+
end
|
414
|
+
|
415
|
+
desc[:sync_interval] = options[:sync_interval] unless options[:sync_interval].nil?
|
416
|
+
desc[:disable_read_your_writes] = !options[:read_your_writes] unless options[:read_your_writes].nil?
|
417
|
+
|
418
|
+
@inner = CLibsql::Database.init desc
|
419
|
+
|
420
|
+
return unless block_given?
|
421
|
+
|
422
|
+
begin yield self ensure close end
|
423
|
+
end
|
424
|
+
|
425
|
+
def sync
|
426
|
+
@inner.sync
|
427
|
+
end
|
428
|
+
|
429
|
+
def connect
|
430
|
+
conn = Connection.new @inner.connect
|
431
|
+
|
432
|
+
return unless block_given?
|
433
|
+
|
434
|
+
begin yield conn ensure conn.close end
|
435
|
+
end
|
436
|
+
|
437
|
+
def close = @inner.deinit
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
config = CLibsql::Config.new
|
442
|
+
config[:version] = FFI::MemoryPointer.from_string 'libsql-ruby'
|
443
|
+
CLibsql.libsql_setup config
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: turso_libsql
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Levy Albuquerque
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: libSQL Ruby SDK
|
14
|
+
email: levy@turso.tech
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/lib/aarch64-unknown-linux-gnu/liblibsql.so
|
20
|
+
- lib/lib/universal2-apple-darwin/liblibsql.dylib
|
21
|
+
- lib/lib/x86_64-unknown-linux-gnu/liblibsql.so
|
22
|
+
- lib/libsql.rb
|
23
|
+
homepage: https://rubygems.org/gems/turso_libsql
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubygems_version: 3.5.16
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: libSQL
|
46
|
+
test_files: []
|