rasti-db 2.3.0 → 4.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
  SHA256:
3
- metadata.gz: 057df50ee7debeb86b2ad63d4dffc965df8941e0f19ac4d4f96fe97ca319c314
4
- data.tar.gz: c0cda671e2ea8f748b59c34108440edc7e016702f4d5832efac995a650005e62
3
+ metadata.gz: 63f41e1bc62674437962478fc753698954559bf6bfcc491ab6bcdb76ea9082aa
4
+ data.tar.gz: e57dad5c6377b82c14a3a0775bc9f2b4abb75570edece928d3679e4c172e571d
5
5
  SHA512:
6
- metadata.gz: d31034d885d8791bb04a2417372d56226c51b4fe8c54279d294148b22c68a7744f12887a948692f12e0b24c1a4abf8868b3c9250948ffb516e2c2515b42ea0aa
7
- data.tar.gz: b75bc69a65eb10032f510ff5cb99cd511b69bc354c6bc3bc836e23612a0a21f9cc0a01849b752d58b1e86c0b9387adcb665ad609198495120a1da0c6fa2418a7
6
+ metadata.gz: acce93a9224b4531de96969886f2d8c384a047f1b58169f344a8eca518eb8328d6d46ff9359d0ebba15dc0ab017785ff5120616678c9651581fc5ea0f1ff646b
7
+ data.tar.gz: 3d85bf6a76c25a55e775c36bdb0dff504e28e945bdb94afd341416e8337f3bd442de20f03f50a87e3290784a4743786d4a4152f6c4cd698b8302d9b9f5e28c4b
data/.travis.yml CHANGED
@@ -8,6 +8,7 @@ rvm:
8
8
  - 2.5
9
9
  - 2.6
10
10
  - 2.7
11
+ - 3.0
11
12
  - jruby-9.2.9.0
12
13
  - ruby-head
13
14
  - jruby-head
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in rasti-db.gemspec
4
- gemspec
4
+ gemspec
data/lib/rasti/db.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'sequel'
2
+ require 'rasti-model'
2
3
  require 'consty'
3
4
  require 'time'
4
5
  require 'timing'
@@ -15,13 +16,13 @@ module Rasti
15
16
  extend MultiRequire
16
17
  extend ClassConfig
17
18
 
18
- require_relative 'db/query'
19
- require_relative_pattern 'db/relations/*'
20
- require_relative_pattern 'db/type_converters/postgres_types/*'
21
- require_relative_pattern 'db/type_converters/sqlite_types/*'
22
- require_relative 'db/nql/nodes/constants/base'
23
- require_relative_pattern 'db/nql/filter_condition_strategies/types/*'
24
- require_relative_pattern 'db/**/*'
19
+ require_relative 'db/query'
20
+ require_relative_pattern 'db/relations/*'
21
+ require_relative_pattern 'db/type_converters/postgres_types/*'
22
+ require_relative_pattern 'db/type_converters/sqlite_types/*'
23
+ require_relative 'db/nql/nodes/constants/base'
24
+ require_relative_pattern 'db/nql/filter_condition_strategies/types/*'
25
+ require_relative_pattern 'db/**/*'
25
26
 
26
27
  attr_config :type_converters, []
27
28
  attr_config :nql_filter_condition_strategy, nil
@@ -14,7 +14,7 @@ module Rasti
14
14
  end
15
15
 
16
16
  def collection_attributes
17
- @collection_attributes ||= model.attributes - relations.keys - computed_attributes.keys
17
+ @collection_attributes ||= model.attribute_names - relations.keys - computed_attributes.keys
18
18
  end
19
19
 
20
20
  def primary_key
@@ -89,7 +89,7 @@ module Rasti
89
89
  raise "Query #{name} already exists" if queries.key? name
90
90
 
91
91
  queries[name] = lambda || block
92
-
92
+
93
93
  define_method name do |*args|
94
94
  default_query.instance_exec(*args, &self.class.queries.fetch(name))
95
95
  end
@@ -210,21 +210,21 @@ module Rasti
210
210
  def qualified_collection_name
211
211
  data_source.qualify self.class.collection_name
212
212
  end
213
-
213
+
214
214
  def qualify(collection_name, data_source_name: nil)
215
215
  data_source_name ||= self.class.data_source_name
216
216
  environment.qualify data_source_name, collection_name
217
217
  end
218
218
 
219
219
  def default_query
220
- Query.new collection_class: self.class,
221
- dataset: dataset.select_all(self.class.collection_name),
220
+ Query.new collection_class: self.class,
221
+ dataset: dataset.select_all(self.class.collection_name),
222
222
  environment: environment
223
223
  end
224
224
 
225
225
  def build_query(filter=nil, &block)
226
226
  raise ArgumentError, 'must specify filter hash or block' if filter.nil? && block.nil?
227
-
227
+
228
228
  if filter
229
229
  default_query.where(filter)
230
230
  else
@@ -233,7 +233,7 @@ module Rasti
233
233
  end
234
234
 
235
235
  def transform_attributes_to_db(attributes)
236
- attributes.each_with_object({}) do |(attribute_name, value), result|
236
+ attributes.each_with_object({}) do |(attribute_name, value), result|
237
237
  transformed_value = Rasti::DB.to_db data_source.db, qualified_collection_name, attribute_name, value
238
238
  result[attribute_name] = transformed_value
239
239
  end
@@ -247,7 +247,7 @@ module Rasti
247
247
 
248
248
  [collection_attributes, relations_ids]
249
249
  end
250
-
250
+
251
251
  def save_relations(primary_key, relations_primary_keys)
