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
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: []