rasti-db 4.1.1 → 4.2.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: 331138443b43eefbd6f4e9008755646f790a7a12329d5fb342936b97de8d9bfe
4
- data.tar.gz: 9723170bbbf65352a112312a6b72953a69055ceca9d115763705d6363b00e669
3
+ metadata.gz: fa10d65e8a9fbd3c311384e8806addd5c04b803405444717d6904282dbf9207c
4
+ data.tar.gz: 24f1e8801906634288e62ef7337da1179392e75203b08ae6f034b5f25256228e
5
5
  SHA512:
6
- metadata.gz: '00777167854dfaa0f0e133b157ac97e56a8a94c840b79a024a2f0af507a995a77f72372b263ee4a00770970d0f6646f0c034ee5cee733dae892bb85cae78f756'
7
- data.tar.gz: 66f2f804441640d2cfe7ed3694000092e9d8f7541e6478c4be98b475b7e3d70de7d8a7c78c63b19a8542c89cf1ff7311291f6c09f8d339ba8a2d257a2a671efe
6
+ metadata.gz: 04a6c1deb6afa47fae66203bec39d81926ac5e6435844593c321279423d6a8a5651178fc5769e58868f88286ae819ecfd7aa77785b2e6df82cd63096d12ee34f
7
+ data.tar.gz: 28ec23866d539f20163bff9449586060d1f943d022f10f72d2d4b4ff5f3fc8b9db97acbefa2482fcc262d0e51625bad603ea3861fbea7f47fe36382ce9da5821
@@ -13,7 +13,7 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby-version: ['2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', 'jruby-9.2.9.0']
16
+ ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', 'jruby-9.2.9.0']
17
17
 
18
18
  steps:
19
19
  - uses: actions/checkout@v3
@@ -53,6 +53,10 @@ module Rasti
53
53
  build_query relations_graph: relations_graph.merge(excluded_attributes: excluded_attributes)
54
54
  end
55
55
 
56
+ def graph_queries(queries)
57
+ build_query relations_graph: relations_graph.merge(queries: queries)
58
+ end
59
+
56
60
  def all_graph_attributes(*relations)
57
61
  build_query relations_graph: relations_graph.with_all_attributes_for(relations)
58
62
  end
@@ -215,4 +219,4 @@ module Rasti
215
219
 
216
220
  end
217
221
  end
218
- end
222
+ end
@@ -3,20 +3,22 @@ module Rasti
3
3
  module Relations
4
4
  class Graph
5
5
 
6
- def initialize(environment, collection_class, relations=[], selected_attributes={}, excluded_attributes={})
6
+ def initialize(environment, collection_class, relations=[], selected_attributes={}, excluded_attributes={}, queries={})
7
7
  @environment = environment
8
8
  @collection_class = collection_class
9
9
  @graph = build_graph relations,
10
10
  Hash::Indifferent.new(selected_attributes),
11
- Hash::Indifferent.new(excluded_attributes)
11
+ Hash::Indifferent.new(excluded_attributes),
12
+ Hash::Indifferent.new(queries)
12
13
  end
13
14
 
14
- def merge(relations:[], selected_attributes:{}, excluded_attributes:{})
15
+ def merge(relations:[], selected_attributes:{}, excluded_attributes:{}, queries: {})
15
16
  Graph.new environment,
16
17
  collection_class,
17
18
  (flat_relations | relations),
18
19
  flat_selected_attributes.merge(selected_attributes),
19
- flat_excluded_attributes.merge(excluded_attributes)
20
+ flat_excluded_attributes.merge(excluded_attributes),
21
+ flat_queries.merge(queries)
20
22
  end
21
23
 
22
24
  def with_all_attributes_for(relations)
@@ -30,16 +32,17 @@ module Rasti
30
32
  query.graph(*flat_relations)
31
33
  .select_graph_attributes(flat_selected_attributes)
32
34
  .exclude_graph_attributes(flat_excluded_attributes)
35
+ .graph_queries(flat_queries)
33
36
  end
34
37
 
