lora-ruby 0.5.6-x86_64-linux → 0.8.4-x86_64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 155820b5ff90f8828c11df7dd6ce3950b0601e2e374ea8353af9222db282c6f3
4
- data.tar.gz: d856048cb887c4cbefac9bbe7f4e72af2fb22eae82c6488d5140edd22fe952b9
3
+ metadata.gz: d80ff16c35cd0c2c9a41563b78cf6eb4efd920da2ab37d72db9364b3ab1dbcf2
4
+ data.tar.gz: b05c7f6b6f29cdb116f0f0f6b771074ec613e460905a7a015c8b8705034e6f40
5
5
  SHA512:
6
- metadata.gz: 06b481a3cdc376c01bdb2e8933974d6c736a48963a81ed78107f1547efadc3634983471fe4e8da8d07089f42715c92a8c0d2a4f854be78ede0c01b605e74d149
7
- data.tar.gz: 1a55006ecb781a0ac2ecdd37a75c89eb9d7571a31f7836d5d78b94bedb7e4fa9ce8406df609b77f00f9e61a2cae289c13b4515b0f59bfe49b01a8a5ad33fd669
6
+ metadata.gz: '028fa90d227cd7b2a97be8c07675ed8991afbec05b22009569373226277cab3548b6a84ee516ee0fa2f8ce045e79b634b175a33de7b73ae02ea631a45cb3998e'
7
+ data.tar.gz: 1f687e32046ead1c082932c4571e38f2da7bb12f4aa5d08f858a17dead2a9fc5c05aa385320cb73dd4854fc7a15dd96c5426018c2c8a5051d188cb6989284a00
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # lora-ruby
2
2
 
