rasti-db 0.4.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25e0bbb3407cfae9d3217b22dff5f9756f451d2c
4
- data.tar.gz: 8e92b0f310f1a7761e62b288cf3482b788f6c89c
3
+ metadata.gz: 01b5188397b357e5b8414eebd556115131bb8c46
4
+ data.tar.gz: 84d1beb743f8a8ff07247724013bb8c0f9394ede
5
5
  SHA512:
6
- metadata.gz: 6ce81a8a43cba1212c251d86a7cd32293c649059b0b1674bfb83fbc845cd4f9376ca2cd5f89046eecf26b69c63ce624f255a9f62f67511afca7e86d308eea985
7
- data.tar.gz: f61e038f876cb4064fb75b61d2141eda0d013d17841d6b6b1e3933564e147c5a75d35df0f9595e42a7adebd0456e8b8ae7280f07cb1860fd58aa67e9f44a0a03
6
+ metadata.gz: 10563c028636028583d1205b0c999ad82e5281180ba16367442b1f5804510b09184db8930145e9937e2a82e675879aa9f56a8eea8f399ab6346eb6f40a6df1eb
7
+ data.tar.gz: a8ba4affb905f24c39cfab601b51cd263ccf2ab3c34c22494e4fc53475e96530e73df7e2759af381e7d1f2f288b2f168408432138a37042b40823a1697c64a46
data/.travis.yml CHANGED
@@ -1,15 +1,15 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 1.9.3
5
4
  - 2.0
6
5
  - 2.1
7
6
  - 2.2
8
7
  - 2.3.0
9
8
  - 2.4.0
10
9
  - 2.5.0
11
- - jruby-1.7.25
10
+ - 2.6.0
12
11
  - jruby-9.1.7.0
12
+ - jruby-9.1.16.0
13
13
  - ruby-head
14
14
  - jruby-head
15
15
 
@@ -19,5 +19,9 @@ matrix:
19
19
  - rvm: ruby-head
20
20
  - rvm: jruby-head
21
21
 
22
+ jdk:
23
+ - openjdk8
24
+
22
25
  before_install:
23
- - gem install bundler
26
+ - rvm all-gemsets do gem uninstall bundler -ax || true
27
+ - gem install bundler -v "< 2"
@@ -2,8 +2,9 @@ module Rasti
2
2
  module DB
3
3
  class Collection
4
4
 
5
- QUERY_METHODS = (Query::DATASET_CHAINED_METHODS + [:graph, :count, :all, :first, :pluck, :primary_keys, :any?, :empty?, :raw]).freeze
5
+ QUERY_METHODS = (Query::DATASET_CHAINED_METHODS + [:graph, :count, :all, :each, :first, :pluck, :primary_keys, :any?, :empty?, :raw]).freeze
6
6
 
7
+ include Enumerable
7
8
  include Helpers::WithSchema
8
9
 
9
10
  class << self
@@ -75,7 +76,7 @@ module Rasti
75
76
  queries[name] = lambda || block
76
77
 
77
78
  define_method name do |*args|
78
- query.instance_exec *args, &self.class.queries[name]
79
+ query.instance_exec(*args, &self.class.queries[name])
79
80
  end
80
81
  end
81
82
 
@@ -94,7 +95,7 @@ module Rasti
94
95
 
95
96
  def insert(attributes)
96
97
  db.transaction do
97
- db_attributes = type_converter.apply_to attributes
98
+ db_attributes = transform_attributes_to_db attributes
98
99
  collection_attributes, relations_primary_keys = split_related_attributes db_attributes
99
100
  primary_key = dataset.insert collection_attributes
100
101
  save_relations primary_key, relations_primary_keys
@@ -103,7 +104,7 @@ module Rasti
103
104
  end
104
105
 
105
106
  def bulk_insert(attributes, options={})
106
- db_attributes = type_converter.apply_to attributes
107
+ db_attributes = attributes.map { |attrs| transform_attributes_to_db attrs }
107
108
  dataset.multi_insert db_attributes, options
108
109
  end
109
110
 
@@ -117,7 +118,7 @@ module Rasti
117
118
 
118
119
  def update(primary_key, attributes)
119
120
  db.transaction do
