rasti-db 1.5.0 → 2.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: b801c94dd51c4ee11f624cb542d784a42e445622e0090c42cb9d47322b87e855
4
- data.tar.gz: 518c58daf408e477f80cdac52837a0e2d3256938352c888a73e369f3eca5b7a2
3
+ metadata.gz: 210581882359ef05a1b09c69b172f259b0b5010b61a254442e9844158a4f9456
4
+ data.tar.gz: 1dd3f0fcc8399e0145abc50166495a87826bb1b32e52de4acb45ea114f7650d5
5
5
  SHA512:
6
- metadata.gz: ae1452c9b77c6d50f9aa8b05b85f9970c801369e7e3a67a7a88436762fbacea4191390e114be066458d7bc2dc563f834cda93a364185354c74267db86798a889
7
- data.tar.gz: 2707b44943ea63f17cd0f613c4fa08bdfc0663e8fde17f604c8c6ce9ba8f1fff23b4fa1641dfe42f77810a55fda6794491f5e8d8cb756c4fc19adb1cbb8cba76
6
+ metadata.gz: 2c209c735eb50327d4bb7b54754530cd155dec884e32661f046de73dfb53fb036877e1e25f1ade565ef51a0517254096d24934f3d6e47393febc99318ea71118
7
+ data.tar.gz: a5a8326418216e1558ffea4b93e52a2369420fed2c8d9633dda5ffd8ee34b457e06aaaea2018001ba8725e51c1ef44386a78e2abaa51819628eba93cec38da99
data/README.md CHANGED
@@ -28,49 +28,62 @@ Or install it yourself as:
28
28
  ### Database connection
29
29
 
30
30
  ```ruby
31
- DB = Sequel.connect ...
31
+ DB_1 = Sequel.connect ...
32
+ DB_2 = Sequel.connect ...
32
33
  ```
33
34
 
34
35
  ### Database schema
35
36
 
36
37
  ```ruby
37
- DB.create_table :users do
38
+ DB_1.create_table :users do
38
39
  primary_key :id
39
40
  String :name, null: false, unique: true
40
41
  end
41
42
 
42
- DB.create_table :posts do
43
+ DB_1.create_table :posts do
43
44
  primary_key :id
44
45
  String :title, null: false, unique: true
45
46
  String :body, null: false
47
+ Integer :language_id, null: false, index: true
46
48
  foreign_key :user_id, :users, null: false, index: true
47
49
  end
48
50
 
49
- DB.create_table :comments do
51
+ DB_1.create_table :comments do
50
52
  primary_key :id
51
53
  String :text, null: false
52
54
  foreign_key :user_id, :users, null: false, index: true
53
55
  foreign_key :post_id, :posts, null: false, index: true
54
56
  end
55
57
 
56
- DB.create_table :categories do
58
+ DB_1.create_table :categories do
57
59
  primary_key :id
58
60
  String :name, null: false, unique: true
59
61
  end
60
62
 
61
- DB.create_table :categories_posts do
63
+ DB_1.create_table :categories_posts do
62
64
  foreign_key :category_id, :categories, null: false, index: true
63
65
  foreign_key :post_id, :posts, null: false, index: true
64
66
  primary_key [:category_id, :post_id]
65
67
  end
66
68
 
67
- DB.create_table :people do
69
+ DB_1.create_table :people do
68
70
  String :document_number, null: false, primary_key: true
69
71
  String :first_name, null: false
70
72
  String :last_name, null: false
71
73
  Date :birth_date, null: false
72
74
  foreign_key :user_id, :users, null: false, unique: true
73
75
  end
76
+
77
+ DB_1.create_table :languages_people do
78
+ Integer :language_id, null: false, index: true
79
+ foreign_key :document_number, :people, type: String, null: false, index: true
80
+ primary_key [:language_id, :document_number]
81
+ end
82
+
83
+ DB_2.create_table :languages do
84
+ primary_key :id
85
+ String :name, null: false, unique: true
86
+ end
74
87
  ```