252
252
  relations_primary_keys.each do |relation_name, relation_primary_keys|
253
253
  relation = self.class.relations[relation_name]
@@ -281,9 +281,9 @@ module Rasti
281
281
  relation_data_source = environment.data_source relation.relation_data_source_name
282
282
  relation_collection_name = relation_data_source.qualify relation.relation_collection_name
283
283
 
284
- values = relation_primary_keys.map do |relation_pk|
284
+ values = relation_primary_keys.map do |relation_pk|
285
285
  {
286
- relation.source_foreign_key => primary_key,
286
+ relation.source_foreign_key => primary_key,
287
287
  relation.target_foreign_key => relation_pk
288
288
  }
289
289
  end
@@ -12,7 +12,7 @@ module Rasti
12
12
  def qualify(collection_name)
13
13
  schema ? Sequel[schema][collection_name] : Sequel[collection_name]
14
14
  end
15
-
15
+
16
16
  end
17
17
  end
18
18
  end
@@ -1,112 +1,11 @@
1
1
  module Rasti
2
2
  module DB
3
- class Model
3
+ class Model < Rasti::Model
4
4
 
5
- class UninitializedAttributeError < StandardError
6
-
7
- attr_reader :attribute
8
-
9
- def initialize(attribute)
10
- @attribute = attribute
11
- super "Uninitialized attribute #{attribute}"
12
- end
13
-
14
- end
15
-
16
-
17
- class << self
18
-
19
- def [](*attribute_names)
20
- Class.new(self) do
21
- attribute(*attribute_names)
22
-
23
- def self.inherited(subclass)
24
- subclass.instance_variable_set :@attributes, attributes.dup
25
- end
26
- end
27
- end
28
-
29
- def attributes
30
- @attributes ||= []
31
- end
32
-
33
- def model_name
34
- name || self.superclass.name
35
- end
36
-
37
- def to_s
38
- "#{model_name}[#{attributes.join(', ')}]"
39
- end
40
- alias_method :inspect, :to_s
41
-
42
- private
43
-
44
- def attribute(*names)
45
- names.each do |name|
46
- raise ArgumentError, "Attribute #{name} already exists" if attributes.include?(name)
47
-
48
- attributes << name
49
-
50
- define_method name do
51
- fetch_attribute name
52
- end
53
- end
54
- end
55
-
56
- end
57
-
58
-
59
- def initialize(attributes)
60
- invalid_attributes = attributes.keys - self.class.attributes
61
- raise "#{self.class.model_name} invalid attributes: #{invalid_attributes.join(', ')}" unless invalid_attributes.empty?
62
- @attributes = attributes
63
- end
64
-
65
- def merge(new_attributes)
66
- self.class.new attributes.merge(new_attributes)
67
- end
68
-
69
- def eql?(other)
70
- instance_of?(other.class) && to_h.eql?(other.to_h)
71
- end
72
-
73
- def ==(other)
74
- other.kind_of?(self.class) && to_h == other.to_h
75
- end
76
-
77
- def hash
78
- attributes.map(&:hash).hash
79
- end
80
-
81
- def to_s
82
- "#<#{self.class.model_name}[#{attributes.map { |n,v| "#{n}: #{v.inspect}" }.join(', ')}]>"
83
- end
84
- alias_method :inspect, :to_s
85
-
86
- def to_h
87
- self.class.attributes.each_with_object({}) do |name, hash|
88
- if attributes.key? name
89
- value = fetch_attribute name
90
- case value
91
- when Model
92
- hash[name] = value.to_h
93
- when Array
94
- hash[name] = value.map do |e|
95
- e.is_a?(Model) ? e.to_h : e
96
- end
97
- else
98
- hash[name] = value
99
- end
100
- end
101
- end
102
- end
103
-
104
5
  private
105
6
 
106
- attr_reader :attributes
107
-
108
- def fetch_attribute(name)
109
- attributes.key?(name) ? Rasti::DB.from_db(attributes[name]) : raise(UninitializedAttributeError, name)
7
+ def cast_attribute(type, value)
8
+ super type, Rasti::DB.from_db(value)
110
9
  end
111
10
 
112
11
  end
@@ -3,7 +3,7 @@ module Rasti
3
3
  module NQL
4
4
  module Nodes
5
5
  class BinaryNode < Treetop::Runtime::SyntaxNode
6
-
6
+
7
7
  def dependency_tables
8
8
  values.flat_map(&:dependency_tables)
9
9
  end
@@ -3,7 +3,7 @@ module Rasti
3
3
  module NQL
4
4
  module Nodes
5
5
  class ParenthesisSentence < Treetop::Runtime::SyntaxNode
6
-
6
+
7
7
  def dependency_tables
8
8
  sentence.dependency_tables
9
9
  end
@@ -2,7 +2,7 @@ module Rasti
2
2
  module DB
3
3
  module Relations
4
4
  class Base
5
-
5
+
6
6
  include Sequel::Inflections
7
7
 
8
8
  attr_reader :name, :source_collection_class
@@ -63,10 +63,10 @@ module Rasti
63
63
 
64
64
  def validate_join!
65
65
  if source_collection_class.data_source_name != target_collection_class.data_source_name
66
- raise "Invalid join of multiple data sources: #{source_collection_class.data_source_name}.#{source_collection_class.collection_name} > #{target_collection_class.data_source_name}.#{target_collection_class.collection_name}"
66
+ raise "Invalid join of multiple data sources: #{source_collection_class.data_source_name}.#{source_collection_class.collection_name} > #{target_collection_class.data_source_name}.#{target_collection_class.collection_name}"
67
67
  end
68
68
  end
69
-
69
+
70
70
  end
