sequel-xtdb 0.1.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 588ca986b6f08698e828e9b82ca407efe7ed9cb53bcf88e4bb7d5a3079c543bb
4
- data.tar.gz: 6f40888887ed889acf0bb4fe0b71aae53e566453668dcea3c983fc5fddfdb11c
3
+ metadata.gz: feef2fdeeefa8b1adfd9d214aab772c02250814aa8e6ef36a79bc7eddc4a8386
4
+ data.tar.gz: 417e16888185230ad9f7714b7d0d322594457f6f0d8645c033a9203463103293
5
5
  SHA512:
6
- metadata.gz: de181ba238344b2eb73143653a63ecd67d53a1920f5016f88b505ec4bc0ad9c8f8461e7bc15dc66f19ac53fe01e840db470a8e7128e48fd33d491b93e73210d2
7
- data.tar.gz: a4dab5cb1ca1ee2e760580df3d12efa101e176dcf0bf5c03f0fc7bab6bedef08f557a6175eaffc5080e0c8b7c6b75e01b78d406aef6c9b9bc65c7095f6cb1b65
6
+ metadata.gz: 28456e08dfc22572d63a5de8dbfba0b8f849a78478f1ec43336e2495212a4217bacf665d53faf7f205d54c75ef8df931064288dd079bf496dd85389bcb3d1911
7
+ data.tar.gz: cb4e306b7641e07812e146843d982104e143935c83d58ffc7cd480246f1dec99fc0f5946fa2ebd964eed4c50e338051785fa772119fe497d156cf88e82e2925c
data/.envrc ADDED
@@ -0,0 +1,7 @@
1
+ # env-var using [direnv](https://github.com/direnv/direnv)
2
+ PATH_add bin
3
+
4
+ export XTDB_URL=xtdb://localhost:5432/xtdb
5
+
6
+ # put overrides in .envrc.local
7
+ source_env_if_exists .envrc.local
data/README.md CHANGED
@@ -24,7 +24,7 @@ Shortcut to happiness:
24
24
  $ sequel 'xtdb://localhost:5432/xtdb'
25
25
 
26
26
  # ..or from repl/your project
27
- DB = Sequel.connect("xtdb://localhost:54321/xtdb")
27
+ DB = Sequel.connect("xtdb://localhost:5432/xtdb")
28
28
 
29
29
  # then
30
30
  irb(main)> DB << "insert into products(_id, name, price) values(1, 'Spam', 1000), (2, 'Ham', 1200)"
@@ -32,6 +32,35 @@ irb(main)> DB["select * from products"].all
32
32
  => [{:_id=>2, :name=>"Ham", :price=>1200}, {:_id=>1, :name=>"Spam", :price=>1100}]