75
88
 
76
89
  ### Models
@@ -81,6 +94,7 @@ Post = Rasti::DB::Model[:id, :title, :body, :user_id, :user, :comments, :cat
81
94
  Comment = Rasti::DB::Model[:id, :text, :user_id, :user, :post_id, :post]
82
95
  Category = Rasti::DB::Model[:id, :name, :posts]
83
96
  Person = Rasti::DB::Model[:document_number, :first_name, :last_name, :birth_date, :user_id, :user]
97
+ Language = Rasti::DB::Model[:id, :name, :people]
84
98
  ```
85
99
 
86
100
  ### Collections
@@ -105,8 +119,8 @@ class Posts < Rasti::DB::Collection
105
119
 
106
120
  query :commented_by do |user_id|
107
121
  chainable do
108
- dataset.join(with_schema(:comments), post_id: :id)
109
- .where(with_schema(:comments, :user_id) => user_id)
122
+ dataset.join(qualify(:comments), post_id: :id)
123
+ .where(Sequel[:comments][:user_id] => user_id)
110
124
  .select_all(:posts)
111
125
  .distinct
112
126
  end
@@ -129,19 +143,30 @@ class People < Rasti::DB::Collection
129
143
  set_model Person
130
144
 
131
145
  many_to_one :user
146
+ many_to_many :languages
132
147
  end
133
148
 
134
- users = Users.new DB
135
- posts = Posts.new DB
136
- comments = Comments.new DB
137
- categories = Categories.new DB
138
- people = People.new DB
149
+ class Languages < Rasti::DB::Collection
150
+ set_data_source_name :other
151
+
152
+ one_to_many :posts
153
+ many_to_many :people, collection: People, relation_data_source_name: :default
154
+ end
155
+
156
+ environment = Rasti::DB::Environment.new default: Rasti::DB::DataSource.new(DB_1),
157
+ other: Rasti::DB::DataSource.new(DB_2, 'custom_schema')
158
+
159
+ users = Users.new environment
160
+ posts = Posts.new environment
161
+ comments = Comments.new environment
162
+ categories = Categories.new environment
163
+ people = People.new environment
139
164
  ```
140
165
 
141
166
  ### Persistence
142
167
 
143
168
  ```ruby
144
- DB.transaction do
169
+ DB_1.transaction do
145
170
  id = users.insert name: 'User 1'
146
171
  users.update id, name: 'User updated'
147
172
  users.delete id
@@ -174,7 +199,7 @@ posts.created_by(1) # => [Post, ...]
174
199
  posts.created_by(1).entitled('...').commented_by(2) # => [Post, ...]
175
200
  posts.with_categories([1,2]) # => [Post, ...]
176
201
 
177
- posts.graph(:user, :categories, 'comments.user') # => [Post(User, [Categories, ...], [Comments(User)]), ...]
202
+ posts.graph(:user, :language, :categories, 'comments.user') # => [Post(User, Language, [Categories, ...], [Comments(User)]), ...]
178
203
 
179
204
  posts.join(:user).where(name: 'User 4') # => [Post, ...]
180
205
 
data/lib/rasti/db.rb CHANGED
@@ -14,7 +14,6 @@ module Rasti
14
14
  extend MultiRequire
15
15
  extend ClassConfig
16
16
 
17
- require_relative 'db/helpers'
18
17
  require_relative 'db/query'
19
18
  require_relative_pattern 'db/relations/*'
20
19
  require_relative_pattern 'db/type_converters/postgres_types/*'
@@ -4,8 +4,6 @@ module Rasti
4
4
 
5
5
  QUERY_METHODS = Query.public_instance_methods - Object.public_instance_methods
6
6
 
7
- include Helpers::WithSchema
8
-
9
7
  class << self
10
8
 
11
9
  extend Sequel::Inflections
@@ -37,12 +35,16 @@ module Rasti
37
35
  end
38
36
  end
39
37
 
38
+ def data_source_name
39
+ @data_source_name ||= superclass.respond_to?(:data_source_name) ? superclass.data_source_name : :default
40
+ end
41
+
40
42
  def relations
41
- @relations ||= {}
43
+ @relations ||= Hash::Indifferent.new
42
44
  end
43
45
 
44
46
  def queries
45
- @queries ||= {}
47
+ @queries ||= Hash::Indifferent.new
46
48
  end
47
49
 
48
50
  private
@@ -63,11 +65,17 @@ module Rasti
63
65
  @model = model
64
66
  end
65
67
 
68
+ def set_data_source_name(name)
69
+ @data_source_name = name.to_sym
70
+ end
71
+
66
72
  [Relations::OneToMany, Relations::ManyToOne, Relations::ManyToMany, Relations::OneToOne].each do |relation_class|
67
73
  define_method underscore(demodulize(relation_class.name)) do |name, options={}|
68
74
  relations[name] = relation_class.new name, self, options
69
75
 
70
- query "with_#{pluralize(name)}".to_sym do |primary_keys|
76
+ query_name = relations[name].to_many? ? name : pluralize(name)
77
+
78
+ query "with_#{query_name}" do |primary_keys|
71
79
  with_related name, primary_keys
72
80
  end
73
81
  end
@@ -85,11 +93,8 @@ module Rasti
85
93
 
86
94
  end
87
95
 
88
- attr_reader :db, :schema
89
-
90
- def initialize(db, schema=nil)
91
- @db = db
92
- @schema = schema ? schema.to_sym : nil
96
+ def initialize(environment)
97
+ @environment = environment
93
98
  end
94
99
 
95
100
  QUERY_METHODS.each do |method|
@@ -98,12 +103,8 @@ module Rasti
98
103
  end
99
104
  end
100
105
 
101
- def dataset
102
- db[qualified_collection_name]
103
- end
104
-
105
106
  def insert(attributes)
106
- db.transaction do
107
+ data_source.db.transaction do
107
108
  db_attributes = transform_attributes_to_db attributes
108
109
  collection_attributes, relations_primary_keys = split_related_attributes db_attributes
109
110
  primary_key = dataset.insert collection_attributes
@@ -126,7 +127,7 @@ module Rasti
126
127
  end
127
128
 
128
129
  def update(primary_key, attributes)
129
- db.transaction do
130
+ data_source.db.transaction do
130
131
  db_attributes = transform_attributes_to_db attributes
131
132
  collection_attributes, relations_primary_keys = split_related_attributes db_attributes
132
133
  dataset.where(self.class.primary_key => primary_key).update(collection_attributes) unless collection_attributes.empty?
@@ -152,7 +153,7 @@ module Rasti
152
153
  end
153
154
 
154
155
  def delete_relations(primary_key, relations)
155
- db.transaction do
156
+ data_source.db.transaction do
156
157
  relations.each do |relation_name, relation_primary_keys|
157
158
  relation = self.class.relations[relation_name]
158
159
  delete_relation_table relation, primary_key, relation_primary_keys
@@ -162,7 +163,7 @@ module Rasti
162
163
  end
163
164
 
164
165
  def delete_cascade(*primary_keys)
165
- db.transaction do
166
+ data_source.db.transaction do
166
167
  delete_cascade_relations primary_keys
167
168
  bulk_delete { |q| q.where self.class.primary_key => primary_keys }
168
169
  end
@@ -187,33 +188,48 @@ module Rasti
187
188
 
188
189
  private
189
190
 
190
- def transform_attributes_to_db(attributes)
191
- attributes.each_with_object({}) do |(attribute_name, value), result|
192
- transformed_value = Rasti::DB.to_db db, qualified_collection_name, attribute_name, value
193
- result[attribute_name] = transformed_value
194
- end
191
+ attr_reader :environment
192
+
193
+ def data_source
194
+ @data_source ||= environment.data_source_of self.class
195
+ end
196
+
197
+ def dataset
198
+ data_source.db[qualified_collection_name]
195
199
  end
196
200
 
197
201
  def qualified_collection_name
198
- schema.nil? ? Sequel[self.class.collection_name] : Sequel[schema][self.class.collection_name]
202
+ data_source.qualify self.class.collection_name
199
203
  end
200
204
 
205
+ def qualify(collection_name, data_source_name: nil)
206
+ data_source_name ||= self.class.data_source_name
207
+ environment.qualify data_source_name, collection_name
208
+ end
209
+
201
210
  def default_query
202
211
  Query.new collection_class: self.class,
203
212
  dataset: dataset.select_all(self.class.collection_name),
204
- schema: schema
213
+ environment: environment
205
214
  end
206
215
 
207
216
  def build_query(filter=nil, &block)
208
217
  raise ArgumentError, 'must specify filter hash or block' if filter.nil? && block.nil?
209
218
 
210
219
  if filter
211
- default_query.where filter
220
+ default_query.where(filter)
212
221
  else
213
222
  block.arity == 0 ? default_query.instance_eval(&block) : block.call(default_query)
214
223
  end
215
224
  end
216
225
 
226
+ def transform_attributes_to_db(attributes)
227
+ attributes.each_with_object({}) do |(attribute_name, value), result|
228
+ transformed_value = Rasti::DB.to_db data_source.db, qualified_collection_name, attribute_name, value
229
+ result[attribute_name] = transformed_value
230
+ end
231
+ end
232
+
217
233
  def split_related_attributes(attributes)
218
234
  relation_names = self.class.relations.values.select(&:many_to_many?).map(&:name)
219
235
 
@@ -239,18 +255,22 @@ module Rasti
239
255
  end
240
256
 
241
257
  relations.select { |r| r.one_to_many? || r.one_to_one? }.each do |relation|
242
- relation_collection_name = with_schema(relation.target_collection_class.collection_name)
243
- relations_ids = db[relation_collection_name].where(relation.foreign_key => primary_keys)
244
- .select(relation.target_collection_class.primary_key)
245
- .map(relation.target_collection_class.primary_key)
258
+ relation_data_source = environment.data_source_of relation.target_collection_class
259
+ relation_collection_name = relation_data_source.qualify relation.target_collection_class.collection_name
260
+
261
+ relations_ids = relation_data_source.db[relation_collection_name]
262
+ .where(relation.foreign_key => primary_keys)
263
+ .select(relation.target_collection_class.primary_key)
264
+ .map(relation.target_collection_class.primary_key)
246
265
 
247
- target_collection = relation.target_collection_class.new db, schema
266
+ target_collection = relation.target_collection_class.new environment
248
267
  target_collection.delete_cascade(*relations_ids) unless relations_ids.empty?
249
268
  end
250
269
  end
251
270
 
252
271
  def insert_relation_table(relation, primary_key, relation_primary_keys)
253
- relation_collection_name = relation.qualified_relation_collection_name(schema)
272
+ relation_data_source = environment.data_source relation.relation_data_source_name
273
+ relation_collection_name = relation_data_source.qualify relation.relation_collection_name
254
274
 
255
275
  values = relation_primary_keys.map do |relation_pk|
256
276
  {
@@ -259,12 +279,14 @@ module Rasti
259
279
  }
260
280
  end
261
281
 
262
- db[relation_collection_name].multi_insert values
282
+ relation_data_source.db[relation_collection_name].multi_insert values
263
283
  end
264
284
 
265
285
  def delete_relation_table(relation, primary_keys, relation_primary_keys=nil)
266
- relation_collection_name = relation.qualified_relation_collection_name(schema)
267
- ds = db[relation_collection_name].where(relation.source_foreign_key => primary_keys)
286
+ relation_data_source = environment.data_source relation.relation_data_source_name
287
+ relation_collection_name = relation_data_source.qualify relation.relation_collection_name
288
+
289
+ ds = relation_data_source.db[relation_collection_name].where(relation.source_foreign_key => primary_keys)
268
290
  ds = ds.where(relation.target_foreign_key => relation_primary_keys) if relation_primary_keys
269
291
  ds.delete
270
292
  end
@@ -0,0 +1,18 @@
1
+ module Rasti
2
+ module DB
3
+ class DataSource
4
+
5
+ attr_reader :db, :schema
6
+
7
+ def initialize(db, schema=nil)
8
+ @db = db
9
+ @schema = schema ? schema.to_sym : nil
10
+ end
11
+
12
+ def qualify(collection_name)
13
+ schema ? Sequel[schema][collection_name] : Sequel[collection_name]
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ module Rasti
2
+ module DB
3
+ class Environment
4
+
5
+ def initialize(data_sources)
6
+ @data_sources = data_sources
7
+ end
8
+
9
+ def data_source(name)
10
+ raise "Undefined data source #{name}" unless data_sources.key? name
11
+ data_sources[name]
12
+ end
13
+
14
+ def data_source_of(collection_class)
15
+ data_source collection_class.data_source_name
16
+ end
17
+
18
+ def qualify(data_source_name, collection_name)
19
+ data_source(data_source_name).qualify collection_name
20
+ end
21
+
22
+ def qualify_collection(collection_class)
23
+ data_source_of(collection_class).qualify collection_class.collection_name
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :data_sources
29
+
30
+ end
31
+ end
32
+ end
@@ -5,13 +5,12 @@ module Rasti
5
5
  DATASET_CHAINED_METHODS = [:where, :exclude, :or, :order, :reverse_order, :limit, :offset].freeze
6
6
 
7
7
  include Enumerable
8
- include Helpers::WithSchema
9
8
 
10
- def initialize(collection_class:, dataset:, relations_graph:nil, schema:nil)
9
+ def initialize(environment:, collection_class:, dataset:, relations_graph:nil)
10
+ @environment = environment
11
11
  @collection_class = collection_class
12
12
  @dataset = dataset
13
- @relations_graph = relations_graph || Relations::Graph.new(dataset.db, schema, collection_class)
14
- @schema = schema
13
+ @relations_graph = relations_graph || Relations::Graph.new(environment, collection_class)
15
14
  end
16
15
 
17
16
  DATASET_CHAINED_METHODS.each do |method|
@@ -74,7 +73,7 @@ module Rasti
74
73
  end
75
74
 
76
75
  def join(*relations)
77
- graph = Relations::Graph.new dataset.db, schema, collection_class, relations
76
+ graph = Relations::Graph.new environment, collection_class, relations
78
77
 
79
78
  ds = graph.add_joins(dataset)
80
79
  .distinct
@@ -127,14 +126,14 @@ module Rasti
127
126
 
128
127
  private
129
128
 
130
- attr_reader :collection_class, :dataset, :relations_graph, :schema
129
+ attr_reader :environment, :collection_class, :dataset, :relations_graph
131
130
 
132
131
  def build_query(**args)
133
132
  current_args = {
133
+ environment: environment,
134
134
  collection_class: collection_class,
135
135
  dataset: dataset,
136
- relations_graph: relations_graph,
137
- schema: schema
136
+ relations_graph: relations_graph
138
137
  }
139
138
 
140
139
  Query.new(**current_args.merge(args))
@@ -145,7 +144,7 @@ module Rasti
145
144
  end
146
145
 
147
146
  def with_related(relation_name, primary_keys)
148
- ds = collection_class.relations[relation_name].apply_filter dataset, schema, primary_keys
147
+ ds = collection_class.relations[relation_name].apply_filter environment, dataset, primary_keys
149
148
  build_query dataset: ds
150
149
  end
151
150
 
@@ -155,6 +154,11 @@ module Rasti
155
154
  data
156
155
  end
157
156
 
157
+ def qualify(collection_name, data_source_name: nil)
158
+ data_source_name ||= collection_class.data_source_name
159
+ environment.qualify data_source_name, collection_name
160
+ end
161
+
158
162
  def nql_parser
159
163
  NQL::SyntaxParser.new
160
164
  end