lib/sequel/adapters/shared/xtdb.rb in sequel-xtdb-0.3.0 vs lib/sequel/adapters/shared/xtdb.rb in sequel-xtdb-0.3.2
- old
+ new
@@ -1,61 +1,60 @@
+require "sequel/adapters/utils/unmodified_identifiers"
+
module Sequel
module XTDB
+ Sequel::Database.set_shared_adapter_scheme :xtdb, self
+
+ def self.mock_adapter_setup(db)
+ db.instance_exec do
+ @server_version = 0
+
+ # def schema_parse_table(*)
+ # []
+ # end
+ # singleton_class.send(:private, :schema_parse_table)
+ # adapter_initialize
+ # extend(MockAdapterDatabaseMethods)
+ end
+ end
+
module DatabaseMethods
+ include UnmodifiedIdentifiers::DatabaseMethods # ensure lowercase identifiers
+
def database_type
:xtdb
end
def primary_key(_table)
# eg used for RETURNING on insert (prevents crash)
:_id
end
# Get a dataset with `current`, `valid` and `system` set.
- #
- # For selects this creates the SETTING pre-amble, e.g. 'SETTING DEFAULT VALID_TIME ...':
- # ```
- # DB.as_of(current: 2.weeks.ago).select(Sequel.lit('current_timestamp')).single_value
- # ```
- #
- # A block can be provided as a convenience to stay in SQL-land (selects only):
- # ```
- # DB.as_of(current: 2.hours.ago) do
- # DB["select current_timestamp"]
- # end.sql
- # =>
- # SETTING
- # CURRENT_TIME TO TIMESTAMP '2024-12-17T12:59:48+01:00'
- # select current_timestamp
- # ```
- #
- # When doing inserts, the `_valid_from` will be added (if not provided):
- # ```
- # DB[:products].as_of(valid: 2.weeks.ago).insert(_id: 1, name: 'Spam')
- # ```
def as_of(...)
- ds = @default_dataset.as_of(...)
- return ds unless block_given?
-
- yield.clone(append_sql: ds.select_setting_sql(""))
+ @default_dataset.as_of(...)
end
end
module DatasetMethods
+ include UnmodifiedIdentifiers::DatasetMethods # ensure lowercase identifiers
+
Dataset.def_sql_method(self, :select,
[["if opts[:values]",
%w[values compounds order limit]],
["else",
- %w[setting select distinct columns from join where group having compounds order limit lock]]])
+ %w[select distinct columns from join where group having compounds order limit lock]]])
def as_of(valid: nil, system: nil, current: nil)
{valid: valid, system: system, current: current}.reject { |_k, v| v.nil? }.then do |opts|
clone(opts)
end
end
def server_version
+ # TODO 2_000_000 from xt.version() output
+ # requires all def_sql_methods
0
end
def insert_values_sql(sql)
if (from_ix = opts[:columns].index(:_valid_from))
@@ -75,30 +74,52 @@
opts[:values] << opts[:valid]
end
super
end
- def select_setting_sql(sql)
+ def select_sql
+ sql = super
+
+ if (setting = select_setting_sql)
+ if sql.frozen?
+ setting += sql
+ setting.freeze
+ elsif @opts[:append_sql] || @opts[:placeholder_literalizer]
+ setting << sql
+ else
+ setting + sql
+ end
+ else
+ sql
+ end
+ end
+
+ def select_setting_sql
setting = opts.slice(:current, :valid, :system)
- return sql if setting.empty?
+ return if setting.empty?
cast_value = ->(v) do
- case v
- when DateTime, Time
- literal_append "TIMESTAMP ", v.iso8601
- when Date
- literal_append "DATE ", v.iso8601
+ type = case v
+ when DateTime, Time then "TIMESTAMP"
+ when Date then "DATE"
end
+ literal_append "#{type} ", v.iso8601
end
- sql << "SETTING "
- sql << setting.map do |k, v|
+ sql = "SETTING "
+ sql.concat(setting.map do |k, v|
if k == :current
- literal_append "CURRENT_TIME TO TIMESTAMP ", v.iso8601
+ "CURRENT_TIME TO #{cast_value[v.to_time]}"
else
"DEFAULT #{k.upcase}_TIME AS OF #{cast_value[v]}"
end
- end.join(", ")
- sql << " "
+ end.join(", "))
+ sql.concat " "
+ end
+
+ private
+
+ def default_timestamp_format
+ "'%Y-%m-%d %H:%M:%S'"
end
end
end
end