120
- db_attributes = type_converter.apply_to attributes
121
+ db_attributes = transform_attributes_to_db attributes
121
122
  collection_attributes, relations_primary_keys = split_related_attributes db_attributes
122
123
  dataset.where(self.class.primary_key => primary_key).update(collection_attributes) unless collection_attributes.empty?
123
124
  save_relations primary_key, relations_primary_keys
@@ -126,7 +127,7 @@ module Rasti
126
127
  end
127
128
 
128
129
  def bulk_update(attributes, &block)
129
- db_attributes = type_converter.apply_to attributes
130
+ db_attributes = transform_attributes_to_db attributes
130
131
  build_query(&block).instance_eval { dataset.update db_attributes }
131
132
  nil
132
133
  end
@@ -183,8 +184,11 @@ module Rasti
183
184
 
184
185
  private
185
186
 
186
- def type_converter
187
- @type_converter ||= TypeConverter.new db, qualified_collection_name
187
+ def transform_attributes_to_db(attributes)
188
+ attributes.each_with_object({}) do |(attribute_name, value), result|
189
+ transformed_value = Rasti::DB.to_db db, qualified_collection_name, attribute_name, value
190
+ result[attribute_name] = transformed_value
191
+ end
188
192
  end
189
193
 
190
194
  def qualified_collection_name
@@ -235,7 +239,7 @@ module Rasti
235
239
  .map(relation.target_collection_class.primary_key)
236
240
 
237
241
  target_collection = relation.target_collection_class.new db, schema
238
- target_collection.delete_cascade *relations_ids unless relations_ids.empty?
242
+ target_collection.delete_cascade(*relations_ids) unless relations_ids.empty?
239
243
  end
240
244
  end
241
245
 
@@ -102,13 +102,9 @@ module Rasti
102
102
  attr_reader :attributes
103
103
 
104
104
  def fetch_attribute(name)
105
- attributes.key?(name) ? casted_attribute(name) : raise(UninitializedAttributeError, name)
105
+ attributes.key?(name) ? Rasti::DB.from_db(attributes[name]) : raise(UninitializedAttributeError, name)
106
106
  end
107
107
 
108
- def casted_attribute(name)
109
- attributes[name].is_a?(Time) ? Timing::TimeInZone.new(attributes[name]) : attributes[name]
110
- end
111
-
112
108
  end
113
109
  end
114
110
  end
@@ -35,7 +35,7 @@ module Rasti
35
35
  alias_method :to_a, :all
36
36
 
37
37
  def each(&block)
38
- all.each &block
38
+ all.each(&block)
39
39
  end
40
40
 
41
41
  DATASET_CHAINED_METHODS.each do |method|
@@ -88,7 +88,7 @@ module Rasti
88
88
  private
89
89
 
90
90
  def chainable(&block)
91
- ds = instance_eval &block
91
+ ds = instance_eval(&block)
92
92
  Query.new collection_class, ds, relations, schema
93
93
  end
94
94
 
@@ -105,7 +105,7 @@ module Rasti
105
105
 
106
106
  def method_missing(method, *args, &block)
107
107
  if collection_class.queries.key?(method)
108
- instance_exec *args, &collection_class.queries[method]
108
+ instance_exec(*args, &collection_class.queries[method])
109
109
  else
110
110
  super
111
111
  end