35
38
  def fetch_graph(rows)
36
39
  return if rows.empty?
37
-
38
40
  graph.roots.each do |node|
39
41
  relation_of(node).fetch_graph environment,
40
42
  rows,
41
43
  node[:selected_attributes],
42
- node[:excluded_attributes] ,
44
+ node[:excluded_attributes],
45
+ node[:queries] ,
43
46
  subgraph_of(node)
44
47
  end
45
48
  end
@@ -76,33 +79,43 @@ module Rasti
76
79
  end
77
80
  end
78
81
 
82
+ def flat_queries
83
+ graph.each_with_object(Hash::Indifferent.new) do |node, hash|
84
+ hash[node.id] = node[:queries]
85
+ end
86
+ end
87
+
79
88
  def subgraph_of(node)
80
89
  relations = []
81
90
  selected = Hash::Indifferent.new
82
91
  excluded = Hash::Indifferent.new
92
+ queries = Hash::Indifferent.new
83
93
 
84
94
  node.descendants.each do |descendant|
85
95
  id = descendant.id[node[:name].length+1..-1]
86
96
  relations << id
87
97
  selected[id] = descendant[:selected_attributes]
88
98
  excluded[id] = descendant[:excluded_attributes]
99
+ queries[id] = descendant[:queries]
89
100
  end
90
101
 
91
102
  Graph.new environment,
92
103
  relation_of(node).target_collection_class,
93
104
  relations,
94
105
  selected,
95
- excluded
106
+ excluded,
107
+ queries
96
108
  end
97
109
 
98
- def build_graph(relations, selected_attributes, excluded_attributes)
110
+ def build_graph(relations, selected_attributes, excluded_attributes, queries)
99
111
  HierarchicalGraph.new.tap do |graph|
100
112
  flatten(relations).each do |relation|
101
113
  sections = relation.split('.')
102
114
 
103
115
  graph.add_node relation, name: sections.last.to_sym,
104
116
  selected_attributes: selected_attributes[relation],
105
- excluded_attributes: excluded_attributes[relation]
117
+ excluded_attributes: excluded_attributes[relation],
118
+ queries: queries[relation]
106
119
 
107
120
  if sections.count > 1
108
121
  parent_id = sections[0..-2].join('.')
@@ -126,4 +139,4 @@ module Rasti
126
139
  end
127
140
  end
128
141
  end
129
- end
142
+ end
@@ -19,9 +19,9 @@ module Rasti
19
19
  @relation_data_source_name ||= options[:relation_data_source_name] || source_collection_class.data_source_name
20
20
  end
21
21
 
22
- def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
22
+ def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, queries=nil, relations_graph=nil)
23
23
  pks = rows.map { |row| row[source_collection_class.primary_key] }
24
-
24
+
25
25
  if target_collection_class.data_source_name == relation_data_source_name
26
26
  target_data_source = environment.data_source_of target_collection_class
27
27
 
@@ -30,10 +30,14 @@ module Rasti
30
30
  .where(Sequel[relation_collection_name][source_foreign_key] => pks)
31
31
  .select_all(target_collection_class.collection_name)
32
32
 
33
- selected_attributes ||= target_collection_class.collection_attributes - excluded_attributes if excluded_attributes
34
- dataset = dataset.select(*selected_attributes.map { |a| Sequel[target_collection_class.collection_name][a] }) if selected_attributes
33
+ selected_attributes ||= target_collection_class.collection_attributes - excluded_attributes unless excluded_attributes.nil?
34
+ dataset = dataset.select(*selected_attributes.map { |a| Sequel[target_collection_class.collection_name][a] }) unless selected_attributes.nil?
35
+
36
+ query = Query.new collection_class: target_collection_class, dataset: dataset, environment: environment
37
+ query = queries.inject(query) { |new_query, sub_query| new_query.send(sub_query) } unless queries.nil?
38
+
39
+ join_rows = query.send(:dataset).select_append(Sequel[relation_collection_name][source_foreign_key].as(:source_foreign_key)).all
35
40
 
