rasti-db 4.1.1 → 4.2.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
  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