@@ -0,0 +1,65 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ class Postgres
5
+
6
+ CONVERTERS = [PostgresTypes::JSON, PostgresTypes::JSONB, PostgresTypes::HStore, PostgresTypes::Array]
7
+
8
+ @to_db_mapping = {}
9
+
10
+ class << self
11
+
12
+ def to_db(db, collection_name, attribute_name, value)
13
+ to_db_mapping = to_db_mapping_for db, collection_name
14
+
15
+ if to_db_mapping.key? attribute_name
16
+ to_db_mapping[attribute_name][:converter].to_db value, to_db_mapping[attribute_name][:sub_type]
17
+ else
18
+ value
19
+ end
20
+ end
21
+
22
+ def from_db(object)
23
+ if from_db_mapping.key? object.class
24
+ from_db_mapping[object.class].from_db object
25
+ else
26
+ object
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def to_db_mapping_for(db, collection_name)
33
+ key = [db.opts[:database], collection_name]
34
+
35
+ @to_db_mapping[key] ||= begin
36
+ columns = Hash[db.schema(collection_name)]
37
+
38
+ columns.each_with_object({}) do |(name, schema), hash|
39
+ CONVERTERS.each do |converter|
40
+ unless hash.key? name
41
+ match = converter.column_type_regex.match schema[:db_type]
42
+
43
+ hash[name] = {converter: converter, sub_type: match.captures.first} if match
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def from_db_mapping
51
+ @from_db_mapping ||= begin
52
+ CONVERTERS.each_with_object({}) do |converter, result|
53
+ converter.db_classes.each do |db_class|
54
+ result[db_class] = converter
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,32 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ module PostgresTypes
5
+ class Array
6
+
7
+ class << self
8
+
9
+ def column_type_regex
10
+ /^([a-z]+)\[\]$/
11
+ end
12
+
13
+ def to_db(value, sub_type)
14
+ array = sub_type == 'hstore' ? value.map { |v| Sequel.hstore v } : value
15
+ Sequel.pg_array array, sub_type
16
+ end
17
+
18
+ def db_classes
19
+ [Sequel::Postgres::PGArray]
20
+ end
21
+
22
+ def from_db(object)
23
+ object.to_a
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ module PostgresTypes
5
+ class HStore
6
+
7
+ class << self
8
+
9
+ def column_type_regex
10
+ /^hstore$/
11
+ end
12
+
13
+ def to_db(value, sub_type)
14
+ Sequel.hstore value
15
+ end
16
+
17
+ def db_classes
18
+ [Sequel::Postgres::HStore]
19
+ end
20
+
21
+ def from_db(object)
22
+ object.to_h
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ module PostgresTypes
5
+ class JSON
6
+
7
+ class << self
8
+
9
+ def column_type_regex
10
+ /^json$/
11
+ end
12
+
13
+ def to_db(value, sub_type)
14
+ Sequel.pg_json value
15
+ end
16
+
17
+ def db_classes
18
+ @db_classes ||= from_db_convertions.keys
19
+ end
20
+
21
+ def from_db(object)
22
+ object.public_send from_db_convertions[object.class]
23
+ end
24
+
25
+ private
26
+
27
+ def from_db_convertions
28
+ @from_db_convertions ||= {
29
+ Sequel::Postgres::JSONHash => :to_h,
30
+ Sequel::Postgres::JSONArray => :to_a
31
+ }
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ module PostgresTypes
5
+ class JSONB
6
+
7
+ class << self
8
+
9
+ def column_type_regex
10
+ /^jsonb$/
11
+ end
12
+
13
+ def to_db(value, sub_type)
14
+ Sequel.pg_jsonb value
15
+ end
16
+
17
+ def db_classes
18
+ @db_classes ||= from_db_convertions.keys
19
+ end
20
+
21
+ def from_db(object)
22
+ object.public_send from_db_convertions[object.class]
23
+ end
24
+
25
+ private
26
+
27
+ def from_db_convertions
28
+ @from_db_convertions ||= {
29
+ Sequel::Postgres::JSONBHash => :to_h,
30
+ Sequel::Postgres::JSONBArray => :to_a
31
+ }
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ module Rasti
2
+ module DB
3
+ module TypeConverters
4
+ class TimeInZone
5
+
6
+ class << self
7
+
8
+ def to_db(db, collection_name, attribute_name, value)
9
+ value
10
+ end
11
+
12
+ def from_db(value)
13
+ value.is_a?(Time) ? Timing::TimeInZone.new(value) : value
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module DB
3
- VERSION = '0.4.1'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
data/lib/rasti/db.rb CHANGED
@@ -2,6 +2,7 @@ require 'sequel'
2
2
  require 'consty'
3
3
  require 'time'
4
4
  require 'timing'
5
+ require 'class_config'
5
6
 
6
7
  require_relative 'db/version'
7
8
  require_relative 'db/helpers'
@@ -14,4 +15,31 @@ require_relative 'db/relations/many_to_one'
14
15
  require_relative 'db/relations/many_to_many'
15
16
  require_relative 'db/collection'