36
- join_rows = dataset.select_append(Sequel[relation_collection_name][source_foreign_key].as(:source_foreign_key)).all
37
41
  else
38
42
  relation_data_source = environment.data_source relation_data_source_name
39
43
 
@@ -42,8 +46,10 @@ module Rasti
42
46
  .select_hash_groups(target_foreign_key, source_foreign_key)
43
47
 
44
48
  query = target_collection_class.new environment
45
- query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
46
- query = query.select_attributes(*selected_attributes) if selected_attributes
49
+ query = query.exclude_attributes(*excluded_attributes) unless excluded_attributes.nil?
50
+ query = query.select_attributes(*selected_attributes) unless selected_attributes.nil?
51
+
52
+ query = queries.inject(query) { |new_query, sub_query| new_query.send(sub_query) } unless queries.nil?
47
53
 
48
54
  join_rows = query.where(target_collection_class.primary_key => relation_index.keys).raw.flat_map do |row|
49
55
  relation_index[row[target_collection_class.primary_key]].map do |source_primary_key|
@@ -110,4 +116,4 @@ module Rasti
110
116
  end
111
117
  end
112
118
  end
113
- end
119
+ end
@@ -7,14 +7,18 @@ module Rasti
7
7
  @foreign_key ||= options[:foreign_key] || target_collection_class.foreign_key
8
8
  end
9
9
 
10
- def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
10
+ def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, queries=nil, relations_graph=nil)
11
11
  fks = rows.map { |row| row[foreign_key] }.uniq
12
12
 
13
13
  target_collection = target_collection_class.new environment
14
14
 
15
15
  query = target_collection.where(source_collection_class.primary_key => fks)
16
- query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
17
- query = query.select_attributes(*selected_attributes) if selected_attributes
16
+
17
+ query = query.exclude_attributes(*excluded_attributes) unless excluded_attributes.nil?
18
+ query = query.select_attributes(*selected_attributes) unless selected_attributes.nil?
19
+
20
+ query = queries.inject(query) { |new_query, sub_query| new_query.send(sub_query) } unless queries.nil?
21
+
18
22
  query = relations_graph.apply_to query if relations_graph
19
23
 
20
24
  relation_rows = query.each_with_object({}) do |row, hash|
@@ -47,4 +51,4 @@ module Rasti
47
51
  end
48
52
  end
49
53
  end
50
- end
54
+ end
@@ -7,14 +7,17 @@ module Rasti
7
7
  @foreign_key ||= options[:foreign_key] || source_collection_class.foreign_key
8
8
  end
9
9
 
10
- def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, relations_graph=nil)
10
+ def fetch_graph(environment, rows, selected_attributes=nil, excluded_attributes=nil, queries=nil, relations_graph=nil)
11
11
  pks = rows.map { |row| row[source_collection_class.primary_key] }.uniq
12
12
 
13
13
  target_collection = target_collection_class.new environment
14
14
 
15
15
  query = target_collection.where(foreign_key => pks)
16
- query = query.exclude_attributes(*excluded_attributes) if excluded_attributes
17
- query = query.select_attributes(*selected_attributes) if selected_attributes
16
+ query = query.exclude_attributes(*excluded_attributes) unless excluded_attributes.nil?
17
+ query = query.select_attributes(*selected_attributes) unless selected_attributes.nil?
18
+
19
+ query = queries.inject(query) { |new_query, sub_query| new_query.send(sub_query) } unless queries.nil?
20
+
18
21
  query = relations_graph.apply_to query if relations_graph
19
22
 
20
23
  relation_rows = query.group_by(&foreign_key)
@@ -62,4 +65,4 @@ module Rasti
62
65
  end
63
66
  end
64
67
  end
65
- end
68
+ end
@@ -1,5 +1,5 @@
1
1
  module Rasti
2
2
  module DB
3
- VERSION = '4.1.1'
3
+ VERSION = '4.2.0'
4
4
  end
5
5
  end
