libsql-sequel 0.3.0 → 0.3.1
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 +4 -4
- data/README.md +8 -2
- data/docs/architecture.md +9 -0
- data/docs/development.md +11 -1
- data/lib/sequel/libsql/connection.rb +2 -1
- data/lib/sequel/libsql/dataset.rb +7 -2
- data/lib/sequel/libsql/native.rb +12 -5
- data/lib/sequel/libsql/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b85ae761e49c7fc3ed4146cdf94f244d1cae27a1642b57fe7ebc9e00265211e
|
|
4
|
+
data.tar.gz: e7a634b05315f2795010cfbb8719ae8edbf70c4fd942950a33b56c77a5d59adf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca3aa0de34530d183c699699380c984a1bf84c52e2f509ac90c433da17abb334db72083fd1d820932b8adef32be47d4a9a3d80f7765a722368d9da417454e2eb
|
|
7
|
+
data.tar.gz: 34d675b2abcaf4435812d98b38ccf3a0c6931ca52e4652bf49a1d77df38538f14b2f5bb1c78ab1a2fc4ca7663d3882ee3d18be7d9e096aa7b0da3774e1e44496
|
data/README.md
CHANGED
|
@@ -30,13 +30,13 @@ Install from [RubyGems](https://rubygems.org/gems/libsql-sequel):
|
|
|
30
30
|
|
|
31
31
|
```ruby
|
|
32
32
|
# Gemfile
|
|
33
|
-
gem 'libsql-sequel', '~> 0.3.
|
|
33
|
+
gem 'libsql-sequel', '~> 0.3.1'
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Then run `bundle install`. To install without Bundler:
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
|
-
gem install libsql-sequel -v 0.3.
|
|
39
|
+
gem install libsql-sequel -v 0.3.1
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Ruby 3.3+ and Sequel 5.80–5.x are required. The native dependency is **pinned to `turso_libsql` 0.2.0**: 0.2.1 contains native debug output of connection credentials and SQL. Do not widen that dependency without reviewing the replacement library. The adapter uses the bundled native library with scoped corrections for the driver's Ruby wrapper; it does not patch global `Libsql` classes or require `sqlite3` at runtime.
|
|
@@ -135,6 +135,7 @@ bundle exec rake lint # syntax and method visibility only
|
|
|
135
135
|
bundle exec rake test # real native local/file databases
|
|
136
136
|
bundle exec rake upstream # upstream SQLite + integration specs
|
|
137
137
|
bundle exec rake remote_local # real native HTTP client, local Hrana server
|
|
138
|
+
bundle exec rake performance # local end-to-end timing and allocation benchmarks
|
|
138
139
|
```
|
|
139
140
|
|
|
140
141
|
`upstream` and `remote_local` need the ignored reference checkouts; setup instructions are in [development.md](docs/development.md). `rake` defaults to `check`. Checks follow Sequel's own syntax/warnings/visibility approach; Sequel does not configure RuboCop or a complexity analyzer. See [the spec and code-quality review](docs/testing-review.md).
|
|
@@ -142,3 +143,8 @@ bundle exec rake remote_local # real native HTTP client, local Hrana server
|
|
|
142
143
|
For an explicit test against a **disposable** hosted database, set `LIBSQL_TEST_URL` and `LIBSQL_TEST_AUTH_TOKEN` in your environment, then run `bundle exec rake remote`. It creates randomly named test tables and drops those tables afterward. Hosted authentication and HTTPS remote operations have been validated with a `turso://` URL; embedded replication remains unverified. See [compatibility and verification](docs/compatibility.md) for the tested scope.
|
|
143
144
|
|
|
144
145
|
See [architecture](docs/architecture.md), [compatibility](docs/compatibility.md), and [the local example](examples/local.rb).
|
|
146
|
+
|
|
147
|
+
The [performance suite](test/performance/README.md) covers queries/chaining, bound
|
|
148
|
+
and prepared operations, result decoding, CRUD, models, transactions, bulk writes,
|
|
149
|
+
schema operations, and file-backed connection concurrency. It includes correctness
|
|
150
|
+
checks, JSON before/after comparisons, and a Sequel SQLite reference mode.
|
data/docs/architecture.md
CHANGED
|
@@ -34,6 +34,15 @@ Sequel's cached placeholder literalizer optimization is disabled because it repl
|
|
|
34
34
|
|
|
35
35
|
Numeric timestamps follow Sequel's SQLite convention: Integer means Unix seconds and Float means Julian day. Numeric TIME values preserve microseconds. BLOB columns containing integer/real/text storage values convert through their string representation, and nonnumeric text in a decimal column remains text, matching Sequel's SQLite adapter.
|
|
36
36
|
|
|
37
|
+
Result decoding resolves column types once per result, then uses an indexed loop
|
|
38
|
+
to assemble row hashes, following Sequel's SQLite adapter. The native column count
|
|
39
|
+
is also resolved once per iteration over a result. Signed-integer bounds are
|
|
40
|
+
constants rather than repeated Bignum arithmetic per cell/bind. Native text input
|
|
41
|
+
can reuse a frozen UTF-8 string; mutable strings are still copied before calls
|
|
42
|
+
that release the GVL. These optimizations preserve per-row cleanup and schema
|
|
43
|
+
invalidation; they introduce no statement or result-type cache. The local
|
|
44
|
+
[performance suite](../test/performance/README.md) records timing and allocations.
|
|
45
|
+
|
|
37
46
|
Sequel invalidates its own schema cache for schema DSL changes. External schema changes and arbitrary DDL via `run` follow Sequel's usual cache rules; reload the affected schema or reconnect the Database object when needed. No extra unbounded type cache is introduced.
|
|
38
47
|
|
|
39
48
|
## Driver boundary
|
data/docs/development.md
CHANGED
|
@@ -51,11 +51,21 @@ The fixture needs a free localhost port 8080. It creates a temporary SQLite file
|
|
|
51
51
|
|
|
52
52
|
For a disposable hosted database, export `LIBSQL_TEST_URL` and `LIBSQL_TEST_AUTH_TOKEN`, then run `bundle exec rake remote`. Tests create randomly named tables and drop only those tables. Do not point destructive integration fixtures from another project at a production database.
|
|
53
53
|
|
|
54
|
+
## Performance benchmarks
|
|
55
|
+
|
|
56
|
+
See [`test/performance/README.md`](../test/performance/README.md) for the standalone
|
|
57
|
+
local native benchmark suite and [`results.md`](../test/performance/results.md)
|
|
58
|
+
for measured optimization results. `bundle exec rake performance:smoke` checks all
|
|
59
|
+
workloads with small fixtures on libSQL memory/file databases and a SQLite file
|
|
60
|
+
database. `bundle exec rake performance` runs the measured memory suite; use the
|
|
61
|
+
runner directly for file mode, filtering, longer samples, and JSON output.
|
|
62
|
+
Benchmarks are opt-in and do not impose noisy wall-clock thresholds on `rake check`.
|
|
63
|
+
|
|
54
64
|
## Packaging
|
|
55
65
|
|
|
56
66
|
```sh
|
|
57
67
|
mkdir -p pkg
|
|
58
|
-
gem build libsql-sequel.gemspec --output pkg/libsql-sequel-0.3.
|
|
68
|
+
gem build libsql-sequel.gemspec --output pkg/libsql-sequel-0.3.1.gem
|
|
59
69
|
```
|
|
60
70
|
|
|
61
71
|
The explicit gem file list includes Ruby library files, public docs, examples, README, and LICENSE. It excludes private notes, cloned repositories, credentials, tests, and temporary databases. Nothing is automatically published.
|
|
@@ -132,12 +132,13 @@ module Sequel
|
|
|
132
132
|
|
|
133
133
|
def each
|
|
134
134
|
check_open
|
|
135
|
+
column_count = columns.length
|
|
135
136
|
loop do
|
|
136
137
|
check_open
|
|
137
138
|
row = Native.check(Native.rows_next(@rows))
|
|
138
139
|
break if row[:inner].null?
|
|
139
140
|
begin
|
|
140
|
-
values = Array.new(
|
|
141
|
+
values = Array.new(column_count) do |index|
|
|
141
142
|
Native.value(Native.check(CLibsql.libsql_row_value(row, index))[:ok])
|
|
142
143
|
end
|
|
143
144
|
yield values
|
|
@@ -27,13 +27,18 @@ module Sequel
|
|
|
27
27
|
execute(sql) do |result|
|
|
28
28
|
columns = result.columns.map{|column| output_identifier(column)}
|
|
29
29
|
types = ResultTypes.new(self).for_columns(columns)
|
|
30
|
+
column_types = columns.map{|name| types[name]}
|
|
31
|
+
column_count = columns.length
|
|
30
32
|
converter = TypeConverter.new(db)
|
|
31
33
|
self.columns = columns
|
|
32
34
|
result.each do |values|
|
|
33
35
|
row = {}
|
|
34
|
-
|
|
36
|
+
index = 0
|
|
37
|
+
while index < column_count
|
|
35
38
|
value = values[index]
|
|
36
|
-
|
|
39
|
+
type = column_types[index]
|
|
40
|
+
row[columns[index]] = type ? converter.call(value, type) : value
|
|
41
|
+
index += 1
|
|
37
42
|
end
|
|
38
43
|
yield row
|
|
39
44
|
end
|
data/lib/sequel/libsql/native.rb
CHANGED
|
@@ -11,6 +11,11 @@ module Sequel
|
|
|
11
11
|
module Native
|
|
12
12
|
class Error < StandardError; end
|
|
13
13
|
|
|
14
|
+
# Hoist Bignum arithmetic out of the per-cell decode and bind paths.
|
|
15
|
+
INTEGER_MIN = -(1 << 63)
|
|
16
|
+
INTEGER_LIMIT = 1 << 63
|
|
17
|
+
INTEGER_MODULUS = 1 << 64
|
|
18
|
+
|
|
14
19
|
extend FFI::Library
|
|
15
20
|
ffi_lib(*CLibsql.ffi_libraries.map(&:name))
|
|
16
21
|
|
|
@@ -47,7 +52,9 @@ module Sequel
|
|
|
47
52
|
end
|
|
48
53
|
|
|
49
54
|
def self.string(value)
|
|
50
|
-
value = value.to_s
|
|
55
|
+
value = value.to_s
|
|
56
|
+
# Keep a stable copy of mutable input while native calls release the GVL.
|
|
57
|
+
value = value.encode(Encoding::UTF_8) unless value.frozen? && value.encoding == Encoding::UTF_8
|
|
51
58
|
raise Sequel::Error, 'libSQL text cannot contain NUL bytes; use Sequel.blob for binary data' if value.include?("\0")
|
|
52
59
|
raise Sequel::Error, 'libSQL text must be valid UTF-8' unless value.valid_encoding?
|
|
53
60
|
value
|
|
@@ -69,17 +76,17 @@ module Sequel
|
|
|
69
76
|
end
|
|
70
77
|
|
|
71
78
|
def self.value(value)
|
|
72
|
-
case value[:type]
|
|
79
|
+
case type = value[:type]
|
|
73
80
|
when :null
|
|
74
81
|
nil
|
|
75
82
|
when :integer
|
|
76
83
|
# The Ruby driver declares uint64, while the C API returns int64.
|
|
77
84
|
integer = value[:value][:integer]
|
|
78
|
-
integer >=
|
|
85
|
+
integer >= INTEGER_LIMIT ? integer - INTEGER_MODULUS : integer
|
|
79
86
|
when :real
|
|
80
87
|
value[:value][:real]
|
|
81
88
|
when :text, :blob
|
|
82
|
-
read_slice(value[:value][
|
|
89
|
+
read_slice(value[:value][type], type == :text)
|
|
83
90
|
else
|
|
84
91
|
raise Error, 'unknown libSQL value type'
|
|
85
92
|
end
|
|
@@ -91,7 +98,7 @@ module Sequel
|
|
|
91
98
|
when nil
|
|
92
99
|
yield CLibsql.libsql_null
|
|
93
100
|
when Integer
|
|
94
|
-
unless
|
|
101
|
+
unless value >= INTEGER_MIN && value < INTEGER_LIMIT
|
|
95
102
|
raise Sequel::Error, 'libSQL integers must fit in signed 64 bits'
|
|
96
103
|
end
|
|
97
104
|
yield CLibsql.libsql_integer(value)
|