16
17
  require_relative 'db/model'
17
- require_relative 'db/type_converter'
18
+ require_relative 'db/type_converters/time_in_zone'
19
+ require_relative 'db/type_converters/postgres_types/array'
20
+ require_relative 'db/type_converters/postgres_types/hstore'
21
+ require_relative 'db/type_converters/postgres_types/json'
22
+ require_relative 'db/type_converters/postgres_types/jsonb'
23
+ require_relative 'db/type_converters/postgres'
24
+
25
+ module Rasti
26
+ module DB
27
+
28
+ extend ClassConfig
29
+
30
+ attr_config :type_converters, []
31
+
32
+ def self.to_db(db, collection_name, attribute_name, value)
33
+ type_converters.inject(value) do |result, type_converter|
34
+ type_converter.to_db db, collection_name, attribute_name, result
35
+ end
36
+ end
37
+
38
+ def self.from_db(value)
39
+ type_converters.inject(value) do |result, type_converter|
40
+ type_converter.from_db result
41
+ end
42
+ end
43
+
44
+ end
45
+ end
data/rasti-db.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_runtime_dependency 'sequel', '~> 5.0'
22
22
  spec.add_runtime_dependency 'consty', '~> 1.0', '>= 1.0.3'
23
23
  spec.add_runtime_dependency 'timing', '~> 0.1', '>= 0.1.3'
24
+ spec.add_runtime_dependency 'class_config', '~> 0.0', '>= 0.0.2'
24
25
 
25
26
  spec.add_development_dependency 'bundler', '~> 1.12'
26
27
  spec.add_development_dependency 'rake', '~> 11.0'
@@ -254,6 +254,12 @@ describe 'Collection' do
254
254
  users.all.must_equal [User.new(id: id, name: 'User 1')]
255
255
  end
256
256
 
257
+ it 'Map' do
258
+ 1.upto(2) { |i| db[:users].insert name: "User #{i}" }
259
+
260
+ users.map(&:name).sort.must_equal ['User 1', 'User 2']
261
+ end
262
+
257
263
  it 'First' do
258
264
  1.upto(10) { |i| db[:users].insert name: "User #{i}" }
259
265
 
@@ -8,6 +8,10 @@ require 'sequel/extensions/pg_hstore'
8
8
  require 'sequel/extensions/pg_array'
9
9
  require 'sequel/extensions/pg_json'
10
10
 
11
+ Rasti::DB.configure do |config|
12
+ config.type_converters = [Rasti::DB::TypeConverters::TimeInZone]
13
+ end
14
+
11
15
  User = Rasti::DB::Model[:id, :name, :posts, :comments, :person]
12
16
  Post = Rasti::DB::Model[:id, :title, :body, :user_id, :user, :comments, :categories]
13
17
  Comment = Rasti::DB::Model[:id, :text, :user_id, :user, :post_id, :post]
@@ -68,11 +72,6 @@ class People < Rasti::DB::Collection
68
72
  end
69
73
 
70
74
 
71
- Rasti::DB::TypeConverter::CONVERTIONS[:sqlite] = {
72
- Regexp.new('integer') => ->(value, match) { value.to_i }
73
- }
74
-
75
-
76
75
  class Minitest::Spec
77
76
 
78
77
  let(:users) { Users.new db }
data/spec/model_spec.rb CHANGED
@@ -28,12 +28,6 @@ describe 'Model' do
28
28
  proc { post.invalid_method }.must_raise NoMethodError
29
29
  end
30
30
 
31
- it 'Time conversion' do
32
- person = Person.new birth_date: Time.parse('2019-01-07T11:00:00-03:00')
33
-
34
- person.birth_date.must_be_instance_of Timing::TimeInZone
35
- end
36
-
37
31
  end
38
32
 
39
33
 