71
71
  end
72
72
  end
@@ -6,15 +6,15 @@ module Rasti
6
6
  def initialize(environment, collection_class, relations=[], selected_attributes={}, excluded_attributes={})
7
7
  @environment = environment
8
8
  @collection_class = collection_class
9
- @graph = build_graph relations,
10
- Hash::Indifferent.new(selected_attributes),
9
+ @graph = build_graph relations,
10
+ Hash::Indifferent.new(selected_attributes),
11
11
  Hash::Indifferent.new(excluded_attributes)
12
12
  end
13
13
 
14
14
  def merge(relations:[], selected_attributes:{}, excluded_attributes:{})
15
- Graph.new environment,
16
- collection_class,
17
- (flat_relations | relations),
15
+ Graph.new environment,
16
+ collection_class,
17
+ (flat_relations | relations),
18
18
  flat_selected_attributes.merge(selected_attributes),
19
19
  flat_excluded_attributes.merge(excluded_attributes)
20
20
  end
@@ -22,7 +22,7 @@ module Rasti
22
22
  def with_all_attributes_for(relations)
23
23
  relations_with_all_attributes = relations.map { |r| [r, nil] }.to_h
24
24
 
25
- merge selected_attributes: relations_with_all_attributes,
25
+ merge selected_attributes: relations_with_all_attributes,
26
26
  excluded_attributes: relations_with_all_attributes
27
27
  end
28
28
 
@@ -37,7 +37,7 @@ module Rasti
37
37
 
38
38
  graph.roots.each do |node|
39
39
  relation_of(node).fetch_graph environment,
40
- rows,
40
+ rows,
41
41
  node[:selected_attributes],
42
42
  node[:excluded_attributes] ,
43
43
  subgraph_of(node)
@@ -88,25 +88,25 @@ module Rasti
88
88
  excluded[id] = descendant[:excluded_attributes]
89
89
  end
90
90
 
91
- Graph.new environment,
92
- relation_of(node).target_collection_class,
93
- relations,
94
- selected,
91
+ Graph.new environment,
92
+ relation_of(node).target_collection_class,
93
+ relations,
94
+ selected,
95
95
  excluded
96
96
  end
97
97
 
98
98
  def build_graph(relations, selected_attributes, excluded_attributes)
99
99
  HierarchicalGraph.new.tap do |graph|
100
- flatten(relations).each do |relation|
100
+ flatten(relations).each do |relation|
101
101
  sections = relation.split('.')
102
-
102
+
103
103
  graph.add_node relation, name: sections.last.to_sym,
104
104
  selected_attributes: selected_attributes[relation],
105
105
  excluded_attributes: excluded_attributes[relation]
106
-
106
+
107
107
  if sections.count > 1
108
108
  parent_id = sections[0..-2].join('.')
109
- graph.add_relation parent_id: parent_id,
109
+ graph.add_relation parent_id: parent_id,
110
110
  child_id: relation
111
111
  end
112
112
  end
@@ -54,19 +54,19 @@ module Rasti
54
54
 
55
55
  relations_graph.fetch_graph join_rows if relations_graph
56
56
 
57
- relation_rows = join_rows.each_with_object(Hash.new { |h,k| h[k] = [] }) do |row, hash|
58
- attributes = row.select { |attr,_| target_collection_class.model.attributes.include? attr }
57
+ relation_rows = join_rows.each_with_object(Hash.new { |h,k| h[k] = [] }) do |row, hash|
58
+ attributes = row.select { |attr,_| target_collection_class.model.attribute_names.include? attr }
59
59
  hash[row[:source_foreign_key]] << target_collection_class.model.new(attributes)
60
60
  end
61
61
 
62
- rows.each do |row|
62
+ rows.each do |row|
63
63
  row[name] = relation_rows.fetch row[source_collection_class.primary_key], []
64
64
  end
65
65
  end
66
66
 
67
67
  def add_join(environment, dataset, prefix=nil)
68
68
  validate_join!
69
-
69
+
70
70
  many_to_many_relation_alias = with_prefix prefix, "#{relation_collection_name}_#{SecureRandom.base64}"
71
71
 
72
72
  relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
@@ -17,18 +17,18 @@ module Rasti
17
17
  query = query.select_attributes(*selected_attributes) if selected_attributes
18
18
  query = relations_graph.apply_to query if relations_graph
19
19
 
20
- relation_rows = query.each_with_object({}) do |row, hash|
20
+ relation_rows = query.each_with_object({}) do |row, hash|
21
21
  hash[row.public_send(source_collection_class.primary_key)] = row
22
22
  end
23
-
24
- rows.each do |row|
23
+
24
+ rows.each do |row|
25
25
  row[name] = relation_rows[row[foreign_key]]
26
26
  end
27
27
  end
28
28
 
29
29
  def add_join(environment, dataset, prefix=nil)
30
30
  validate_join!
31
-
31
+
32
32
  relation_alias = join_relation_name prefix
33
33
 
34
34
  relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
@@ -19,14 +19,14 @@ module Rasti
19
19
 
20
20
  relation_rows = query.group_by(&foreign_key)
21
21
 
22
- rows.each do |row|
22
+ rows.each do |row|
23
23
  row[name] = build_graph_result relation_rows.fetch(row[source_collection_class.primary_key], [])
24
24
  end
25
25
  end
26
26
 
27
27
  def add_join(environment, dataset, prefix=nil)
28
28
  validate_join!
29
-
29
+
30
30
  relation_alias = join_relation_name prefix
31
31
 
32
32
  relation_name = prefix ? Sequel[prefix] : Sequel[source_collection_class.collection_name]
@@ -3,62 +3,58 @@ module Rasti
3
3
  module TypeConverters
4
4
  class Postgres
5
5
 
6
- CONVERTERS = [PostgresTypes::JSON, PostgresTypes::JSONB, PostgresTypes::HStore, PostgresTypes::Array]
7
-
8
- @to_db_mapping = {}
6
+ CONVERTERS = [
7
+ PostgresTypes::JSON,
8
+ PostgresTypes::JSONB,
9
+ PostgresTypes::HStore,
10
+ PostgresTypes::Array
11
+ ]
9
12
 
10
13
  class << self
11
14
 
12
15
  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
16
+ converter, type = find_to_db_converter_and_type db, collection_name, attribute_name
17
+ converter ? converter.to_db(value, type) : value
20
18
  end
21
19
 
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
20
+ def from_db(value)
21
+ converter = find_from_db_converter value.class
22
+ converter ? converter.from_db(value) : value
28
23
  end
29
24
 
30
25
  private
31
26
 
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)]
27
+ def from_db_converters
28
+ @from_db_converters ||= {}
29
+ end
37
30
 
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]
31
+ def to_db_converters
32
+ @to_db_converters ||= {}
33
+ end
34
+
35
+ def find_to_db_converter_and_type(db, collection_name, attribute_name)
36
+ key = [db.opts[:database], collection_name]
42
37
 
43
- hash[name] = {converter: converter, sub_type: match.captures.first} if match
44
- end
45
- end
38
+ to_db_converters[key] ||= begin
39
+ columns = Hash[db.schema(collection_name)]
40
+ to_db_converters[key] = columns.each_with_object({}) do |(name, schema), hash|
41
+ converter = CONVERTERS.detect { |c| c.to_db? schema[:db_type] }
42
+ hash[name] = [converter, schema[:db_type]] if converter
46
43
  end
47
44
  end
45
+
46
+ to_db_converters[key].fetch(attribute_name, [])
48
47
  end
49
48
 
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
49
+ def find_from_db_converter(klass)
50
+ if !from_db_converters.key?(klass)
51
+ from_db_converters[klass] = CONVERTERS.detect { |c| c.from_db? klass }
57
52
  end
53
+
54
+ from_db_converters[klass]
58
55
  end
59
56
 
60
57
  end
61
-
62
58
  end
63
59
  end
64
60
  end
@@ -3,28 +3,30 @@ module Rasti
3
3
  module TypeConverters
4
4
  module PostgresTypes
5
5
  class Array
6
-
7
6
  class << self
8
7
 
9
- def column_type_regex
10
- /^([a-z]+)\[\]$/
8
+ DB_TYPE_REGEX = /^([a-z]+)\[\]$/
9
+
10
+ def to_db?(type)
11
+ !type.match(DB_TYPE_REGEX).nil?
11
12
  end
12
13
 
13
- def to_db(value, sub_type)
14
+ def to_db(value, type)
15
+ sub_type = type[0..-3]
14
16
  array = sub_type == 'hstore' ? value.map { |v| Sequel.hstore v } : value
15
17
  Sequel.pg_array array, sub_type
16
18
  end
17
19
 
18
- def db_classes
19
- [Sequel::Postgres::PGArray]
20
+ def from_db?(klass)
21
+ defined?(Sequel::Postgres::PGArray) &&
22
+ klass == Sequel::Postgres::PGArray
20
23
  end
21
24
 
22
- def from_db(object)
23
- object.to_a
25
+ def from_db(value)
26
+ value.to_a
24
27
  end
25
28
 
26
29
  end
27
-
28
30
  end
29
31
  end
30
32
  end
@@ -3,27 +3,28 @@ module Rasti
3
3
  module TypeConverters
4
4
  module PostgresTypes
5
5
  class HStore
6
-
7
6
  class << self
8
7
 
9
- def column_type_regex
10
- /^hstore$/
8
+ DB_TYPE_REGEX = /^hstore$/
9
+
10
+ def to_db?(type)
11
+ !type.match(DB_TYPE_REGEX).nil?
11
12
  end
12
13
 
13
- def to_db(value, sub_type)
14
+ def to_db(value, type)
14
15
  Sequel.hstore value
15
16
  end
16
17
 
17
- def db_classes
18
- [Sequel::Postgres::HStore]
18
+ def from_db?(klass)
19
+ defined?(Sequel::Postgres::HStore) &&
20
+ klass == Sequel::Postgres::HStore
19
21
  end
20
22
 
21
- def from_db(object)
22
- object.to_h
23
+ def from_db(value)
24
+ value.to_h
23
25
  end
24
26
 
25
27
  end
26
-
27
28
  end
28
29
  end
29
30
  end
@@ -3,36 +3,39 @@ module Rasti
3
3
  module TypeConverters
4
4
  module PostgresTypes
5
5
  class JSON
6
-
7
6
  class << self
8
7
 
9
- def column_type_regex
10
- /^json$/
8
+ DB_TYPE_REGEX = /^json$/
9
+
10
+ def to_db?(type)
11
+ !type.match(DB_TYPE_REGEX).nil?
11
12
  end
12
13
 
13
- def to_db(value, sub_type)
14
+ def to_db(value, type)
14
15
  Sequel.pg_json value
15
16
  end
16
17
 
17
- def db_classes
18
- @db_classes ||= from_db_convertions.keys
18
+ def from_db?(klass)
19
+ to_hash?(klass) || to_array?(klass)
19
20
  end
20
21
 
21
- def from_db(object)
22
- object.public_send from_db_convertions[object.class]
22
+ def from_db(value)
23
+ to_hash?(value.class) ? value.to_h : value.to_a
23
24
  end