33
33
  ```
34
34
 
35
+ ### time-travel
36
+
37
+ _these examples use the [activesupport time helpers](https://api.rubyonrails.org/classes/ActiveSupport/Duration.html)_
38
+
39
+ ```ruby
40
+ DB = Sequel.connect("xtdb://localhost:5432/xtdb")
41
+
42
+ # get a dataset (ie query)
43
+ users = DB[:users]
44
+ past, future = 2.days.ago, 2.days.from_now
45
+ ds1, ds2 = users.as_of(valid: past), users.as_of(valid: future)
46
+
47
+ # expect empty
48
+ ds1.all
49
+ ds1.insert(_id: 1, name: "James")
50
+
51
+ # expect a user
52
+ ds1.as_of(valid: 2.days.ago).all
53
+
54
+ # add to future
55
+ ds2.insert(_id: 2, name: "Jeremy")
56
+
57
+ # expect only James
58
+ users.all
59
+ # expect both James and Jeremy
60
+ ds2.as_of(valid: 2.days.from_now).all
61
+ ```
62
+
63
+
35
64
  ## Status
36
65
 
37
66
  Very early days :)
@@ -40,7 +69,9 @@ Currently it's essentially the postgres-adapter with support for a xtdb-scheme u
40
69
 
41
70
  ## Development
42
71
 
43
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
72
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
73
+
74
+ You can also run `bin/console [xtdb-url]` for an interactive prompt that will allow you to experiment. The script will pick up on env-var `XTDB_URL`, though the argument takes precedence.
44
75
 
45
76
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
46
77
 
@@ -1,9 +1,104 @@
1
1
  module Sequel
2
2
  module XTDB
3
3
  module DatabaseMethods
4
+ def database_type
5
+ :xtdb
6
+ end
7
+
8
+ def primary_key(_table)
9
+ # eg used for RETURNING on insert (prevents crash)
10
+ :_id
11
+ end
12
+
13
+ # Get a dataset with `current`, `valid` and `system` set.
14
+ #
15
+ # For selects this creates the SETTING pre-amble, e.g. 'SETTING DEFAULT VALID_TIME ...':
16
+ # ```
17
+ # DB.as_of(current: 2.weeks.ago).select(Sequel.lit('current_timestamp')).single_value
18
+ # ```
19
+ #
20
+ # A block can be provided as a convenience to stay in SQL-land (selects only):
21
+ # ```
22
+ # DB.as_of(current: 2.hours.ago) do
23
+ # DB["select current_timestamp"]
24
+ # end.sql
25
+ # =>
26
+ # SETTING
27
+ # CURRENT_TIME TO TIMESTAMP '2024-12-17T12:59:48+01:00'
28
+ # select current_timestamp
29
+ # ```
30
+ #
31
+ # When doing inserts, the `_valid_from` will be added (if not provided):
32
+ # ```
33
+ # DB[:products].as_of(valid: 2.weeks.ago).insert(_id: 1, name: 'Spam')
34
+ # ```
35
+ def as_of(...)
36
+ ds = @default_dataset.as_of(...)
37
+ return ds unless block_given?
38
+
39
+ yield.clone(append_sql: ds.select_setting_sql(""))
40
+ end
4
41
  end
5
42
 
6
43
  module DatasetMethods
44
+ Dataset.def_sql_method(self, :select,
45
+ [["if opts[:values]",
46
+ %w[values compounds order limit]],
47
+ ["else",
48
+ %w[setting select distinct columns from join where group having compounds order limit lock]]])
49
+
50
+ def as_of(valid: nil, system: nil, current: nil)
51
+ {valid: valid, system: system, current: current}.reject { |_k, v| v.nil? }.then do |opts|
52
+ clone(opts)
53
+ end
54
+ end
55
+
56
+ def server_version
57
+ 0
58
+ end
59
+
60
+ def insert_values_sql(sql)
61
+ if (from_ix = opts[:columns].index(:_valid_from))
62
+ opts[:values][from_ix] = Sequel.lit("TIMESTAMP ?", opts[:values][from_ix])
63
+ end
64
+
65
+ if (to_ix = opts[:columns].index(:_valid_to))
66
+ opts[:values][to_ix] = Sequel.lit("TIMESTAMP ?", opts[:values][to_ix])
67
+ end
68
+
69
+ super
70
+ end
71
+
72
+ def insert_columns_sql(sql)
73
+ if opts[:valid] && !opts[:columns].index(:_valid_from)
74
+ opts[:columns] << :_valid_from
75
+ opts[:values] << opts[:valid]
76
+ end
77
+ super
78
+ end
79
+
80
+ def select_setting_sql(sql)
81
+ setting = opts.slice(:current, :valid, :system)
82
+ return sql if setting.empty?
83
+
84
+ cast_value = ->(v) do
85
+ case v
86
+ when DateTime, Time
87
+ literal_append "TIMESTAMP ", v.iso8601
88
+ when Date
89
+ literal_append "DATE ", v.iso8601
90
+ end
91
+ end
92
+ sql << "SETTING "
93
+ sql << setting.map do |k, v|
94
+ if k == :current
95
+ literal_append "CURRENT_TIME TO TIMESTAMP ", v.iso8601
96
+ else
97
+ "DEFAULT #{k.upcase}_TIME AS OF #{cast_value[v]}"
98
+ end
99
+ end.join(", ")
100
+ sql << " "
101
+ end
7
102
  end