@@ -0,0 +1,229 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Rasti::DB::TypeConverters::Postgres do
4
+
5
+ let(:type_converter) { Rasti::DB::TypeConverters::Postgres }
6
+
7
+ let(:pg) do
8
+ Object.new.tap do |pg|
9
+
10
+ def pg.opts
11
+ {
12
+ database: 'database'
13
+ }
14
+ end
15
+
16
+ def pg.schema(table_name, opts={})
17
+ [
18
+ [:hash, {db_type: 'hstore'}],
19
+ [:text_array, {db_type: 'text[]'}],
20
+ [:integer_array, {db_type: 'integer[]'}],
21
+ [:hstore_array, {db_type: 'hstore[]'}],
22
+ [:json, {db_type: 'json'}],
23
+ [:jsonb, {db_type: 'jsonb'}]
24
+ ]
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ describe 'Default' do
31
+
32
+ it 'must not change value in to_db if column not found in mapping' do
33
+ string = type_converter.to_db pg, :table_name, :column, "hola"
34
+
35
+ string.class.must_equal String
36
+ string.must_equal "hola"
37
+ end
38
+
39
+ it 'must not change value in from_db if class not found in mapping' do
40
+ string = type_converter.from_db "hola"
41
+
42
+ string.class.must_equal String
43
+ string.must_equal "hola"
44
+ end
45
+
46
+ end
47
+
48
+
49
+ describe 'HStore' do
50
+
51
+ describe 'To DB' do
52
+
53
+ it 'must transform Hash to HStore' do
54
+ hstore = type_converter.to_db pg, :table_name, :hash, {key_1: 1, key_2: 2}
55
+
56
+ hstore.class.must_equal Sequel::Postgres::HStore
57
+ hstore.must_equal 'key_1' => '1', 'key_2' => '2'
58
+ end
59
+
60
+ it 'must transform empty hash to HStore' do
61
+ hstore = type_converter.to_db pg, :table_name, :hash, {}
62
+
63
+ hstore.class.must_equal Sequel::Postgres::HStore
64
+ hstore.must_be_empty
65
+ end
66
+
67
+ end
68
+
69
+ describe 'From DB' do
70
+
71
+ it 'must transform HStore to Hash' do
72
+ hstore = Sequel::Postgres::HStore.new 'key_1' => '1', 'key_2' => '2'
73
+ hash = type_converter.from_db hstore
74
+
75
+ hash.class.must_equal Hash
76
+ hash.must_equal hstore
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ describe 'Array' do
84
+
85
+ describe 'To DB' do
86
+
87
+ it 'must transform String[] to PGArray' do
88
+ pg_array = type_converter.to_db pg, :table_name, :text_array, %w(a b c)
89
+
90
+ pg_array.class.must_equal Sequel::Postgres::PGArray
91
+ pg_array.array_type.must_equal 'text'
92
+ pg_array.must_equal %w(a b c)
93
+ end
94
+
95
+ it 'must transform Integer[] to PGArray' do
96
+ pg_array = type_converter.to_db pg, :table_name, :integer_array, [1,2,3]
97
+
98
+ pg_array.class.must_equal Sequel::Postgres::PGArray
99
+ pg_array.array_type.must_equal 'integer'
100
+ pg_array.must_equal [1,2,3]
101
+ end
102
+
103
+ it 'must transform Hstore[] to PGArray' do
104
+ pg_array = type_converter.to_db pg, :table_name, :hstore_array, [{key: 0}, {key: 1}]
105
+
106
+ pg_array.class.must_equal Sequel::Postgres::PGArray
107
+ pg_array.array_type.must_equal 'hstore'
108
+
109
+ pg_array.each_with_index do |element, index|
110
+ element.class.must_equal Sequel::Postgres::HStore
111
+ element.must_equal 'key' => index.to_s
112
+ end
113
+ end
114
+
115
+ it 'Must transform empty array to PGArray' do
116
+ pg_array = type_converter.to_db pg, :table_name, :integer_array, []
117
+
118
+ pg_array.class.must_equal Sequel::Postgres::PGArray
119
+ pg_array.array_type.must_equal 'integer'
120
+ pg_array.must_be_empty
121
+ end
122
+
123
+ end
124
+
125
+ describe 'From DB' do
126
+
127
+ it 'must transform PGArray to Array' do
128
+ pg_array = Sequel::Postgres::PGArray.new [1,2,3]
129
+ array = type_converter.from_db pg_array
130
+
131
+ array.class.must_equal Array
132
+ array.must_equal pg_array
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+
139
+ describe 'JSON' do
140
+
141
+ let(:json_hash) { {key_1: {key_2: [3]}} }
142
+ let(:json_array) { [{key_1: {key_2: [3]}}] }
143
+
144
+ describe 'To DB' do
145
+
146
+ it 'must transform Hash to JSONHash' do
147
+ pg_json_hash = type_converter.to_db pg, :table_name, :json, json_hash
148
+
149
+ pg_json_hash.class.must_equal Sequel::Postgres::JSONHash
150
+ pg_json_hash.must_equal json_hash
151
+ end
152
+
153
+ it 'must transform Array to JSONArray' do
154
+ pg_json_array = type_converter.to_db pg, :table_name, :json, json_array
155
+
156
+ pg_json_array.class.must_equal Sequel::Postgres::JSONArray
157
+ pg_json_array.must_equal json_array
158
+ end
159
+
160
+ end
161
+
162
+ describe 'From DB' do
163
+
164
+ it 'must transform JSONHash to Hash' do
165
+ pg_json_hash = Sequel::Postgres::JSONHash.new json_hash
166
+ hash = type_converter.from_db pg_json_hash
167
+
168
+ hash.class.must_equal Hash
169
+ hash.must_equal pg_json_hash
170
+ end
171
+
172
+ it 'must transform JSONArray to Array' do
173
+ pg_json_array = Sequel::Postgres::JSONArray.new json_array
174
+ array = type_converter.from_db pg_json_array
175
+
176
+ array.class.must_equal Array
177
+ array.must_equal pg_json_array
178
+ end
179
+
180
+ end
181
+
182
+ end
183
+
184
+ describe 'JSONB' do
185
+
186
+ let(:json_hash) { {key_1: {key_2: [3]}} }
187
+ let(:json_array) { [{key_1: {key_2: [3]}}] }
188
+
189
+ describe 'To DB' do
190
+
191
+ it 'must transform Hash to JSONBHash' do
192
+ pg_jsonb_hash = type_converter.to_db pg, :table_name, :jsonb, json_hash
193
+
194
+ pg_jsonb_hash.class.must_equal Sequel::Postgres::JSONBHash
195
+ pg_jsonb_hash.must_equal json_hash
196
+ end
197
+
198
+ it 'must transform Array to JSONBArray' do
199
+ pg_jsonb_array = type_converter.to_db pg, :table_name, :jsonb, json_array
200
+
201
+ pg_jsonb_array.class.must_equal Sequel::Postgres::JSONBArray
202
+ pg_jsonb_array.must_equal json_array
203
+ end
204
+
205
+ end
206
+
207
+ describe 'From DB' do
208
+
209
+ it 'must transform JSONBHash to Hash' do
210
+ pg_jsonb_hash = Sequel::Postgres::JSONBHash.new json_hash
211
+ hash = type_converter.from_db pg_jsonb_hash
212
+
213
+ hash.class.must_equal Hash
214
+ hash.must_equal pg_jsonb_hash
215
+ end
216
+
217
+ it 'must transform JSONBArray to Array' do
218
+ pg_jsonb_array = Sequel::Postgres::JSONBArray.new json_array
219
+ array = type_converter.from_db pg_jsonb_array
220
+
221
+ array.class.must_equal Array
222
+ array.must_equal pg_jsonb_array
223
+ end
224
+
225
+ end
226
+
227
+ end
228
+
229
+ end
@@ -0,0 +1,33 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Rasti::DB::TypeConverters::TimeInZone do
4
+
5
+ let(:type_converter) { Rasti::DB::TypeConverters::TimeInZone }
6
+
7
+ describe 'To DB' do
8
+
9
+ it 'must not transform Time to TimeInZone' do
10
+ time = Time.now
11
+
12
+ converted_time = type_converter.to_db db, 'table', :time, time
13
+
14
+ converted_time.class.must_equal Time
15
+ converted_time.must_equal time
16
+ end
17
+
18
+ end
19
+
20
+ describe 'From DB' do
21
+
22
+ it 'must transform Time to TimeInZone' do
23
+ time = Time.now
24
+
25
+ converted_time = type_converter.from_db time
26
+
27
+ converted_time.class.must_equal Timing::TimeInZone
28
+ converted_time.must_equal time
29
+ end
30
+
31
+ end
32
+
33
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasti-db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Naiman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-07 00:00:00.000000000 Z
11
+ date: 2019-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -64,6 +64,26 @@ dependencies:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: 0.1.3
67
+ - !ruby/object:Gem::Dependency
68
+ name: class_config
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 0.0.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '0.0'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 0.0.2
67
87
  - !ruby/object:Gem::Dependency
68
88
  name: bundler
69
89
  requirement: !ruby/object:Gem::Requirement
@@ -218,7 +238,12 @@ files:
218
238
  - lib/rasti/db/relations/many_to_one.rb
219
239
  - lib/rasti/db/relations/one_to_many.rb
220
240
  - lib/rasti/db/relations/one_to_one.rb
221
- - lib/rasti/db/type_converter.rb
241
+ - lib/rasti/db/type_converters/postgres.rb
242
+ - lib/rasti/db/type_converters/postgres_types/array.rb
243
+ - lib/rasti/db/type_converters/postgres_types/hstore.rb
244
+ - lib/rasti/db/type_converters/postgres_types/json.rb
245
+ - lib/rasti/db/type_converters/postgres_types/jsonb.rb
246
+ - lib/rasti/db/type_converters/time_in_zone.rb
222
247
  - lib/rasti/db/version.rb
223
248
  - rasti-db.gemspec
224
249
  - spec/collection_spec.rb
@@ -227,7 +252,8 @@ files:
227
252
  - spec/model_spec.rb
228
253
  - spec/query_spec.rb
229
254
  - spec/relations_spec.rb
230
- - spec/type_converter_spec.rb
255
+ - spec/type_converters/postgres_spec.rb
256
+ - spec/type_converters/time_in_zone_spec.rb
231
257
  homepage: https://github.com/gabynaiman/rasti-db
232
258
  licenses:
233
259
  - MIT
@@ -259,4 +285,5 @@ test_files:
259
285
  - spec/model_spec.rb
260
286
  - spec/query_spec.rb
261
287
  - spec/relations_spec.rb
262
- - spec/type_converter_spec.rb
288
+ - spec/type_converters/postgres_spec.rb
289
+ - spec/type_converters/time_in_zone_spec.rb
@@ -1,53 +0,0 @@
1
- module Rasti
2
- module DB
3
- class TypeConverter
4
-
5
- CONVERTIONS = {
6
- postgres: {
7
- /^json$/ => ->(value, match) { Sequel.pg_json value },
8
- /^jsonb$/ => ->(value, match) { Sequel.pg_jsonb value },
9
- /^hstore$/ => ->(value, match) { Sequel.hstore value },
10
- /^hstore\[\]$/ => ->(value, match) { Sequel.pg_array value.map { |v| Sequel.hstore v }, 'hstore' },
11
- /^([a-z]+)\[\]$/ => ->(value, match) { Sequel.pg_array value, match.captures[0] }
12
- }
13
- }
14
-
15
- def initialize(db, collection_name)
16
- @db = db
17
- @collection_name = collection_name
18
- end
19
-
20
- def apply_to(attributes)
21
- convertions = self.class.convertions_for @db, @collection_name
22
-
23
- return attributes if convertions.empty?
24
-
25
- (attributes.is_a?(Array) ? attributes : [attributes]).each do |attrs|
26
- convertions.each do |name, convertion|
27
- attrs[name] = convertion[:block].call attrs[name], convertion[:match] if attrs.key? name
28
- end
29
- end
30
-
31
- attributes
32
- end
33
-
34
- @cache ||= {}
35
-
36
- def self.convertions_for(db, collection_name)
37
- key = [db.database_type, collection_name]
38
- if !@cache.key?(key)
39
- columns = Hash[db.schema(collection_name)]
40
- @cache[key] = columns.each_with_object({}) do |(name, schema), hash|
41
- CONVERTIONS.fetch(db.database_type, {}).each do |type, convertion|
42
- if !hash.key?(name) && match = type.match(schema[:db_type])
43
- hash[name] = {match: match, block: convertion}
44
- end
45
- end
46
- end
47
- end
48
- @cache[key]
49
- end
50
-
51
- end
52
- end
53
- end
@@ -1,106 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- describe 'Type Converter' do
4
-
5
- it 'Apply convertion' do
6
- type_converter = Rasti::DB::TypeConverter.new db, :users
7
- type_converter.apply_to(id: '123', name: 'User 1').must_equal id: 123, name: 'User 1'
8
- end
9
-
10
- describe 'Postgres' do
11
-
12
- let(:pg) do
13
- Object.new.tap do |pg|
14
- def pg.database_type
15
- :postgres
16
- end
17
-
18
- def pg.schema(table_name, opts={})
19
- [
20
- [:hash, {db_type: 'hstore'}],
21
- [:text_array, {db_type: 'text[]'}],
22
- [:integer_array, {db_type: 'integer[]'}],
23
- [:hstore_array, {db_type: 'hstore[]'}],
24
- [:json, {db_type: 'json'}],
25
- [:jsonb, {db_type: 'jsonb'}]
26
- ]
27
- end
28
- end
29
- end
30
-
31
- let(:type_converter) { Rasti::DB::TypeConverter.new pg, :table_name }
32
-
33
- it 'HStore' do
34
- attributes = type_converter.apply_to hash: {key_1: 1, key_2: 2}
35
-
36
- attributes[:hash].class.must_equal Sequel::Postgres::HStore
37
- attributes[:hash].must_equal 'key_1' => '1', 'key_2' => '2'
38
- end
39
-
40
- it 'Empty hstore' do
41
- attributes = type_converter.apply_to hash: {}
42
-
43
- attributes[:hash].class.must_equal Sequel::Postgres::HStore
44
- attributes[:hash].must_equal Hash.new
45
- end
46
-
47
- it 'Text array' do
48
- attributes = type_converter.apply_to text_array: %w(a b c)
49
-
50
- attributes[:text_array].class.must_equal Sequel::Postgres::PGArray
51
- attributes[:text_array].array_type.must_equal 'text'
52
- attributes[:text_array].must_equal %w(a b c)
53
- end
54
-
55
- it 'Integer array' do
56
- attributes = type_converter.apply_to integer_array: [1,2,3]
57
-
58
- attributes[:integer_array].class.must_equal Sequel::Postgres::PGArray
59
- attributes[:integer_array].array_type.must_equal 'integer'
60
- attributes[:integer_array].must_equal [1,2,3]
61
- end
62
-
63
- it 'Hstore array' do
64
- attributes = type_converter.apply_to hstore_array: [{key: 0}, {key: 1}]
65
-
66
- attributes[:hstore_array].class.must_equal Sequel::Postgres::PGArray
67
- attributes[:hstore_array].array_type.must_equal 'hstore'
68
-
69
- 2.times do |i|
70
- attributes[:hstore_array][i].class.must_equal Sequel::Postgres::HStore
71
- attributes[:hstore_array][i].must_equal 'key' => i.to_s
72
- end
73
- end
74
-
75
- it 'Empty array' do
76
- attributes = type_converter.apply_to integer_array: []
77
-
78
- attributes[:integer_array].class.must_equal Sequel::Postgres::PGArray
79
- attributes[:integer_array].array_type.must_equal 'integer'
80
- attributes[:integer_array].must_equal []
81
- end
82
-
83
- it 'Json' do
84
- attributes = type_converter.apply_to json: {key_1: {key_2: [3]}}
85
-
86
- attributes[:json].class.must_equal Sequel::Postgres::JSONHash
87
- attributes[:json].must_equal key_1: {key_2: [3]}
88
- end
89
-
90
- it 'Json array' do
91
- attributes = type_converter.apply_to json: [{key_1: {key_2: [3]}}]
92
-
93
- attributes[:json].class.must_equal Sequel::Postgres::JSONArray
94
- attributes[:json].must_equal [{key_1: {key_2: [3]}}]
95
- end
96
-
97
- it 'Json binary' do
98
- attributes = type_converter.apply_to jsonb: {key_1: {key_2: [3]}}
99
-
100
- attributes[:jsonb].class.must_equal Sequel::Postgres::JSONBHash
101
- attributes[:jsonb].must_equal key_1: {key_2: [3]}
102
- end
103
-
104
- end
105
-
106
- end