24
25
 
25
26
  private
26
27
 
27
- def from_db_convertions
28
- @from_db_convertions ||= {
29
- Sequel::Postgres::JSONHash => :to_h,
30
- Sequel::Postgres::JSONArray => :to_a
31
- }
28
+ def to_hash?(klass)
29
+ defined?(Sequel::Postgres::JSONHash) &&
30
+ klass == Sequel::Postgres::JSONHash
32
31
  end
33
32
 
34
- end
33
+ def to_array?(klass)
34
+ defined?(Sequel::Postgres::JSONArray) &&
35
+ klass == Sequel::Postgres::JSONArray
36
+ end
35
37
 
38
+ end
36
39
  end
37
40
  end
38
41
  end
@@ -3,36 +3,39 @@ module Rasti
3
3
  module TypeConverters
4
4
  module PostgresTypes
5
5
  class JSONB
6
-
7
6
  class << self
8
7
 
9
- def column_type_regex
10
- /^jsonb$/
8
+ DB_TYPE_REGEX = /^jsonb$/
9
+
10
+ def to_db?(type)
11
+ !type.match(DB_TYPE_REGEX).nil?
11
12
  end
12
13
 
13
- def to_db(value, sub_type)
14
+ def to_db(value, type)
14
15
  Sequel.pg_jsonb value
15
16
  end
16
17
 
17
- def db_classes
18
- @db_classes ||= from_db_convertions.keys
18
+ def from_db?(klass)
19
+ to_hash?(klass) || to_array?(klass)
19
20
  end
20
21
 
21
- def from_db(object)
22
- object.public_send from_db_convertions[object.class]
22
+ def from_db(value)
23
+ to_hash?(value.class) ? value.to_h : value.to_a
23
24
  end
24
25
 
25
26
  private
26
27
 
27
- def from_db_convertions
28
- @from_db_convertions ||= {
29
- Sequel::Postgres::JSONBHash => :to_h,
30
- Sequel::Postgres::JSONBArray => :to_a
31
- }
28
+ def to_hash?(klass)
29
+ defined?(Sequel::Postgres::JSONBHash) &&
30
+ klass == Sequel::Postgres::JSONBHash
32
31
  end
33
32
 
34
- end
33
+ def to_array?(klass)
34
+ defined?(Sequel::Postgres::JSONBArray) &&
35
+ klass == Sequel::Postgres::JSONBArray
36
+ end
35
37
 
38
+ end
36
39
  end
37
40
  end
38
41
  end
@@ -6,7 +6,7 @@ module Rasti
6
6
  class << self
7
7
 
8
8
  def to_db(db, collection_name, attribute_name, value)
9
- value
9
+ value.is_a?(Timing::TimeInZone) ? value.to_time : value
10
10
  end
11
11
 
12
12
  def from_db(value)
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module DB
3
- VERSION = '2.3.0'
3
+ VERSION = '4.0.0'
4
4
  end
5
5
  end
data/rasti-db.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_runtime_dependency 'sequel', '~> 5.0'
22
+ spec.add_runtime_dependency 'rasti-model', '~> 2.0'
22
23
  spec.add_runtime_dependency 'treetop', '~> 1.4.8'
23
24
  spec.add_runtime_dependency 'consty', '~> 1.0', '>= 1.0.3'
24
25
  spec.add_runtime_dependency 'timing', '~> 0.1', '>= 0.1.3'
@@ -52,7 +52,7 @@ describe 'Collection' do
52
52
  it 'Insert with many to many' do
53
53
  user_id = db[:users].insert name: 'User 1'
54
54
 
55
- 1.upto(2) do |i|
55
+ 1.upto(2) do |i|
56
56
  db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1
57
57
  db[:categories].insert name: "Category #{i}"
58
58
  end
@@ -65,7 +65,7 @@ describe 'Collection' do
65
65
  end
66
66
 
67
67
  it 'Insert only many to many' do
68
- 1.upto(3) do |i|
68
+ 1.upto(3) do |i|
69
69
  db[:categories].insert name: "Category #{i}"
70
70
  end
71
71
 
@@ -101,7 +101,7 @@ describe 'Collection' do
101
101
  it 'Update with many to many' do
102
102
  user_id = db[:users].insert name: 'User 1'
103
103
 
104
- 1.upto(3) do |i|
104
+ 1.upto(3) do |i|
105
105
  db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1
106
106
  db[:categories].insert name: "Category #{i}"
107
107
  end
@@ -115,11 +115,11 @@ describe 'Collection' do
115
115
  posts.update 1, categories: [2,3]
116
116
 
117
117
  db[:categories_posts].where(post_id: 1).map(:category_id).must_equal [2,3]
118
-
118
+
119
119
  db[:categories_posts].where(category_id: 2).map(:post_id).must_equal [1,2]
120
120
 
121
121
  categories.update 2, posts: [2,3]
122
-
122
+
123
123
  db[:categories_posts].where(category_id: 2).map(:post_id).must_equal [2,3]
124
124
  end
125
125
 
@@ -145,7 +145,7 @@ describe 'Collection' do
145
145
  end
146
146
 
147
147
  it 'Delete only many to many' do
148
- 1.upto(3) do |i|
148
+ 1.upto(3) do |i|
149
149
  db[:categories].insert name: "Category #{i}"
150
150
  end
151
151
 
@@ -172,14 +172,14 @@ describe 'Collection' do
172
172
  1.upto(3) do |i|
173
173
  user_id = db[:users].insert name: "User #{i}"
174
174
 
175
- db[:people].insert document_number: "document_#{i}",
175
+ db[:people].insert document_number: "document_#{i}",
176
176
  first_name: "John #{i}",
177
177
  last_name: "Doe #{i}",
178
178
  birth_date: Time.now - i,
179
179
  user_id: user_id
180
180
 
181
- category_id = db[:categories].insert name: "Category #{i}"
182
-
181
+ category_id = db[:categories].insert name: "Category #{i}"
182
+
183
183
  1.upto(3) do |n|
184
184
  post_id = db[:posts].insert user_id: user_id, title: "Post #{i}.#{n}", body: '...', language_id: 1
185
185
  db[:categories_posts].insert post_id: post_id, category_id: category_id
@@ -227,7 +227,7 @@ describe 'Collection' do
227
227
  db[:posts].where(user_id: 1).count.must_equal 0
228
228
  db[:comments].join(:posts, id: :post_id).where(Sequel[:posts][:user_id] => 1).count.must_equal 0
229
229
  db[:categories_posts].join(:posts, id: :post_id).where(Sequel[:posts][:user_id] => 1).count.must_equal 0
230
-
230
+
231
231
  db[:users].count.must_equal 2
232
232
  db[:people].count.must_equal 2
233
233
  db[:categories].count.must_equal 3
@@ -241,9 +241,9 @@ describe 'Collection' do
241
241
  describe 'Multiple data sources' do
242
242
 
243
243
  before do
244
- 1.upto(3) do |i|
244
+ 1.upto(3) do |i|
245
245
  db[:users].insert name: "User #{i}"
246
- db[:people].insert document_number: "document_#{i}",
246
+ db[:people].insert document_number: "document_#{i}",
247
247
  first_name: "John #{i}",
248
248
  last_name: "Doe #{i}",
249
249
  birth_date: Time.now - i,
@@ -303,7 +303,7 @@ describe 'Collection' do
303
303
 
304
304
  it 'Find' do
305
305
  id = db[:users].insert name: 'User 1'
306
-
306
+
307
307
  users.find(id).must_equal User.new(id: id, name: 'User 1')
308
308
  end
309
309
 
@@ -410,26 +410,26 @@ describe 'Collection' do
410
410
 
411
411
  1.upto(2) do |i|
412
412
  db[:categories].insert name: "Category #{i}"
413
-
413
+
414
414
  db[:users].insert name: "User #{i}"
415
-
416
- db[:people].insert document_number: "document_#{i}",
415
+
416
+ db[:people].insert document_number: "document_#{i}",
417
417
  first_name: "John #{i}",
418
418
  last_name: "Doe #{i}",
419
419
  birth_date: Time.now - i,
420
420
  user_id: i
421
-
421
+
422
422
  end
423
423
 
424
424
  db[:languages_people].insert language_id: 1, document_number: 'document_1'
425
425
  db[:languages_people].insert language_id: 2, document_number: 'document_2'
426
426
 
427
- 1.upto(3) do |i|
427
+ 1.upto(3) do |i|
428
428
  db[:posts].insert user_id: 1, title: "Post #{i}", body: '...', language_id: 1
429
429
  db[:categories_posts].insert category_id: 1, post_id: i
430
430
  end
431
-
432
- 4.upto(5) do |i|
431
+
432
+ 4.upto(5) do |i|
433
433
  db[:posts].insert user_id: 2, title: "Post #{i}", body: '...', language_id: 2
434
434
  db[:categories_posts].insert category_id: 2, post_id: i
435
435
  end
@@ -475,7 +475,7 @@ describe 'Collection' do
475
475
  it 'Global' do
476
476
  result_1 = posts.created_by(1)
477
477
  result_1.primary_keys.must_equal [1,2,3]
478
-
478
+
479
479
  result_2 = posts.created_by(2)
480
480
  result_2.primary_keys.must_equal [4,5]
481
481
  end
@@ -490,7 +490,7 @@ describe 'Collection' do
490
490
  it 'Graph' do
491
491
  1.upto(3) do |i|
492
492
  db[:users].insert name: "User #{i}"
493
- db[:people].insert document_number: "document_#{i}",
493
+ db[:people].insert document_number: "document_#{i}",
494
494
  first_name: "John #{i}",
495
495
  last_name: "Doe #{i}",
496
496
  birth_date: Time.now - i,
@@ -521,10 +521,10 @@ describe 'Collection' do
521
521
 
522
522
  comment.post_id.must_equal 1
523
523
  comment.user_id.must_equal i
524
-
524
+
525
525
  comment.user.id.must_equal i
526
526
  comment.user.name.must_equal "User #{i}"
527
-
527
+
528
528
  comment.user.posts.count.must_equal 1
529
529
  comment.user.posts[0].id.must_equal i
530
530
  comment.user.posts[0].title.must_equal "Post #{i}"
@@ -544,7 +544,7 @@ describe 'Collection' do
544
544
  stubs = Proc.new do |sql|
545
545
  case sql
546
546
 
547
- when 'SELECT users.* FROM schema_1.users',
547
+ when 'SELECT users.* FROM schema_1.users',
548
548
  'SELECT users.* FROM schema_1.users WHERE (users.id IN (2, 1))'