@@ -20,10 +20,11 @@ Comment = Rasti::DB::Model[:id, :text, :user_id, :user, :post_id, :post, :tags]
20
20
  Category = Rasti::DB::Model[:id, :name, :posts]
21
21
  Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :birth_date, :user_id, :user, :languages, :full_name]
22
22
  Language = Rasti::DB::Model[:id, :name, :people, :countries]
23
- Country = Rasti::DB::Model[:id, :name, :language_id]
23
+ Country = Rasti::DB::Model[:id, :name, :population, :language_id]
24
24
 
25
25
 
26
26
  class Users < Rasti::DB::Collection
27
+
27
28
  one_to_many :posts
28
29
  one_to_many :comments
29
30
  one_to_one :person
@@ -42,6 +43,7 @@ class Users < Rasti::DB::Collection
42
43
  end
43
44
 
44
45
  class Posts < Rasti::DB::Collection
46
+
45
47
  many_to_one :user
46
48
  many_to_one :language
47
49
  many_to_many :categories
@@ -62,6 +64,18 @@ class Posts < Rasti::DB::Collection
62
64
  end
63
65
  end
64
66
 
67
+ query :only_title do
68
+ chainable do
69
+ dataset.select(:title).select_append(:id, :user_id)
70
+ end
71
+ end
72
+
73
+ query :append_body do
74
+ chainable do
75
+ dataset.select_append(:body)
76
+ end
77
+ end
78
+
65
79
  computed_attribute :notice do
66
80
  Rasti::DB::ComputedAttribute.new Sequel.join([:title, ': ', :body])
67
81
  end
@@ -73,6 +87,7 @@ class Posts < Rasti::DB::Collection
73
87
  end
74
88
 
75
89
  class Comments < Rasti::DB::Collection
90
+
76
91
  many_to_one :user
77
92
  many_to_one :post
78
93
 
@@ -82,13 +97,17 @@ class Comments < Rasti::DB::Collection
82
97
  .select_all(:posts)
83
98
  .map { |row| Post.new row }
84
99
  end
100
+
85
101
  end
86
102
 
87
103
  class Categories < Rasti::DB::Collection
104
+
88
105
  many_to_many :posts
106
+
89
107
  end
90
108
 
91
109
  class People < Rasti::DB::Collection
110
+
92
111
  set_collection_name :people
93
112
  set_primary_key :document_number
94
113
  set_foreign_key :document_number
@@ -100,18 +119,23 @@ class People < Rasti::DB::Collection
100
119
  computed_attribute :full_name do |db|
101
120
  Rasti::DB::ComputedAttribute.new Sequel.join([:first_name, ' ', :last_name])
102
121
  end
122
+
103
123
  end
104
124
 
105
125
  class Languages < Rasti::DB::Collection
126
+
106
127
  set_data_source_name :custom
107
128
 
108
129
  many_to_many :people, collection: People, relation_data_source_name: :default
109
130
  one_to_many :posts
110
131
  one_to_many :countries
132
+
111
133
  end
112
134
 
113
135
  class Countries < Rasti::DB::Collection
136
+
114
137
  many_to_one :language
138
+
115
139
  end
116
140
 
117
141
 
@@ -140,7 +164,6 @@ class Minitest::Spec
140
164
 
141
165
  let :db do
142
166
  Sequel.connect(driver).tap do |db|
143
-
144
167
  db.create_table :users do
145
168
  primary_key :id
146
169
  String :name, null: false, unique: true
@@ -193,19 +216,16 @@ class Minitest::Spec
193
216
  Integer :population, null: false
194
217
  Integer :language_id, null: false, index: true
195
218
  end
196
-
197
219
  end
198
220
  end
199
221
 
200
222
  let :custom_db do
201
223
  Sequel.connect(driver).tap do |db|
202
-
203
224
  db.create_table :languages do
204
225
  primary_key :id
205
226
  String :name, null: false, unique: true
206
227
  end
207
-
208
228
  end
209
229
  end
210
230
 
211
- end
231
+ end
data/spec/query_spec.rb CHANGED
@@ -48,6 +48,8 @@ describe 'Query' do
48
48
 
