vorpal 1.0.1 → 1.2.1
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 +4 -4
- data/README.md +72 -56
- data/lib/vorpal/aggregate_mapper.rb +11 -0
- data/lib/vorpal/config/class_config.rb +71 -0
- data/lib/vorpal/configs.rb +9 -66
- data/lib/vorpal/driver/postgresql.rb +39 -3
- data/lib/vorpal/dsl/config_builder.rb +12 -50
- data/lib/vorpal/dsl/configuration.rb +131 -42
- data/lib/vorpal/dsl/defaults_generator.rb +14 -4
- data/lib/vorpal/engine.rb +18 -5
- data/lib/vorpal/identity_map.rb +15 -14
- data/lib/vorpal/version.rb +1 -1
- data/vorpal.gemspec +9 -9
- metadata +36 -88
- data/.editorconfig +0 -13
- data/.envrc +0 -4
- data/.gitignore +0 -16
- data/.rspec +0 -1
- data/.yardopts +0 -1
- data/Appraisals +0 -34
- data/Gemfile +0 -4
- data/Rakefile +0 -10
- data/bin/appraisal +0 -29
- data/bin/rake +0 -29
- data/bin/rspec +0 -29
- data/gemfiles/rails_4_1.gemfile +0 -11
- data/gemfiles/rails_4_1.gemfile.lock +0 -92
- data/gemfiles/rails_4_2.gemfile +0 -11
- data/gemfiles/rails_4_2.gemfile.lock +0 -90
- data/gemfiles/rails_5_0.gemfile +0 -11
- data/gemfiles/rails_5_0.gemfile.lock +0 -88
- data/gemfiles/rails_5_1.gemfile +0 -11
- data/gemfiles/rails_5_1.gemfile.lock +0 -88
- data/gemfiles/rails_5_2.gemfile +0 -11
- data/gemfiles/rails_5_2.gemfile.lock +0 -88
- data/spec/helpers/db_helpers.rb +0 -66
- data/spec/helpers/profile_helpers.rb +0 -26
- data/spec/integration_spec_helper.rb +0 -36
- data/spec/unit_spec_helper.rb +0 -0
- data/spec/vorpal/acceptance/aggregate_mapper_spec.rb +0 -911
- data/spec/vorpal/integration/driver/postgresql_spec.rb +0 -42
- data/spec/vorpal/performance/performance_spec.rb +0 -235
- data/spec/vorpal/unit/configs_spec.rb +0 -117
- data/spec/vorpal/unit/db_loader_spec.rb +0 -103
- data/spec/vorpal/unit/dsl/config_builder_spec.rb +0 -18
- data/spec/vorpal/unit/dsl/defaults_generator_spec.rb +0 -75
- data/spec/vorpal/unit/identity_map_spec.rb +0 -62
- data/spec/vorpal/unit/loaded_objects_spec.rb +0 -22
- data/spec/vorpal/unit/util/string_utils_spec.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83737ac0a684cae35b5e849cba0c7851234dd83644ec04458e2c3c49ae0213f1
|
4
|
+
data.tar.gz: 8ac93c1267e080bc874dc2526d7b9f2c5abc1635c579d0f4be7cbd9af4fd7fc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 959ef178a6479c47053c2d100c323a48134fdcf7c63479c21afff0cc7cb91f2a198962013e5b324c7a8a4b1946e19332b15198c957c3e1b097e7734036b2ab09
|
7
|
+
data.tar.gz: 2783c22ba9362a9285e4e80369565a8be0695feb910325f77233b43060826dfffafd03e74c2c4cdcb554e6246eba1e42441b7b2f94d7ba0748cda140effee044
|
data/README.md
CHANGED
@@ -1,16 +1,13 @@
|
|
1
|
-
# Vorpal [](https://travis-ci.com/nulogy/vorpal) [](https://codeclimate.com/github/nulogy/vorpal) [](https://codecov.io/gh/nulogy/vorpal/branch/main)
|
2
2
|
|
3
3
|
Separate your domain model from your persistence mechanism. Some problems call for a really sharp tool.
|
4
4
|
|
5
|
-
|
6
|
-
>
|
7
|
-
|
8
|
-
> The vorpal blade went snicker-snack!
|
9
|
-
|
10
|
-
> He left it dead, and with its head
|
11
|
-
|
5
|
+
> One, two! One, two! and through and through<br/>
|
6
|
+
> The vorpal blade went snicker-snack!<br/>
|
7
|
+
> He left it dead, and with its head<br/>
|
12
8
|
> He went galumphing back.
|
13
9
|
|
10
|
+
\- [Jabberwocky](https://www.poetryfoundation.org/poems/42916/jabberwocky) by Lewis Carroll
|
14
11
|
|
15
12
|
## Overview
|
16
13
|
Vorpal is a [Data Mapper](http://martinfowler.com/eaaCatalog/dataMapper.html)-style ORM (object relational mapper) framelet that persists POROs (plain old Ruby objects) to a relational DB. It has been heavily influenced by concepts from [Domain Driven Design](http://www.infoq.com/minibooks/domain-driven-design-quickly).
|
@@ -48,27 +45,21 @@ Or install it yourself as:
|
|
48
45
|
Start with a domain model of POROs and AR::Base objects that form an aggregate:
|
49
46
|
|
50
47
|
```ruby
|
51
|
-
class Tree; end
|
52
|
-
|
53
48
|
class Branch
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
attribute :diameter, Decimal
|
59
|
-
attribute :tree, Tree
|
49
|
+
attr_accessor :id
|
50
|
+
attr_accessor :length
|
51
|
+
attr_accessor :diameter
|
52
|
+
attr_accessor :tree
|
60
53
|
end
|
61
54
|
|
62
|
-
class Gardener
|
55
|
+
class Gardener
|
63
56
|
end
|
64
57
|
|
65
58
|
class Tree
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
attribute :gardener, Gardener
|
71
|
-
attribute :branches, Array[Branch]
|
59
|
+
attr_accessor :id
|
60
|
+
attr_accessor :name
|
61
|
+
attr_accessor :gardener
|
62
|
+
attr_accessor :branches
|
72
63
|
end
|
73
64
|
```
|
74
65
|
|
@@ -143,7 +134,8 @@ module TreeRepository
|
|
143
134
|
end
|
144
135
|
```
|
145
136
|
|
146
|
-
Here we've used the `owned` flag on the `belongs_to` from the Tree to the Gardener to show
|
137
|
+
Here we've used the `owned: false` flag on the `belongs_to` from the Tree to the Gardener to show
|
138
|
+
that the Gardener is on the aggregate boundary.
|
147
139
|
|
148
140
|
And use it:
|
149
141
|
|
@@ -164,9 +156,33 @@ TreeRepository.destroy(dead_tree)
|
|
164
156
|
TreeRepository.destroy_by_id(dead_tree_id)
|
165
157
|
```
|
166
158
|
|
159
|
+
### Ids
|
160
|
+
|
161
|
+
Vorpal by default will use auto-incrementing Integers from a DB sequence for ids. However, UUID v4 ids are also
|
162
|
+
supported:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
Vorpal.define do
|
166
|
+
# UUID v4 id!
|
167
|
+
map Tree, primary_key_type: :uuid do
|
168
|
+
# ..
|
169
|
+
end
|
170
|
+
|
171
|
+
# Also a UUID v4 id, the Rails Way!
|
172
|
+
map Trunk, id: :uuid do
|
173
|
+
# ..
|
174
|
+
end
|
175
|
+
|
176
|
+
# If you feel the need to specify an auto-incrementing integer id.
|
177
|
+
map Branch, primary_key_type: :serial do
|
178
|
+
# ..
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
167
183
|
## API Documentation
|
168
184
|
|
169
|
-
http://rubydoc.info/github/nulogy/vorpal/
|
185
|
+
http://rubydoc.info/github/nulogy/vorpal/main/frames
|
170
186
|
|
171
187
|
## Caveats
|
172
188
|
It also does not do some things that you might expect from other ORMs:
|
@@ -174,7 +190,7 @@ It also does not do some things that you might expect from other ORMs:
|
|
174
190
|
1. No lazy loading of associations. This might sound like a big deal, but with [correctly designed aggregates](http://dddcommunity.org/library/vernon_2011/) it turns out not to be.
|
175
191
|
1. No managing of transactions. It is the strong opinion of the authors that managing transactions is an application-level concern.
|
176
192
|
1. No support for validations. Validations are not a persistence concern.
|
177
|
-
1. No AR-style callbacks. Use Infrastructure, Application, or Domain
|
193
|
+
1. No AR-style callbacks. Use [Infrastructure, Application, or Domain services](http://martinfowler.com/bliki/EvansClassification.html) instead.
|
178
194
|
1. No has-many-through associations. Use two has-many associations to a join entity instead.
|
179
195
|
1. The `id` attribute is reserved for database primary keys. If you have a natural key/id on your domain model, name it something that makes sense for your domain. It is the strong opinion of the authors that using natural keys as foreign keys is a bad idea. This mixes domain and persistence concerns.
|
180
196
|
|
@@ -183,13 +199,10 @@ It also does not do some things that you might expect from other ORMs:
|
|
183
199
|
1. Only supports PostgreSQL.
|
184
200
|
|
185
201
|
## Future Enhancements
|
186
|
-
*
|
187
|
-
* Support for other DBMSs (no MySQL support until ids can be generated without inserting into a table!)
|
188
|
-
* Support for other ORMs.
|
189
|
-
* Value objects.
|
190
|
-
* Remove dependency on ActiveRecord (optimistic locking? updated_at, created_at support? Data type conversions? TimeZone support?)
|
191
|
-
* More efficient updates (use fewer queries.)
|
202
|
+
* Support for clients to set UUID-based ids.
|
192
203
|
* Nicer DSL for specifying attributes that have different names in the domain model than in the DB.
|
204
|
+
* Aggregate updated_at.
|
205
|
+
* Better support for value objects.
|
193
206
|
|
194
207
|
## FAQ
|
195
208
|
|
@@ -205,11 +218,12 @@ It also does not do some things that you might expect from other ORMs:
|
|
205
218
|
|
206
219
|
**A.** Create a method on a [Repository](http://martinfowler.com/eaaCatalog/repository.html)! They have full access to the DB/ORM so you can use [Arel](https://github.com/rails/arel) and go [crazy](http://asciicasts.com/episodes/239-activerecord-relation-walkthrough) or use direct SQL if you want.
|
207
220
|
|
208
|
-
For example:
|
221
|
+
For example, use the [#query](https://rubydoc.info/github/nulogy/vorpal/main/Vorpal/AggregateMapper#query-instance_method) method on the [AggregateMapper](https://rubydoc.info/github/nulogy/vorpal/main/Vorpal/AggregateMapper) to access the underyling [ActiveRecordRelation](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html):
|
209
222
|
|
210
223
|
```ruby
|
211
|
-
def
|
212
|
-
|
224
|
+
def find_special_ones
|
225
|
+
# use `load_all` or `load_one` to convert from ActiveRecord objects to domain POROs.
|
226
|
+
@mapper.query.where(special: true).load_all
|
213
227
|
end
|
214
228
|
```
|
215
229
|
|
@@ -231,6 +245,10 @@ For example:
|
|
231
245
|
|
232
246
|
**A.** You can use [ActiveModel::Serialization](http://api.rubyonrails.org/classes/ActiveModel/Serialization.html) or [ActiveModel::Serializers](https://github.com/rails-api/active_model_serializers) but they are not heartily recommended. The former is too coupled to the model and the latter is too coupled to Rails controllers. Vorpal uses [SimpleSerializer](https://github.com/nulogy/simple_serializer) for this purpose.
|
233
247
|
|
248
|
+
**Q.** Are `updated_at` and `created_at` supported?
|
249
|
+
|
250
|
+
**A.** Yes. If they exist on your database tables, they will behave exactly as if you were using vanilla ActiveRecord.
|
251
|
+
|
234
252
|
## Contributing
|
235
253
|
|
236
254
|
1. Fork it ( https://github.com/nulogy/vorpal/fork )
|
@@ -239,33 +257,31 @@ For example:
|
|
239
257
|
4. Push to the branch (`git push origin my-new-feature`)
|
240
258
|
5. Create a new Pull Request
|
241
259
|
|
242
|
-
|
243
|
-
|
244
|
-
Using this gem's bin stubs (contained in the `bin` dir) is much easier if [DirEnv](https://github.com/direnv/direnv) is installed.
|
245
|
-
|
246
|
-
On OSX using ZSH DirEnv can be installed like so:
|
247
|
-
|
248
|
-
1. `brew install direnv`
|
249
|
-
2. `echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc`
|
260
|
+
## OSX Environment setup
|
250
261
|
|
251
|
-
|
262
|
+
1. Install [Homebrew](https://brew.sh/)
|
263
|
+
2. Install [rbenv](https://github.com/rbenv/rbenv#installation) ([RVM](https://rvm.io/) can work too)
|
264
|
+
3. Install [DirEnv](https://direnv.net/docs/installation.html) (`brew install direnv`)
|
265
|
+
4. Install Docker Desktop Community Edition (`brew cask install docker`)
|
266
|
+
5. Start Docker Desktop Community Edition (`CMD+space docker ENTER`)
|
267
|
+
6. Install Ruby (`rbenv install 2.7.0`)
|
268
|
+
7. Install PostgreSQL (`brew install postgresql`)
|
269
|
+
8. Clone the repo (`git clone git@github.com:nulogy/vorpal.git`) and `cd` to the project root.
|
270
|
+
8. Copy the contents of `gemfiles/rails_<version>.gemfile.lock` into a `Gemfile.lock` file
|
271
|
+
at the root of the project. (`cp gemfiles/rails_6_0.gemfile.lock gemfile.lock`)
|
272
|
+
9. `bundle`
|
252
273
|
|
253
274
|
### Running Tests
|
254
275
|
|
255
|
-
1. Start a PostgreSQL server
|
256
|
-
|
257
|
-
|
258
|
-
* Modify `spec/helpers/db_helpers.rb`.
|
259
|
-
3. Run `rake` from the terminal.
|
276
|
+
1. Start a PostgreSQL server using `docker-compose up`
|
277
|
+
3. Run `rake` from the terminal to run all specs or `rspec <path to spec file>` to
|
278
|
+
run a single spec.
|
260
279
|
|
261
|
-
### Running Tests for
|
280
|
+
### Running Tests for a specific version of Rails
|
262
281
|
|
263
|
-
1. Start a PostgreSQL server
|
264
|
-
2.
|
265
|
-
|
266
|
-
* Modify `spec/helpers/db_helpers.rb`.
|
267
|
-
3. Run `appraisal <rails version> rake` from the terminal.
|
268
|
-
* Where `<rails version>` is one of the options defined in the `./Appraisal` file.
|
282
|
+
1. Start a PostgreSQL server using `docker-compose up`
|
283
|
+
2. Run `appraisal rails-5-2 rake` from the terminal to run all specs or
|
284
|
+
`appraisal rails-5-2 rspec <path to spec file>` to run a single spec.
|
269
285
|
|
270
286
|
Please see the [Appraisal gem docs](https://github.com/thoughtbot/appraisal) for more information.
|
271
287
|
|
@@ -84,6 +84,17 @@ module Vorpal
|
|
84
84
|
@engine
|
85
85
|
end
|
86
86
|
|
87
|
+
# Returns a 'Vorpal-aware' [ActiveRecord::Relation](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html)
|
88
|
+
# for the ActiveRecord object underlying the domain entity mapped by this mapper.
|
89
|
+
#
|
90
|
+
# This method allows you to easily access the power of ActiveRecord::Relation to do more complex
|
91
|
+
# queries in your repositories.
|
92
|
+
#
|
93
|
+
# The ActiveRecord::Relation is 'Vorpal-aware' because it has the {#load_one} and {#load_many} methods
|
94
|
+
# mixed in so that you can get the POROs from your domain model instead of the ActiveRecord
|
95
|
+
# objects normally returned by ActiveRecord::Relation.
|
96
|
+
#
|
97
|
+
# @return [ActiveRecord::Relation]
|
87
98
|
def query
|
88
99
|
@engine.query(@domain_class)
|
89
100
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'equalizer'
|
2
|
+
|
3
|
+
module Vorpal
|
4
|
+
module Config
|
5
|
+
# @private
|
6
|
+
class ClassConfig
|
7
|
+
include Equalizer.new(:domain_class, :db_class)
|
8
|
+
attr_reader :serializer, :deserializer, :domain_class, :db_class, :primary_key_type, :local_association_configs
|
9
|
+
attr_accessor :has_manys, :belongs_tos, :has_ones
|
10
|
+
|
11
|
+
ALLOWED_PRIMARY_KEY_TYPE_OPTIONS = [:serial, :uuid]
|
12
|
+
|
13
|
+
def initialize(attrs)
|
14
|
+
@has_manys = []
|
15
|
+
@belongs_tos = []
|
16
|
+
@has_ones = []
|
17
|
+
@local_association_configs = []
|
18
|
+
|
19
|
+
@serializer = attrs[:serializer]
|
20
|
+
@deserializer = attrs[:deserializer]
|
21
|
+
@domain_class = attrs[:domain_class]
|
22
|
+
@db_class = attrs[:db_class]
|
23
|
+
@primary_key_type = attrs[:primary_key_type]
|
24
|
+
raise "Invalid primary_key_type: '#{@primary_key_type}'" unless ALLOWED_PRIMARY_KEY_TYPE_OPTIONS.include?(@primary_key_type)
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_db_object(attributes)
|
28
|
+
db_class.new(attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_db_object_attributes(db_object, attributes)
|
32
|
+
db_object.attributes = attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_db_object_attributes(db_object)
|
36
|
+
symbolize_keys(db_object.attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
def serialization_required?
|
40
|
+
domain_class.superclass.name != 'ActiveRecord::Base'
|
41
|
+
end
|
42
|
+
|
43
|
+
def serialize(object)
|
44
|
+
serializer.serialize(object)
|
45
|
+
end
|
46
|
+
|
47
|
+
def deserialize(db_object)
|
48
|
+
attributes = get_db_object_attributes(db_object)
|
49
|
+
serialization_required? ? deserializer.deserialize(domain_class.new, attributes) : db_object
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_attribute(db_object, attribute, value)
|
53
|
+
db_object.send("#{attribute}=", value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_attribute(db_object, attribute)
|
57
|
+
db_object.send(attribute)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def symbolize_keys(hash)
|
63
|
+
result = {}
|
64
|
+
hash.each_key do |key|
|
65
|
+
result[key.to_sym] = hash[key]
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/vorpal/configs.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'vorpal/util/hash_initialization'
|
2
2
|
require 'vorpal/exceptions'
|
3
|
+
require 'vorpal/config/class_config'
|
3
4
|
require 'equalizer'
|
4
5
|
|
5
6
|
module Vorpal
|
6
7
|
# @private
|
7
|
-
class
|
8
|
-
def initialize
|
9
|
-
@class_configs =
|
10
|
-
initialize_association_configs
|
8
|
+
class MainConfig
|
9
|
+
def initialize
|
10
|
+
@class_configs = []
|
11
11
|
end
|
12
12
|
|
13
13
|
def config_for(clazz)
|
@@ -20,7 +20,9 @@ module Vorpal
|
|
20
20
|
@class_configs.detect { |conf| conf.db_class == db_object.class }
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
def add_class_config(class_config)
|
24
|
+
@class_configs << class_config
|
25
|
+
end
|
24
26
|
|
25
27
|
def initialize_association_configs
|
26
28
|
association_configs = {}
|
@@ -50,6 +52,8 @@ module Vorpal
|
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
55
|
+
private
|
56
|
+
|
53
57
|
def build_association_config(association_configs, local_config, fk, fk_type)
|
54
58
|
association_config = AssociationConfig.new(local_config, fk, fk_type)
|
55
59
|
if association_configs[association_config]
|
@@ -126,67 +130,6 @@ module Vorpal
|
|
126
130
|
end
|
127
131
|
end
|
128
132
|
|
129
|
-
# @private
|
130
|
-
class ClassConfig
|
131
|
-
include Equalizer.new(:domain_class, :db_class)
|
132
|
-
attr_reader :serializer, :deserializer, :domain_class, :db_class, :local_association_configs
|
133
|
-
attr_accessor :has_manys, :belongs_tos, :has_ones
|
134
|
-
|
135
|
-
def initialize(attrs)
|
136
|
-
@has_manys = []
|
137
|
-
@belongs_tos = []
|
138
|
-
@has_ones = []
|
139
|
-
@local_association_configs = []
|
140
|
-
|
141
|
-
attrs.each do |k,v|
|
142
|
-
instance_variable_set("@#{k}", v)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def build_db_object(attributes)
|
147
|
-
db_class.new(attributes)
|
148
|
-
end
|
149
|
-
|
150
|
-
def set_db_object_attributes(db_object, attributes)
|
151
|
-
db_object.attributes = attributes
|
152
|
-
end
|
153
|
-
|
154
|
-
def get_db_object_attributes(db_object)
|
155
|
-
symbolize_keys(db_object.attributes)
|
156
|
-
end
|
157
|
-
|
158
|
-
def serialization_required?
|
159
|
-
domain_class.superclass.name != 'ActiveRecord::Base'
|
160
|
-
end
|
161
|
-
|
162
|
-
def serialize(object)
|
163
|
-
serializer.serialize(object)
|
164
|
-
end
|
165
|
-
|
166
|
-
def deserialize(db_object)
|
167
|
-
attributes = get_db_object_attributes(db_object)
|
168
|
-
serialization_required? ? deserializer.deserialize(domain_class.new, attributes) : db_object
|
169
|
-
end
|
170
|
-
|
171
|
-
def set_attribute(db_object, attribute, value)
|
172
|
-
db_object.send("#{attribute}=", value)
|
173
|
-
end
|
174
|
-
|
175
|
-
def get_attribute(db_object, attribute)
|
176
|
-
db_object.send(attribute)
|
177
|
-
end
|
178
|
-
|
179
|
-
private
|
180
|
-
|
181
|
-
def symbolize_keys(hash)
|
182
|
-
result = {}
|
183
|
-
hash.each_key do |key|
|
184
|
-
result[key.to_sym] = hash[key]
|
185
|
-
end
|
186
|
-
result
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
133
|
# @private
|
191
134
|
class ForeignKeyInfo
|
192
135
|
include Equalizer.new(:fk_column, :fk_type_column, :fk_type)
|
@@ -9,7 +9,12 @@ module Vorpal
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def insert(db_class, db_objects)
|
12
|
-
if
|
12
|
+
if ActiveRecord::VERSION::MAJOR >= 6
|
13
|
+
return if db_objects.empty?
|
14
|
+
|
15
|
+
update_timestamps_on_create(db_class, db_objects)
|
16
|
+
db_class.insert_all!(db_objects.map(&:attributes))
|
17
|
+
elsif defined? ActiveRecord::Import
|
13
18
|
db_class.import(db_objects, validate: false)
|
14
19
|
else
|
15
20
|
db_objects.each do |db_object|
|
@@ -19,8 +24,15 @@ module Vorpal
|
|
19
24
|
end
|
20
25
|
|
21
26
|
def update(db_class, db_objects)
|
22
|
-
|
23
|
-
|
27
|
+
if ActiveRecord::VERSION::MAJOR >= 6
|
28
|
+
return if db_objects.empty?
|
29
|
+
|
30
|
+
update_timestamps_on_update(db_class, db_objects)
|
31
|
+
db_class.upsert_all(db_objects.map(&:attributes))
|
32
|
+
else
|
33
|
+
db_objects.each do |db_object|
|
34
|
+
db_object.save!(validate: false)
|
35
|
+
end
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
@@ -100,6 +112,30 @@ module Vorpal
|
|
100
112
|
|
101
113
|
private
|
102
114
|
|
115
|
+
# Adapted from https://github.com/rails/rails/blob/614580270d7789e5275defc3da020ce27b3b2302/activerecord/lib/active_record/timestamp.rb#L99
|
116
|
+
def update_timestamps_on_create(db_class, db_objects)
|
117
|
+
return unless db_class.record_timestamps
|
118
|
+
|
119
|
+
current_time = db_class.current_time_from_proper_timezone
|
120
|
+
db_objects.each do |db_object|
|
121
|
+
db_class.all_timestamp_attributes_in_model.each do |column|
|
122
|
+
db_object.write_attribute(column, current_time) unless db_object.read_attribute(column)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
#Adapted from https://github.com/rails/rails/blob/614580270d7789e5275defc3da020ce27b3b2302/activerecord/lib/active_record/timestamp.rb#L111
|
128
|
+
def update_timestamps_on_update(db_class, db_objects)
|
129
|
+
return unless db_class.record_timestamps
|
130
|
+
|
131
|
+
current_time = db_class.current_time_from_proper_timezone
|
132
|
+
db_objects.each do |db_object|
|
133
|
+
db_class.timestamp_attributes_for_update_in_model.each do |column|
|
134
|
+
db_object.write_attribute(column, current_time)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
103
139
|
def sequence_name(db_class)
|
104
140
|
@sequence_names[db_class] ||= execute(
|
105
141
|
"SELECT substring(column_default from '''(.*)''') FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1 AND column_name = 'id' LIMIT 1",
|