549
549
  [
550
550
  {id: 1},
@@ -588,7 +588,7 @@ describe 'Collection' do
588
588
  Sequel.mock fetch: stubs, autoid: autoid
589
589
  end
590
590
 
591
- let :stub_environment do
591
+ let :stub_environment do
592
592
  Rasti::DB::Environment.new default: Rasti::DB::DataSource.new(stub_db, :schema_1),
593
593
  custom: Rasti::DB::DataSource.new(stub_db, :schema_2)
594
594
  end
@@ -627,7 +627,7 @@ describe 'Collection' do
627
627
 
628
628
  stub_users.insert name: 'User 1'
629
629
 
630
- stub_people.insert document_number: 'document_1',
630
+ stub_people.insert document_number: 'document_1',
631
631
  first_name: 'John',
632
632
  last_name: 'Doe',
633
633
  birth_date: Time.parse('2020-04-24'),
@@ -680,7 +680,7 @@ describe 'Collection' do
680
680
 
681
681
  stub_db.sqls.must_equal [
682
682
  'SELECT posts.* FROM schema_1.posts',
683
- 'SELECT categories.*, categories_posts.post_id AS source_foreign_key FROM schema_1.categories INNER JOIN schema_1.categories_posts ON (schema_1.categories_posts.category_id = schema_1.categories.id) WHERE (categories_posts.post_id IN (3, 4))',
683
+ 'SELECT categories.*, categories_posts.post_id AS source_foreign_key FROM schema_1.categories INNER JOIN schema_1.categories_posts ON (schema_1.categories_posts.category_id = schema_1.categories.id) WHERE (categories_posts.post_id IN (3, 4))',
684
684
  'SELECT comments.* FROM schema_1.comments WHERE (comments.post_id IN (3, 4))',
685
685
  'SELECT users.* FROM schema_1.users WHERE (users.id IN (2, 1))',
686
686
  'SELECT posts.* FROM schema_1.posts WHERE (posts.user_id IN (1, 2))',
@@ -8,15 +8,15 @@ describe 'Relations' do
8
8
 
9
9
  it 'Implicit' do
10
10
  relation = Rasti::DB::Relations::OneToMany.new :posts, Users
11
-
11
+
12
12
  relation.target_collection_class.must_equal Posts
13
13
  relation.foreign_key.must_equal :user_id
14
14
  end
15
15
 
16
16
  it 'Explicit' do
17
- relation = Rasti::DB::Relations::OneToMany.new :articles, Users, collection: 'Posts',
17
+ relation = Rasti::DB::Relations::OneToMany.new :articles, Users, collection: 'Posts',
18
18
  foreign_key: :id_user
19
-
19
+
20
20
  relation.target_collection_class.must_equal Posts
21
21
  relation.foreign_key.must_equal :id_user
22
22
  end
@@ -41,9 +41,9 @@ describe 'Relations' do
41
41
  user_id = db[:users].insert name: 'User 1'
42
42
  1.upto(2) { |i| db[:posts].insert user_id: user_id, title: "Post #{i}", body: '...', language_id: 1 }
43
43
  rows = db[:users].all
44
-
44
+
45
45
  Users.relations[:posts].fetch_graph environment, rows
46
-
46
+
47
47
  rows[0][:posts].must_equal posts.where(user_id: user_id).all
48
48
  end
49
49
 
@@ -55,15 +55,15 @@ describe 'Relations' do
55
55
 
56
56
  it 'Implicit' do
57
57
  relation = Rasti::DB::Relations::ManyToOne.new :user, Posts
58
-
58
+
59
59
  relation.target_collection_class.must_equal Users
60
60
  relation.foreign_key.must_equal :user_id
61
61
  end
62
62
 
63
63
  it 'Explicit' do
64
- relation = Rasti::DB::Relations::ManyToOne.new :publisher, Posts, collection: 'Users',
64
+ relation = Rasti::DB::Relations::ManyToOne.new :publisher, Posts, collection: 'Users',
65
65
  foreign_key: :publisher_id
66
-
66
+
67
67
  relation.target_collection_class.must_equal Users
68
68
  relation.foreign_key.must_equal :publisher_id
69
69
  end
@@ -102,7 +102,7 @@ describe 'Relations' do
102
102
 
103
103
  it 'Implicit' do
104
104
  relation = Rasti::DB::Relations::ManyToMany.new :categories, Posts
105
-
105
+
106
106
  relation.target_collection_class.must_equal Categories
107
107
  relation.source_foreign_key.must_equal :post_id
108
108
  relation.target_foreign_key.must_equal :category_id
@@ -110,11 +110,11 @@ describe 'Relations' do
110
110
  end
111
111
 
112
112
  it 'Explicit' do
113
- relation = Rasti::DB::Relations::ManyToMany.new :tags, Posts, collection: 'Categories',
114
- source_foreign_key: :article_id,
115
- target_foreign_key: :tag_id,
113
+ relation = Rasti::DB::Relations::ManyToMany.new :tags, Posts, collection: 'Categories',
114
+ source_foreign_key: :article_id,
115
+ target_foreign_key: :tag_id,
116
116
  relation_collection_name: :tags_articles
117
-
117
+
118
118
  relation.target_collection_class.must_equal Categories
119
119
  relation.source_foreign_key.must_equal :article_id
120
120
  relation.target_foreign_key.must_equal :tag_id
@@ -165,15 +165,15 @@ describe 'Relations' do
165
165
 
166
166
  it 'Implicit' do
167
167
  relation = Rasti::DB::Relations::OneToOne.new :person, Users
168
-
168
+
169
169
  relation.target_collection_class.must_equal People
170
170
  relation.foreign_key.must_equal :user_id
171
171
  end
172
172
 
173
173
  it 'Explicit' do
174
- relation = Rasti::DB::Relations::OneToOne.new :person, Users, collection: 'Users',
174
+ relation = Rasti::DB::Relations::OneToOne.new :person, Users, collection: 'Users',
175
175
  foreign_key: :id_user
176
-
176
+
177
177
  relation.target_collection_class.must_equal Users
178
178
  relation.foreign_key.must_equal :id_user
179
179
  end
@@ -197,7 +197,7 @@ describe 'Relations' do
197
197
  it 'Graph' do
198
198
  2.times do |i|
199
199
  user_id = db[:users].insert name: "User #{i}"
200
- db[:people].insert document_number: "document_#{i}",
200
+ db[:people].insert document_number: "document_#{i}",
201
201
  first_name: "John #{i}",
202
202
  last_name: "Doe #{i}",
203
203
  birth_date: Time.now - i,
@@ -7,7 +7,7 @@ describe Rasti::DB::TypeConverters::TimeInZone do
7
7
  describe 'To DB' do
8
8
 
9
9
  it 'must not transform Time to TimeInZone' do
10
- time = Time.now
10
+ time = Timing::TimeInZone.now
11
11
 
12
12
  converted_time = type_converter.to_db db, 'table', :time, time
13
13
 
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: 2.3.0
4
+ version: 4.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: 2020-12-23 00:00:00.000000000 Z
11
+ date: 2021-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rasti-model
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: treetop
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -352,7 +366,6 @@ files:
352
366
  - spec/computed_attribute_spec.rb
353
367
  - spec/coverage_helper.rb
354
368
  - spec/minitest_helper.rb
355
- - spec/model_spec.rb
356
369
  - spec/nql/computed_attributes_spec.rb
357
370
  - spec/nql/dependency_tables_spec.rb
358
371
  - spec/nql/filter_condition_spec.rb
@@ -382,7 +395,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
382
395
  - !ruby/object:Gem::Version
383
396
  version: '0'
384
397
  requirements: []
385
- rubygems_version: 3.0.1
398
+ rubygems_version: 3.0.9
386
399
  signing_key:
387
400
  specification_version: 4
388
401
  summary: Database collections and relations
@@ -391,7 +404,6 @@ test_files:
391
404
  - spec/computed_attribute_spec.rb
392
405
  - spec/coverage_helper.rb
393
406
  - spec/minitest_helper.rb
394
- - spec/model_spec.rb
395
407
  - spec/nql/computed_attributes_spec.rb
396
408
  - spec/nql/dependency_tables_spec.rb
397
409
  - spec/nql/filter_condition_spec.rb
data/spec/model_spec.rb DELETED
@@ -1,90 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- describe 'Model' do
4
-
5
- describe 'Attribues' do
6
-
7
- it 'Valid definition' do
8
- model = Rasti::DB::Model[:id, :name]
9
- model.attributes.must_equal [:id, :name]
10
- end
11
-
12
- it 'Invalid definition' do
13
- error = proc { Rasti::DB::Model[:id, :name, :name] }.must_raise ArgumentError
14
- error.message.must_equal 'Attribute name already exists'
15
- end
16
-
17
- it 'Accessors' do
18
- post = Post.new id: 1, title: 'Title'
19
-
20
- post.id.must_equal 1
21
- post.title.must_equal 'Title'
22
-
23
- [:body, :user, :comments].each do |attribute|
24
- error = proc { post.send attribute }.must_raise Rasti::DB::Model::UninitializedAttributeError
25
- error.message.must_equal "Uninitialized attribute #{attribute}"
26
- end
27
-
28
- proc { post.invalid_method }.must_raise NoMethodError
29
- end
30
-
31
- end
32
-
33
-
34
- it 'Inheritance' do
35
- subclass = Class.new(User) do
36
- attribute :additional_attribute
37
- end
38
-
39
- subclass.attributes.must_equal (User.attributes + [:additional_attribute])
40
- end
41
-
42
- describe 'To String' do
43
-
44
- it 'Class' do
45
- User.to_s.must_equal 'User[id, name, posts, comments, person, comments_count]'
46
- end
47
-
48
- it 'Instance' do
49
- user = User.new id: 1, name: 'User 1'
50
- user.to_s.must_equal '#<User[id: 1, name: "User 1"]>'
51
- end
52
-
53
- end
54
-
55
- it 'To Hash' do
56
- post = Post.new id: 2,
57
- title: 'Title',
58
- body: 'body',
59
- user_id: 1,
60
- user: User.new(id: 1, name: 'User 1'),
61
- comments: [Comment.new(id: 4, text: 'comment text', user_id: 5)]
62
-
63
- post.to_h.must_equal id: 2,
64
- title: 'Title',
65
- body: 'body',
66
- user_id: 1,
67
- user: {id: 1, name: 'User 1'},
68
- comments: [{id: 4, text: 'comment text', user_id: 5}]
69
- end
70
-
71
- it 'Equality' do
72
- assert User.new(id: 1, name: 'User 1') == User.new(id: 1, name: 'User 1')
73
- refute User.new(id: 1, name: 'User 1') == User.new(id: 2, name: 'User 2')
74
-
75
- assert User.new(id: 1, name: 'User 1').eql? User.new(id: 1, name: 'User 1')
76
- refute User.new(id: 1, name: 'User 1').eql? User.new(id: 2, name: 'User 2')
77
-
78
- assert_equal User.new(id: 1, name: 'User 1').hash, User.new(id: 1, name: 'User 1').hash
79
- refute_equal User.new(id: 1, name: 'User 1').hash, User.new(id: 2, name: 'User 2').hash
80
- end
81
-
82
- it 'Merge' do
83
- user = User.new(id: 1, name: 'User 1')
84
- changed_user = user.merge(name: 'User 2')
85
-
86
- user.must_equal User.new(id: 1, name: 'User 1')
87
- changed_user.must_equal User.new(id: 1, name: 'User 2')
88
- end
89
-
90
- end