49
49
  let(:countries_query) { Rasti::DB::Query.new collection_class: Countries, dataset: db[:countries], environment: environment }
50
50
 
51
+ let(:categories_query) { Rasti::DB::Query.new collection_class: Categories, dataset: db[:categories], environment: environment }
52
+
51
53
  it 'Count' do
52
54
  users_query.count.must_equal 10
53
55
  end
@@ -146,6 +148,59 @@ describe 'Query' do
146
148
  .must_equal [post]
147
149
  end
148
150
 
151
+ it 'Graph with query many to one' do
152
+ comments_query.graph('post')
153
+ .graph_queries('post' => [:only_title])
154
+ .where(id: 1)
155
+ .all
156
+ .must_equal [
157
+ Comment.new(id: 1, text: 'Comment 1', user_id: 5, post_id: 1, post: Post.new(id: 1, user_id: 2, title: 'Sample post'), tags: [])
158
+ ]
159
+ end
160
+
161
+ it 'Graph with query one to many' do
162
+ users_query.graph('posts')
163
+ .graph_queries('posts' => [:only_title])
164
+ .where(id: 1)
165
+ .all
166
+ .must_equal [
167
+ User.new(id: 1, name: 'User 1', posts: [Post.new(user_id: 1, id: 2, title: 'Another post')])
168
+ ]
169
+ end
170
+
171
+ it 'Graph with query many to many' do
172
+ categories_query.graph('posts')
173
+ .graph_queries('posts' => [:only_title])
174
+ .where(id: 1)
175
+ .all
176
+ .must_equal [
177
+ Category.new(id: 1, name: 'Category 1', posts: [Post.new(user_id: 2, id: 1, title: 'Sample post')])
178
+ ]
179
+ end
180
+
181
+ it 'Graph with n queries' do
182
+ comments_query.graph('post')
183
+ .graph_queries('post' => [:only_title, :append_body])
184
+ .where(id: 1)
185
+ .all
186
+ .must_equal [
187
+ Comment.new(id: 1, text: 'Comment 1', user_id: 5, post_id: 1, post: Post.new(id: 1, user_id: 2, title: 'Sample post', body: '...'), tags: [])
188
+ ]
189
+
190
+ end
191
+
192
+ it 'Graph query missing must raise error' do
193
+ proc { posts_query.graph('comments.user')
194
+ .graph_queries('comments.user' => [:with_not_exists_query])
195
+ .all }.must_raise NoMethodError
196
+ end
197
+
198
+ it 'Graph with query params must raise error' do
199
+ proc { users_query.graph('posts')
200
+ .graph_queries('posts' => [:created_by])
201
+ .all }.must_raise ArgumentError
202
+ end
203
+
149
204
  describe 'Select computed attributes' do
150
205
  it 'With join' do
151
206
  db[:comments].insert post_id: 1, user_id: 5, text: 'Comment 4'
@@ -179,12 +234,12 @@ describe 'Query' do
179
234
  language_id: 1
180
235
 
181
236
  [countries_query.detect(id: 1), countries_query.where(id: 1).order(:name).last, countries_query.all.first].each do |country|
182
- country.must_equal Country.new(language_id: 1, id: 1, name: 'Argentina')
237
+ country.must_equal Country.new(language_id: 1, id: 1, name: 'Argentina', population: 40000000)
183
238
  end
184
239
  end
185
240
 
186
241
  it 'Graph nested' do
187
- languages_query.graph(:countries).first.countries.must_equal [Country.new(language_id: 1, id: 1, name: 'Argentina')]
242
+ languages_query.graph(:countries).first.countries.must_equal [Country.new(language_id: 1, id: 1, name: 'Argentina', population: 40000000)]
188
243
  end
189
244
 
190
245
  end
@@ -576,4 +631,4 @@ describe 'Query' do
576
631
 
577
632
  end
578
633
 
579
- end
634
+ 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: 4.1.1
4
+ version: 4.2.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: 2022-05-05 00:00:00.000000000 Z
11
+ date: 2024-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel