rasti-db 0.4.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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