extralite 2.15 → 3.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 +4 -4
- data/.github/workflows/test-bundle.yml +1 -1
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +106 -42
- data/TODO.md +2 -16
- data/examples/transform.rb +61 -0
- data/ext/extralite/changeset.c +11 -11
- data/ext/extralite/common.c +234 -22
- data/ext/extralite/database.c +157 -100
- data/ext/extralite/extralite.h +52 -6
- data/ext/extralite/extralite_ext.c +2 -0
- data/ext/extralite/query.c +67 -41
- data/ext/extralite/transform.c +420 -0
- data/gemspec.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +102 -1
- data/test/perf_array.rb +1 -1
- data/test/perf_hash.rb +1 -1
- data/test/perf_hash_prepared.rb +2 -2
- data/test/perf_splat.rb +1 -1
- data/test/perf_transform.rb +58 -0
- data/test/test_database.rb +37 -10
- data/test/test_query.rb +11 -15
- data/test/test_transform.rb +817 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb66a5b2636ccad51ab5a86ff0b7802d25574a564a5c4395c838a2d26f2599b9
|
|
4
|
+
data.tar.gz: d00921f287ba1c602c8669ff85740108a7bafb4f8111722f14055612db7afc3f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: be12c6a8629f83db24107fc6a6d06f1b94beff46622b9d6c0c47ed55575069cee2529389ba709a7f8dec4f31f11cb3738e3df25f17667264031014fc5e3dc7c8
|
|
7
|
+
data.tar.gz: 43be64a94f7e29cbafb25a2b32271e1b260d2a7f5b6f69eb214c0e069faaca1973e0bb92fb6d62f1bcba05e55136369c6841d28dc22c06b3290188da1a84bba2
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 3.0.0 2026-07-02
|
|
2
|
+
|
|
3
|
+
- Update benchmark results in README
|
|
4
|
+
- Prevent extension loading using `load_extension` SQL function
|
|
5
|
+
- Remove `wal: true` option, add `legacy: true` option for
|
|
6
|
+
- Change default behaviour to set WAL journal mode + synchronous + foreign keys
|
|
7
|
+
- Add transform DSL
|
|
8
|
+
- Add support for type coercion in transforms
|
|
9
|
+
- Add `Extralite::Transform` class for transforming rows into an object graph
|
|
10
|
+
|
|
1
11
|
## 2.15 2026-06-28
|
|
2
12
|
|
|
3
13
|
- Update bundled SQLite to 3.53.3
|
data/README.md
CHANGED
|
@@ -37,12 +37,14 @@ latest features and enhancements.
|
|
|
37
37
|
|
|
38
38
|
## Features
|
|
39
39
|
|
|
40
|
-
- Best-in-class [performance](#performance) (up to
|
|
40
|
+
- Best-in-class [performance](#performance) (up to 2.35X the performance of the
|
|
41
41
|
[sqlite3](https://github.com/sparklemotion/sqlite3-ruby) gem).
|
|
42
|
-
- Support for [concurrency](#concurrency) out of the box for multi-threaded
|
|
43
|
-
|
|
42
|
+
- Support for [concurrency](#concurrency) out of the box for multi-threaded and
|
|
43
|
+
multi-fibered apps.
|
|
44
44
|
- A variety of ways to [retrieve data](#query-modes) - hashes, arrays, single
|
|
45
|
-
columns, single rows
|
|
45
|
+
columns, single rows.
|
|
46
|
+
- Support for retrieving records as structured objects using
|
|
47
|
+
[transforms](#transforms).
|
|
46
48
|
- Support for [external iteration](#iterating-over-records-in-a-prepared-query),
|
|
47
49
|
allowing iterating through single records or batches of records.
|
|
48
50
|
- [Prepared queries](#prepared-queries).
|
|
@@ -53,7 +55,7 @@ latest features and enhancements.
|
|
|
53
55
|
[backups](#creating-backups), retrieve [status
|
|
54
56
|
information](#retrieving-status-information), work with
|
|
55
57
|
[changesets](#working-with-changesets), interrogate [database
|
|
56
|
-
limits](#working-with-database-limits),
|
|
58
|
+
limits](#working-with-database-limits), [trace](#tracing-sql-statements)
|
|
57
59
|
queries.
|
|
58
60
|
- [Sequel](#usage-with-sequel) adapter.
|
|
59
61
|
|
|
@@ -63,7 +65,7 @@ latest features and enhancements.
|
|
|
63
65
|
- [Getting Started](#getting-started)
|
|
64
66
|
- [Query Modes](#query-modes)
|
|
65
67
|
- [Parameter binding](#parameter-binding)
|
|
66
|
-
- [
|
|
68
|
+
- [Transforms](#transforms)
|
|
67
69
|
- [Data Types](#data-types)
|
|
68
70
|
- [Prepared Queries](#prepared-queries)
|
|
69
71
|
- [Batch Execution of Queries](#batch-execution-of-queries)
|
|
@@ -286,18 +288,20 @@ db.execute(sql, Extralite::Blob.new('Hello, 世界!'))
|
|
|
286
288
|
db.execute(sql, 'Hello, 世界!'.force_encoding(Encoding::ASCII_8BIT))
|
|
287
289
|
```
|
|
288
290
|
|
|
289
|
-
##
|
|
291
|
+
## Transforms
|
|
290
292
|
|
|
291
293
|
Extralite allows you to transform rows to any value your application may need by
|
|
292
|
-
providing a transform proc that takes the raw row values and
|
|
293
|
-
transformed data.
|
|
294
|
-
hash or as a list of values.
|
|
294
|
+
providing a transform proc or transform object that takes the raw row values and
|
|
295
|
+
returns the transformed data.
|
|
295
296
|
|
|
296
297
|
Transforms are useful when you need to transform rows into ORM model instances,
|
|
297
298
|
or when you need to do some other transformation on the values retrieved from
|
|
298
|
-
the database.
|
|
299
|
+
the database. With transforms, you can create nested, structured Ruby objects
|
|
300
|
+
that represents different entities. This is especially useful for representing
|
|
301
|
+
one-to-one, one-to-many or many-to-many relationships when doing joins.
|
|
299
302
|
|
|
300
|
-
|
|
303
|
+
A transform proc is expressed as a lambda taking one or more values. To
|
|
304
|
+
transform results, pass a transform proc as the first parameter to one of the
|
|
301
305
|
`#query_xxx` methods:
|
|
302
306
|
|
|
303
307
|
```ruby
|
|
@@ -315,8 +319,50 @@ db.query_splat(transform, 'select a, b, c from foo')
|
|
|
315
319
|
#=> transformed rows
|
|
316
320
|
```
|
|
317
321
|
|
|
318
|
-
|
|
319
|
-
|
|
322
|
+
### Structured Transforms
|
|
323
|
+
|
|
324
|
+
To transform rows into an object graph containing entities, you can use the
|
|
325
|
+
`Extralite::Transform` class, which lets you express data as an object graph.
|
|
326
|
+
This is particularly useful when doing `JOIN` queries. For example, a query may
|
|
327
|
+
express a many-to-many relationship between posts and tags:
|
|
328
|
+
|
|
329
|
+
```sql
|
|
330
|
+
select
|
|
331
|
+
posts.id, posts.content,
|
|
332
|
+
tags.id, tags.name
|
|
333
|
+
from posts
|
|
334
|
+
left outer join posts_tags
|
|
335
|
+
on posts_tags.post_id = posts.id
|
|
336
|
+
left outer join tags
|
|
337
|
+
on posts_tags.tag_id = tags.id
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
The result rows will contain information about both post and tag entities, and
|
|
341
|
+
each entity (be it a post or a tag) may be repeated in multiple rows. With a
|
|
342
|
+
transform you can tell Extralite to eliminate the duplicate entities by using an
|
|
343
|
+
identity map, and to include a list of tags for each post:
|
|
344
|
+
|
|
345
|
+
```ruby
|
|
346
|
+
transform = Extralite::Transform do
|
|
347
|
+
{
|
|
348
|
+
id: integer.identity, # posts.id
|
|
349
|
+
content: text, # posts.content
|
|
350
|
+
tags: [{
|
|
351
|
+
id: integer.identity, # tags.id
|
|
352
|
+
name: text # tags.name
|
|
353
|
+
}]
|
|
354
|
+
}
|
|
355
|
+
end
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
To use the transform, pass it along with the SQL string to `Database#query`:
|
|
359
|
+
|
|
360
|
+
```ruby
|
|
361
|
+
db.qurey(transform, sql) #=> [...]
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Transforms can also be used with [prepared
|
|
365
|
+
queries](#transforms-in-prepared-queries).
|
|
320
366
|
|
|
321
367
|
## Prepared Queries
|
|
322
368
|
|
|
@@ -470,12 +516,13 @@ iterator = Extralite::Iterator.new(query)
|
|
|
470
516
|
iterator.each { |r| ... }
|
|
471
517
|
```
|
|
472
518
|
|
|
473
|
-
###
|
|
519
|
+
### Transforms in Prepared Queries
|
|
474
520
|
|
|
475
521
|
Prepared queries can automatically transform their result sets by setting a
|
|
476
|
-
transform
|
|
477
|
-
(hash, array or splat). To set a transform
|
|
478
|
-
`Database#prepare_xxx` methods, or use
|
|
522
|
+
transform proc or object. If a transform proc is provided, the proc will be
|
|
523
|
+
invoked according to the query mode (hash, array or splat). To set a transform
|
|
524
|
+
proc you can pass a block to one of the `Database#prepare_xxx` methods, or use
|
|
525
|
+
`Query#transform=`:
|
|
479
526
|
|
|
480
527
|
```ruby
|
|
481
528
|
q = db.prepare('select * from items where id = ?') { |h| Item.new(h) }
|
|
@@ -483,7 +530,7 @@ q.bind(42).next #=> Item instance
|
|
|
483
530
|
|
|
484
531
|
# An equivalent
|
|
485
532
|
q = db.prepare('select * from items where id = ?')
|
|
486
|
-
q.transform
|
|
533
|
+
q.transform = ->(h) { Item.new(h) }
|
|
487
534
|
```
|
|
488
535
|
|
|
489
536
|
The same can be done for queries in `splat` or `array` mode:
|
|
@@ -494,6 +541,26 @@ db.prepare_splat('select * from foo') { |a, b, c| a + b + c }
|
|
|
494
541
|
db.prepare_array('select * from foo') { |a| a.map(&:to_s).join }
|
|
495
542
|
```
|
|
496
543
|
|
|
544
|
+
You can also use structured transforms with prepared queries:
|
|
545
|
+
|
|
546
|
+
```ruby
|
|
547
|
+
q = db.prepare <<~SQL
|
|
548
|
+
select posts.id, posts.content, author.id, author.name
|
|
549
|
+
from posts left join authors
|
|
550
|
+
on posts.author_id = authors.id
|
|
551
|
+
SQL
|
|
552
|
+
q.transform = Extralite::Transform.new do
|
|
553
|
+
{
|
|
554
|
+
id: integer.identity,
|
|
555
|
+
content: text,
|
|
556
|
+
author: {
|
|
557
|
+
id: integer.identity,
|
|
558
|
+
name: text
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
end
|
|
562
|
+
```
|
|
563
|
+
|
|
497
564
|
## Batch Execution of Queries
|
|
498
565
|
|
|
499
566
|
Extralite provides methods for batch execution of queries, with multiple sets of
|
|
@@ -764,16 +831,13 @@ Extralite provides a comprehensive set of tools for dealing with concurrency
|
|
|
764
831
|
issues, and for making sure that running queries on SQLite databases does not
|
|
765
832
|
cause the app to freeze.
|
|
766
833
|
|
|
767
|
-
**Note**:
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
with `BusyError` exceptions. You can easily open your database in WAL journaling
|
|
772
|
-
mode by passing a `wal: true` option:
|
|
834
|
+
**Note**: By default Extralite automatically configures SQLite to [WAL
|
|
835
|
+
journaling mode](https://www.sqlite.org/wal.html) for *all* database
|
|
836
|
+
connections. To open a legacy database without WAL journaling, you can open the
|
|
837
|
+
database and pass the `legacy: true` option:
|
|
773
838
|
|
|
774
839
|
```ruby
|
|
775
|
-
|
|
776
|
-
db = Extralite::Database.new('path/to/db', wal: true)
|
|
840
|
+
db = Extralite::Database.new('path/to/db', legacy: true)
|
|
777
841
|
```
|
|
778
842
|
|
|
779
843
|
### The Ruby GVL
|
|
@@ -1248,7 +1312,7 @@ p articles.to_a
|
|
|
1248
1312
|
|
|
1249
1313
|
A benchmark script is included, creating a table of various row counts, then
|
|
1250
1314
|
fetching the entire table using either `sqlite3` or `extralite`. This benchmark
|
|
1251
|
-
shows Extralite to be up to ~
|
|
1315
|
+
shows Extralite to be up to ~2.35 times faster than `sqlite3` when fetching a
|
|
1252
1316
|
large number of rows.
|
|
1253
1317
|
|
|
1254
1318
|
### Rows as Hashes
|
|
@@ -1256,36 +1320,36 @@ large number of rows.
|
|
|
1256
1320
|
[Benchmark source
|
|
1257
1321
|
code](https://github.com/digital-fabric/extralite/blob/main/test/perf_hash.rb)
|
|
1258
1322
|
|
|
1259
|
-
|Row count|sqlite3 2.
|
|
1323
|
+
|Row count|sqlite3 2.9.5|Extralite 2.15|Advantage|
|
|
1260
1324
|
|-:|-:|-:|-:|
|
|
1261
|
-
|10|
|
|
1262
|
-
|1K|
|
|
1263
|
-
|100K|
|
|
1325
|
+
|10|111.6K rows/s|177.3K rows/s|__1.59x__|
|
|
1326
|
+
|1K|2732.8K rows/s|5863.0K rows/s|__2.15x__|
|
|
1327
|
+
|100K|2129.0K rows/s|4863.1K rows/s|__2.28x__|
|
|
1264
1328
|
|
|
1265
1329
|
### Rows as Arrays
|
|
1266
1330
|
|
|
1267
1331
|
[Benchmark source
|
|
1268
1332
|
code](https://github.com/digital-fabric/extralite/blob/main/test/perf_array.rb)
|
|
1269
1333
|
|
|
1270
|
-
|Row count|sqlite3 2.
|
|
1334
|
+
|Row count|sqlite3 2.9.5|Extralite 2.15|Advantage|
|
|
1271
1335
|
|-:|-:|-:|-:|
|
|
1272
|
-
|10|
|
|
1273
|
-
|1K|
|
|
1274
|
-
|100K|
|
|
1336
|
+
|10|1635.0K rows/s|1892.6K rows/s|__1.16x__|
|
|
1337
|
+
|1K|6197.4K rows/s|6691.5K rows/s|__1.08x__|
|
|
1338
|
+
|100K|5845.3K rows/s|5560.3K rows/s|__0.95x__|
|
|
1275
1339
|
|
|
1276
1340
|
### Prepared Queries (Prepared Statements)
|
|
1277
1341
|
|
|
1278
1342
|
[Benchmark source
|
|
1279
1343
|
code](https://github.com/digital-fabric/extralite/blob/main/test/perf_hash_prepared.rb)
|
|
1280
1344
|
|
|
1281
|
-
|Row count|sqlite3 2.
|
|
1345
|
+
|Row count|sqlite3 2.9.5|Extralite 2.15|Advantage|
|
|
1282
1346
|
|-:|-:|-:|-:|
|
|
1283
|
-
|10|
|
|
1284
|
-
|1K|
|
|
1285
|
-
|100K|
|
|
1347
|
+
|10|1584.5K rows/s|2420.4K rows/s|__1.53x__|
|
|
1348
|
+
|1K|2738.2K rows/s|6124.3K rows/s|__2.24x__|
|
|
1349
|
+
|100K|2137.6K rows/s|5015.1K rows/s|__2.35x__|
|
|
1286
1350
|
|
|
1287
|
-
As those benchmarks show, Extralite is capabale of reading up to
|
|
1288
|
-
second, and can be more than
|
|
1351
|
+
As those benchmarks show, Extralite is capabale of reading up to 6.7M rows per
|
|
1352
|
+
second, and can be more than 2 times faster than the `sqlite3` gem.
|
|
1289
1353
|
|
|
1290
1354
|
Note that the benchmarks above were performed on synthetic data, in a
|
|
1291
1355
|
single-threaded environment, with the GVL release threshold set to -1, which
|
data/TODO.md
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- More database methods:
|
|
7
|
-
|
|
8
|
-
- `Database#quote`
|
|
9
|
-
- `Database#cache_flush` https://sqlite.org/c3ref/db_cacheflush.html
|
|
10
|
-
- `Database#release_memory` https://sqlite.org/c3ref/db_release_memory.html
|
|
11
|
-
|
|
12
|
-
- Security
|
|
13
|
-
|
|
14
|
-
- Enable extension loading by using
|
|
15
|
-
[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION](https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension)
|
|
16
|
-
in order to prevent usage of `load_extension()` SQL function.
|
|
1
|
+
- [ ] Version 3.0
|
|
2
|
+
- [ ] Run benchmarks again against latest version of sqlite3 gem
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/inline'
|
|
4
|
+
|
|
5
|
+
gemfile do
|
|
6
|
+
gem 'extralite', path: '.'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
db = Extralite::Database.new(':memory:')
|
|
10
|
+
db.pragma('foreign_keys' => 1)
|
|
11
|
+
db.execute <<~SQL
|
|
12
|
+
create table posts (
|
|
13
|
+
id integer primary key,
|
|
14
|
+
title text,
|
|
15
|
+
content text
|
|
16
|
+
);
|
|
17
|
+
create table tags (
|
|
18
|
+
id integer primary key,
|
|
19
|
+
name text
|
|
20
|
+
);
|
|
21
|
+
create table posts_tags (
|
|
22
|
+
post_id integer references posts(id) on delete cascade,
|
|
23
|
+
tag_id integer references tags(id) on delete cascade
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
insert into posts (title, content) values ('T1', 'C1');
|
|
27
|
+
insert into posts (title, content) values ('T2', 'C2');
|
|
28
|
+
insert into tags (name) values ('tag1');
|
|
29
|
+
insert into tags (name) values ('tag2');
|
|
30
|
+
insert into tags (name) values ('tag3');
|
|
31
|
+
|
|
32
|
+
insert into posts_tags(post_id, tag_id) values (1, 1);
|
|
33
|
+
insert into posts_tags(post_id, tag_id) values (1, 2);
|
|
34
|
+
insert into posts_tags(post_id, tag_id) values (2, 2);
|
|
35
|
+
insert into posts_tags(post_id, tag_id) values (2, 3);
|
|
36
|
+
SQL
|
|
37
|
+
|
|
38
|
+
sql = <<~SQL
|
|
39
|
+
select
|
|
40
|
+
posts.id, posts.title, posts.content,
|
|
41
|
+
tags.id, tags.name
|
|
42
|
+
from posts
|
|
43
|
+
left outer join posts_tags on posts_tags.post_id = posts.id
|
|
44
|
+
left outer join tags on posts_tags.tag_id = tags.id
|
|
45
|
+
order by posts.id, tags.id
|
|
46
|
+
SQL
|
|
47
|
+
|
|
48
|
+
transform = Extralite::Transform.new do
|
|
49
|
+
{
|
|
50
|
+
id: integer.identity,
|
|
51
|
+
title: text,
|
|
52
|
+
content: text,
|
|
53
|
+
tags: [{
|
|
54
|
+
id: integer.identity,
|
|
55
|
+
name: text
|
|
56
|
+
}]
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
require 'pp'
|
|
61
|
+
PP.pp db.query(transform, sql), $stdout, 40
|
data/ext/extralite/changeset.c
CHANGED
|
@@ -117,7 +117,7 @@ VALUE cleanup_track(struct track_ctx *ctx) {
|
|
|
117
117
|
/* Tracks changes in the given block and collects them into the changeset.
|
|
118
118
|
* Changes are tracked only for the given tables. If nil is supplied as the
|
|
119
119
|
* given tables, changes are tracked for all tables.
|
|
120
|
-
*
|
|
120
|
+
*
|
|
121
121
|
* # track changes for the foo and bar tables
|
|
122
122
|
* changeset.track(db, [:foo, :bar]) do
|
|
123
123
|
* run_some_queries
|
|
@@ -207,7 +207,7 @@ VALUE changeset_iter_info(sqlite3_changeset_iter *iter) {
|
|
|
207
207
|
VALUE new_values = Qnil;
|
|
208
208
|
VALUE converted = Qnil;
|
|
209
209
|
VALUE row = rb_ary_new2(4);
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
const char *tbl_name;
|
|
212
212
|
int column_count;
|
|
213
213
|
int op_int;
|
|
@@ -298,7 +298,7 @@ inline void verify_changeset(Changeset_t *changeset) {
|
|
|
298
298
|
* Each change entry is an array containing the operation (:insert / :update /
|
|
299
299
|
* :delete), the table name, an array containing the old values, and an array
|
|
300
300
|
* containing the new values.
|
|
301
|
-
*
|
|
301
|
+
*
|
|
302
302
|
* changeset.each do |(op, table, old_values, new_values)|
|
|
303
303
|
* ...
|
|
304
304
|
* end
|
|
@@ -322,7 +322,7 @@ VALUE Changeset_each(VALUE self) {
|
|
|
322
322
|
* is an array containing the operation (:insert / :update / :delete), the table
|
|
323
323
|
* name, an array containing the old values, and an array containing the new
|
|
324
324
|
* values.
|
|
325
|
-
*
|
|
325
|
+
*
|
|
326
326
|
* @return [Array<Array>] changes in the changeset
|
|
327
327
|
*/
|
|
328
328
|
VALUE Changeset_to_a(VALUE self) {
|
|
@@ -344,7 +344,7 @@ static int xConflict(void *pCtx, int eConflict, sqlite3_changeset_iter *pIter){
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
/* Applies the changeset to the given database.
|
|
347
|
-
*
|
|
347
|
+
*
|
|
348
348
|
* @param db [Extralite::Database] database to apply changes to
|
|
349
349
|
* @return [Extralite::Changeset] changeset
|
|
350
350
|
*/
|
|
@@ -374,7 +374,7 @@ VALUE Changeset_apply(VALUE self, VALUE db) {
|
|
|
374
374
|
*
|
|
375
375
|
* # undo changes
|
|
376
376
|
* changeset.invert.apply(db)
|
|
377
|
-
*
|
|
377
|
+
*
|
|
378
378
|
* @return [Extralite::Changeset] inverted changeset
|
|
379
379
|
*/
|
|
380
380
|
VALUE Changeset_invert(VALUE self) {
|
|
@@ -399,7 +399,7 @@ VALUE Changeset_invert(VALUE self) {
|
|
|
399
399
|
* changeset BLOB can be stored to file for later retrieval.
|
|
400
400
|
*
|
|
401
401
|
* File.open('my.changes', 'w+') { |f| f << changeset.to_blob }
|
|
402
|
-
*
|
|
402
|
+
*
|
|
403
403
|
* @return [String] changeset BLOB
|
|
404
404
|
*/
|
|
405
405
|
VALUE Changeset_to_blob(VALUE self) {
|
|
@@ -417,7 +417,7 @@ VALUE Changeset_to_blob(VALUE self) {
|
|
|
417
417
|
* changeset = Extralite::Changeset.new
|
|
418
418
|
* changeset.load(IO.read('my.changes'))
|
|
419
419
|
* changeset.apply(db)
|
|
420
|
-
*
|
|
420
|
+
*
|
|
421
421
|
* @param blob [String] changeset BLOB
|
|
422
422
|
* @return [Extralite::Changeset] changeset
|
|
423
423
|
*/
|
|
@@ -452,9 +452,9 @@ void Init_ExtraliteChangeset(void) {
|
|
|
452
452
|
rb_define_method(cChangeset, "to_blob", Changeset_to_blob, 0);
|
|
453
453
|
rb_define_method(cChangeset, "track", Changeset_track, 2);
|
|
454
454
|
|
|
455
|
-
SYM_delete = ID2SYM(
|
|
456
|
-
SYM_insert = ID2SYM(
|
|
457
|
-
SYM_update = ID2SYM(
|
|
455
|
+
SYM_delete = ID2SYM(rb_intern_const("delete"));
|
|
456
|
+
SYM_insert = ID2SYM(rb_intern_const("insert"));
|
|
457
|
+
SYM_update = ID2SYM(rb_intern_const("update"));
|
|
458
458
|
|
|
459
459
|
rb_gc_register_mark_object(SYM_delete);
|
|
460
460
|
rb_gc_register_mark_object(SYM_insert);
|