3
- Ruby bindings for the [Lora](../../README.md) graph engine.
3
+ Ruby bindings for the [Lora](../../../README.md) graph engine.
4
4
  Ships a native extension built with [Magnus](https://github.com/matsadler/magnus)
5
5
  on top of [`rb-sys`](https://github.com/oxidize-rb/rb-sys) so the Rust
6
6
  engine runs in-process — no separate server, no socket hop.
@@ -76,10 +76,13 @@ binding's `lora_python.Database` and because it mirrors the
76
76
  ## Public API
77
77
 
78
78
  ```ruby
79
- LoraRuby::Database.create(wal_dir = nil) # -> Database
80
- LoraRuby::Database.new(wal_dir = nil) # -> Database (alias of .create)
79
+ LoraRuby::Database.create(database_name = nil, options = nil) # -> Database
80
+ LoraRuby::Database.new(database_name = nil, options = nil) # -> Database
81
+ LoraRuby::Database.open_wal(wal_dir, options = nil) # -> Database
81
82
 
82
83
  db.execute(query, params = nil) # -> { "columns" => [...], "rows" => [...] }
84
+ db.explain(query, params = nil) # -> plan Hash; never executes
85
+ db.profile(query, params = nil) # -> { "plan" => ..., "metrics" => ... }; PROFILE executes writes
83
86
  db.clear # -> nil
84
87
  db.node_count # -> Integer
85
88
  db.relationship_count # -> Integer
@@ -101,6 +104,37 @@ Hash keys on the output are always **strings**, matching the `lora-node`,
101
104
  symbol or string keys — both work for param names and for tagged
102
105
  constructor Hashes like `point`/`date`/...
103
106
 
107
+ ### Explain & Profile
108
+
109
+ `db.explain` and `db.profile` are first-class methods alongside
110
+ `db.execute`. They are intentionally *separate calls*, not a flag on
111
+ `execute`, so plan inspection and runtime metrics must be requested
112
+ explicitly.
113
+
114
+ ```ruby
115
+ plan = db.explain(
116
+ "MATCH (p:Person) WHERE p.name = $name RETURN p",
117
+ { "name" => "Alice" }
118
+ )
119
+ plan["shape"] # => "readOnly"
120
+ plan["tree"]["operator"]
121
+
122
+ profile = db.profile(
123
+ "MATCH (p:Person) WHERE p.name = $name RETURN p",
124
+ { "name" => "Alice" }
125
+ )
126
+ profile["metrics"]["total_elapsed_ns"]
127
+ profile["metrics"]["per_operator"] # per-step inclusive timing
128
+ ```
129
+
130
+ `explain` never invokes the executor — calling it on a mutating query
131
+ (`CREATE`, `MERGE`, `SET`, `DELETE`, `REMOVE`) leaves the graph
132
+ untouched.
133
+
134
+ > **`profile` executes the query for real.** Mutating queries are
135
+ > persisted exactly as in `execute`. Use `explain` to inspect a
136
+ > mutating plan without running it.
137
+
104
138
  ## Typed value model
105
139
 
106
140
  Identical contract to the other bindings:
@@ -156,16 +190,25 @@ replays committed writes before returning the handle.
156
190
  Call `db.close` before reopening the same archive inside one
157
191
  process.
158
192
 
159
- This first Ruby persistence slice intentionally stays small: the
160
- binding exposes archive-backed initialization plus the existing snapshot
161
- APIs, but not checkpoint, truncate, status, or sync-mode controls.
193
+ For explicit WAL directories with managed snapshots, use `open_wal`:
194
+
195
+ ```ruby
196
+ db = LoraRuby::Database.open_wal(
197
+ "./data/wal",
198
+ snapshot_dir: "./data/snapshots",
199
+ snapshot_every_commits: 1000,
200
+ snapshot_keep_old: 2,
201
+ )
202
+ ```
203
+
204
+ `snapshot_options` accepts the same compression/encryption options as
205
+ `save_snapshot`.
162
206
 
163
207
  ## Concurrency (GVL release)
164
208
 
165
209
  `Database#execute` calls `rb_thread_call_without_gvl`, so other Ruby
166
- threads run while the engine is busy. Concurrent queries against the
167
- same `Database` serialise on an internal `Mutex`; parallel queries
168
- against **different** `Database` instances have no shared state.
210
+ threads run while the engine is busy. Auto-commit reads can overlap on engine
211
+ snapshots; write commits and explicit read-write transactions serialize.
169
212
 
170
213
  The engine has no cancellation hook, so we pass a `NULL` unblock
171
214
  function. A thread interrupted mid-query (`Thread#kill`) will observe
@@ -175,7 +218,7 @@ if you rely on cooperative cancellation.
175
218
  ## Local development
176
219
 
177
220
  ```bash
178
- cd crates/lora-ruby
221
+ cd crates/bindings/lora-ruby
179
222
  bundle install
180
223
  bundle exec rake compile # cargo build → lib/lora_ruby/lora_ruby.<ext>
181
224
  bundle exec rake test # minitest
@@ -190,7 +233,7 @@ precompiled platform gem.
190
233
 
191
234
  ```
192
235
  lora-database (Rust, embedded)
193
- └── crates/lora-ruby/ (gem root + cargo crate)
236
+ └── crates/bindings/lora-ruby/ (gem root + cargo crate)
194
237
  ├── Cargo.toml Rust workspace member
195
238
  ├── extconf.rb rb-sys / mkmf entry point
196
239
  ├── src/lib.rs <- Magnus / rb-sys bindings
Binary file
Binary file
Binary file
@@ -7,7 +7,7 @@ module LoraRuby
7
7
  # - Scalars pass through as Ruby natives (`nil`, `true`, `false`,
8
8
  # `Integer`, `Float`, `String`).
9
9
  # - Lists and maps come back as `Array` / `Hash` (string keys).
10
- # - Graph, temporal, and spatial values come back as plain `Hash`es
10
+ # - Graph, temporal, spatial, vector, and binary values come back as plain `Hash`es
11
11
  # with a `"kind"` discriminator.
12
12
  #
13
13
  # If you want to narrow a value explicitly, use the `node?` / `point?`
@@ -56,6 +56,21 @@ module LoraRuby
56
56
  }
57
57
  end
58
58
 
59
+ # ------------------------------------------------------------------
60
+ # Binary / blob constructor — segmented bytes. The native extension
61
+ # accepts each segment as a Ruby String and preserves segment
62
+ # boundaries in WAL/snapshot storage.
63
+ # ------------------------------------------------------------------
64
+
65
+ def binary(segments)
66
+ copied = segments.map { |segment| segment.b.dup }
67
+ {
68
+ "kind" => "binary",
69
+ "length" => copied.sum(&:bytesize),
70
+ "segments" => copied,
71
+ }
72
+ end
73
+
59
74
  # ------------------------------------------------------------------
60
75
  # Spatial constructors — mirrors lora_python.cartesian / wgs84.
61
76
  # `cartesian(1, 2)` returns a 2D cartesian point; use `cartesian_3d`
@@ -122,6 +137,7 @@ module LoraRuby
122
137
  def path?(v) = tagged?(v, "path")
123
138
  def point?(v) = tagged?(v, "point")
124
139
  def vector?(v) = tagged?(v, "vector")
140
+ def binary?(v) = tagged?(v, "binary")
125
141
 
126
142
  def temporal?(v)
127
143
  return false unless v.is_a?(Hash)
@@ -10,5 +10,5 @@ module LoraRuby
10
10
  # Guard against redefinition so re-requiring this file (or loading
11
11
  # both paths) doesn't emit a "warning: already initialized constant"
12
12
  # when the native extension loads second with the identical value.
13
- VERSION = "0.5.6" unless const_defined?(:VERSION)
13
+ VERSION = "0.8.4" unless const_defined?(:VERSION)
14
14
  end
data/lib/lora_ruby.rb CHANGED
@@ -32,8 +32,8 @@ module LoraRuby
32
32
  %i[
33
33
  date time localtime datetime localdatetime duration
34
34
  cartesian cartesian_3d wgs84 wgs84_3d
35
- vector
36
- node? relationship? path? point? temporal? vector?
35
+ vector binary
36
+ node? relationship? path? point? temporal? vector? binary?
37
37
  ].each do |m|
38
38
  define_singleton_method(m) do |*args, **kwargs|
39
39
  if kwargs.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lora-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.8.4
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - LoraDB, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-27 00:00:00.000000000 Z
11
+ date: 2026-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -73,9 +73,9 @@ licenses:
73
73
  - BUSL-1.1
74
74
  metadata:
75
75
  homepage_uri: https://github.com/lora-db/lora
76
- source_code_uri: https://github.com/lora-db/lora/tree/main/crates/lora-ruby
76
+ source_code_uri: https://github.com/lora-db/lora/tree/main/crates/bindings/lora-ruby
77
77
  bug_tracker_uri: https://github.com/lora-db/lora/issues
78
- documentation_uri: https://github.com/lora-db/lora/blob/main/crates/lora-ruby/README.md
78
+ documentation_uri: https://github.com/lora-db/lora/blob/main/crates/bindings/lora-ruby/README.md
79
79
  rubygems_mfa_required: 'true'
80
80
  post_install_message:
81
81
  rdoc_options: []