8
103
  end
9
104
  end
@@ -1,4 +1,4 @@
1
- require_relative 'shared/xtdb'
1
+ require_relative "shared/xtdb"
2
2
  require "sequel/adapters/postgres"
3
3
 
4
4
  module Sequel
@@ -13,12 +13,31 @@ module Sequel
13
13
  def adapter_initialize
14
14
  # XTDB can't handle this SET-command
15
15
  @opts[:force_standard_strings] = false
16
+
17
+ Sequel.database_timezone = :utc
18
+ Sequel.application_timezone = :local
19
+
20
+ if (app_tz = @opts[:application_timezone])
21
+ Sequel.extension(:named_timezones)
22
+ Sequel.application_timezone = app_tz
23
+ end
24
+
16
25
  super
17
26
  end
27
+
28
+ def dataset_class_default
29
+ Dataset
30
+ end
18
31
  end
19
32
 
20
33
  class Dataset < Sequel::Postgres::Dataset
21
34
  include ::Sequel::XTDB::DatasetMethods
35
+
36
+ private
37
+
38
+ def default_timestamp_format
39
+ "'%Y-%m-%d %H:%M:%S'"
40
+ end
22
41
  end
23
42
  end
24
43
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Sequel
4
4
  module XTDB
5
- VERSION = "0.1.0"
5
+ # NOTE when releasing the git-tag will replace the version below
6
+ VERSION = "0.3.0"
6
7
  end
7
8
  end
data/rakelib/gem.rake ADDED
@@ -0,0 +1,23 @@
1
+ namespace :gem do
2
+ task "write_version", [:version] do |_task, args|
3
+ if args[:version]
4
+ version = args[:version].split("=").last
5
+ version_file = File.expand_path("../../lib/sequel/xtdb/version.rb", __FILE__)
6
+
7
+ system(<<~CMD, exception: true)
8
+ ruby -pi -e 'gsub(/VERSION = ".*"/, %{VERSION = "#{version}"})' #{version_file}
9
+ CMD
10
+ Bundler.ui.confirm "Version #{version} written to #{version_file}."
11
+ else
12
+ Bundler.ui.warn "No version provided, keeping version.rb as is."
13
+ end
14
+ end
15
+
16
+ desc "Build [version]"
17
+ task "build", [:version] => ["write_version", "build"] do
18
+ end
19
+
20
+ desc "Build and push [version] to rubygems"
21
+ task "release", [:version] => ["gem:build", "release:rubygem_push"] do
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel-xtdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-13 00:00:00.000000000 Z
11
+ date: 2024-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -45,6 +45,7 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".envrc"
48
49
  - ".rspec"
49
50
  - ".standard.yml"
50
51
  - CHANGELOG.md
@@ -55,6 +56,7 @@ files:
55
56
  - lib/sequel/adapters/xtdb.rb
56
57
  - lib/sequel/xtdb.rb
57
58
  - lib/sequel/xtdb/version.rb
59
+ - rakelib/gem.rake
58
60
  - sig/sequel/xtdb.rbs
59
61
  homepage: https://github.com/eval/sequel-xtdb
60
62
  licenses:
@@ -78,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
80
  - !ruby/object:Gem::Version
79
81
  version: '0'
80
82
  requirements: []
81
- rubygems_version: 3.5.23
83
+ rubygems_version: 3.5.22
82
84
  signing_key:
83
85
  specification_version: 4
84
86
  summary: Adapter to connect to XTDB v2 using Sequel.