jet_set 0.4.0 → 0.5.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 +4 -4
- data/README.md +35 -2
- data/jet_set.gemspec +7 -7
- data/lib/jet_set/entity_builder.rb +2 -0
- data/lib/jet_set/mapper.rb +4 -2
- data/lib/jet_set/mixin/entity.rb +4 -0
- data/lib/jet_set/session.rb +9 -3
- data/lib/jet_set/validation_definition_error.rb +4 -0
- data/lib/jet_set/validation_error.rb +10 -0
- data/lib/jet_set/validations.rb +89 -0
- data/lib/jet_set/version.rb +1 -1
- data/lib/jet_set.rb +3 -0
- metadata +24 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41fe70bc858f2949d8cf010b6af40066a84bdfdf481f0fef13dfdb49fca1de46
|
4
|
+
data.tar.gz: 02c77cd6a4741a0be81caa52e3c3b63b75722cddffbd289497a194701d60c447
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99ca355278cad5427c3b69228806f7405e4725a2d2acf1c5902fdf488a7e2acf5a29ee509e93ace75cdae86ba6a596fa79493d848b62acff90977cf00a04e864
|
7
|
+
data.tar.gz: 4008d0a706a8c416d7958c4276b3a494f5190a41df6fc4d4e69b669edf9d5e2f97d4dda73091a3692659a526da060aead126b4c44c747b368bbfa1162c857d2d
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ Open DB connection, see [Sequel docs](https://sequel.jeremyevans.net/rdoc/files/
|
|
28
28
|
@connection = Sequel.connect('sqlite:/') # you can connect to any DB supported by Sequel
|
29
29
|
```
|
30
30
|
|
31
|
-
Create a mapping of your model,
|
31
|
+
Create a mapping of your model, details described [here]:
|
32
32
|
```ruby
|
33
33
|
class Mapping
|
34
34
|
def self.load_mapping
|
@@ -137,8 +137,41 @@ json = JSON.generate(data: result)
|
|
137
137
|
In other words, following [CQS](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) approach you can
|
138
138
|
load your model for a command but not for a query.
|
139
139
|
|
140
|
+
### Validation
|
141
|
+
Simple validation is optional feature provided by JetSet out of the box. To add this to your domain object you just need
|
142
|
+
to include module `JetSet::Validations` and use `validate` statements:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
require 'jet_set/validations'
|
146
|
+
|
147
|
+
class User
|
148
|
+
include JetSet::Validations
|
149
|
+
validate :name, 'cannot be empty', -> (value) {!value.nil? && !value.empty?}
|
150
|
+
validate :email, type: :string, presence: true
|
151
|
+
validate :email, 'should be valid email address', -> (value) {value.match(...)}
|
152
|
+
|
153
|
+
def initialize(attrs = {})
|
154
|
+
@name = attrs[:name]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
158
|
+
JetSet uses such validations automatically on saving objects in the database. Also you can invoke validation manually,
|
159
|
+
i.e. in unit tests, using `validate!` method:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
user = User.new(name: nil)
|
163
|
+
user.validate! # raises JetSet::ValidationError
|
164
|
+
```
|
165
|
+
|
166
|
+
`JetSet::ValidationError` contains details regarding invalid items like:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
error.invalid_items # => {name: 'cannot be empty'}
|
170
|
+
```
|
171
|
+
|
172
|
+
|
173
|
+
|
140
174
|
You can find more interesting examples in [JetSet integration tests](https://github.com/cylon-v/jet_set/tree/master/spec/integration).
|
141
|
-
Also for the details please visit our [wiki].
|
142
175
|
|
143
176
|
## Development
|
144
177
|
|
data/jet_set.gemspec
CHANGED
@@ -30,11 +30,11 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
31
|
spec.require_paths = ['lib']
|
32
32
|
|
33
|
-
spec.add_dependency 'sequel', '
|
34
|
-
spec.add_dependency 'hypo', '
|
35
|
-
spec.add_development_dependency 'bundler', '
|
36
|
-
spec.add_development_dependency 'rake', '
|
37
|
-
spec.add_development_dependency 'rspec', '
|
38
|
-
spec.add_development_dependency 'sqlite3', '
|
39
|
-
spec.add_development_dependency 'simplecov', '
|
33
|
+
spec.add_dependency 'sequel', '>= 5.4.0'
|
34
|
+
spec.add_dependency 'hypo', '>= 1.0.0'
|
35
|
+
spec.add_development_dependency 'bundler', '>= 2.1'
|
36
|
+
spec.add_development_dependency 'rake', '>= 10.0'
|
37
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
38
|
+
spec.add_development_dependency 'sqlite3', '>= 1.3'
|
39
|
+
spec.add_development_dependency 'simplecov', '>= 0.16'
|
40
40
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'jet_set/mixin/identity'
|
2
2
|
require 'jet_set/mixin/entity'
|
3
|
+
require 'jet_set/validations'
|
3
4
|
|
4
5
|
module JetSet
|
5
6
|
# A converter of a pure Ruby object to JetSet trackable object.
|
@@ -22,6 +23,7 @@ module JetSet
|
|
22
23
|
|
23
24
|
object.extend(Identity)
|
24
25
|
object.extend(Entity)
|
26
|
+
object.extend(Validations)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
data/lib/jet_set/mapper.rb
CHANGED
@@ -15,7 +15,8 @@ module JetSet
|
|
15
15
|
@container = container
|
16
16
|
|
17
17
|
@mapping.entity_mappings.values.each do |entity_mapping|
|
18
|
-
|
18
|
+
entity_name = "jet_set__#{entity_mapping.type.name.underscore}".to_sym
|
19
|
+
container.register(entity_mapping.type, entity_name)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -29,6 +30,7 @@ module JetSet
|
|
29
30
|
# "SELECT u.name AS customer__name from users u"
|
30
31
|
def map(type, row_hash, session, prefix = type.name.underscore)
|
31
32
|
entity_name = type.name.underscore.to_sym
|
33
|
+
resolve_name = "jet_set__#{type.name.underscore}".to_sym
|
32
34
|
entity_mapping = @mapping.get(entity_name)
|
33
35
|
row = Row.new(row_hash, entity_mapping.fields, prefix)
|
34
36
|
|
@@ -43,7 +45,7 @@ module JetSet
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
|
-
object = @container.resolve(
|
48
|
+
object = @container.resolve(resolve_name, row.attributes_hash.merge(reference_hash))
|
47
49
|
entity = @entity_builder.create(object)
|
48
50
|
entity.load_attributes!(row.attributes)
|
49
51
|
|
data/lib/jet_set/mixin/entity.rb
CHANGED
@@ -77,6 +77,8 @@ module JetSet
|
|
77
77
|
# Parameters:
|
78
78
|
# +sequel+:: Sequel sequel
|
79
79
|
def flush(sequel)
|
80
|
+
validate! if respond_to? :validate!
|
81
|
+
|
80
82
|
table_name = self.class.name.underscore.pluralize.to_sym
|
81
83
|
table = sequel[table_name]
|
82
84
|
entity_name = self.class.name.underscore.to_sym
|
@@ -113,12 +115,14 @@ module JetSet
|
|
113
115
|
values << value.instance_variable_get('@id')
|
114
116
|
end
|
115
117
|
end
|
118
|
+
|
116
119
|
new_id = table.insert(fields, values)
|
117
120
|
@__attributes['@id'] = Attribute.new('@id', new_id)
|
118
121
|
@id = new_id
|
119
122
|
elsif dirty?
|
120
123
|
attributes = {}
|
121
124
|
dirty_attributes.each {|attribute| attributes[attribute.name.sub('@', '')] = instance_variable_get(attribute.name)}
|
125
|
+
|
122
126
|
if attributes.keys.length > 0
|
123
127
|
table.where(id: @id).update(attributes)
|
124
128
|
end
|
data/lib/jet_set/session.rb
CHANGED
@@ -103,9 +103,15 @@ module JetSet
|
|
103
103
|
dirty_objects = @objects.select {|object| object.dirty?}
|
104
104
|
ordered_objects = @dependency_graph.order(dirty_objects)
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
begin
|
107
|
+
if ordered_objects.length > 0
|
108
|
+
@sequel.transaction do
|
109
|
+
ordered_objects.each{|obj| obj.flush(@sequel)}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
ensure
|
113
|
+
@mutex.synchronize do
|
114
|
+
@objects = []
|
109
115
|
end
|
110
116
|
end
|
111
117
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'jet_set/validation_error'
|
2
|
+
|
3
|
+
module JetSet
|
4
|
+
# Optional validation decorator. Adds validation logic to pure Ruby objects.
|
5
|
+
module Validations
|
6
|
+
# The method runs all validations declared in the model
|
7
|
+
def validate!
|
8
|
+
validations = self.class.class_variable_defined?(:@@validations) ? self.class.class_variable_get(:@@validations) : {}
|
9
|
+
attributes = validations.keys
|
10
|
+
invalid_items = []
|
11
|
+
|
12
|
+
attributes.each do |attribute|
|
13
|
+
attribute_validations = validations[attribute] || []
|
14
|
+
|
15
|
+
error = nil
|
16
|
+
attribute_validations.each do |validation|
|
17
|
+
value = instance_variable_get("@#{attribute}")
|
18
|
+
if validation[:func].call(value) == false
|
19
|
+
error = validation[:message]
|
20
|
+
break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
invalid_items << {"#{attribute}": error} if error
|
24
|
+
end
|
25
|
+
|
26
|
+
raise ValidationError.new("#{self.class.name} is invalid", invalid_items) if invalid_items.length > 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.included(base)
|
30
|
+
base.extend(ClassMethods)
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
# Adds a validation to an attribute of the entity
|
35
|
+
# Parameters:
|
36
|
+
# +attribute_name+:: +Symbol+ attribute name
|
37
|
+
# +options+ || +message+:: validation options {type, presence, message, custom} or just a message
|
38
|
+
# +func+:: boolean proc with a check for validity
|
39
|
+
def validate(attribute_name, options, func = nil)
|
40
|
+
validations = self.class_variable_defined?(:@@validations) ? self.class_variable_get(:@@validations) : {}
|
41
|
+
validations[attribute_name] ||= []
|
42
|
+
|
43
|
+
if options.is_a?(Hash)
|
44
|
+
if options.has_key?(:type)
|
45
|
+
validations[attribute_name] << validate_type(options[:type])
|
46
|
+
end
|
47
|
+
|
48
|
+
if options[:presence] == true
|
49
|
+
validations[attribute_name] << validate_presence
|
50
|
+
end
|
51
|
+
|
52
|
+
message = options[:message]
|
53
|
+
elsif options.is_a?(String)
|
54
|
+
message = options
|
55
|
+
else
|
56
|
+
raise ValidationDefinitionError, "Validation definition of attribute #{attribute_name} is incorrect."
|
57
|
+
end
|
58
|
+
|
59
|
+
func ||= options[:custom]
|
60
|
+
|
61
|
+
unless func.nil?
|
62
|
+
validations[attribute_name] << {func: func, message: message}
|
63
|
+
end
|
64
|
+
|
65
|
+
self.class_variable_set(:@@validations, validations)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def validate_presence
|
71
|
+
{message: 'cannot be blank', func: -> (value) {!value.nil? && value != ''}}
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_type(type)
|
75
|
+
unless [:numeric, :string, :boolean].include?(type)
|
76
|
+
raise ValidationDefinitionError, "the type should be :numeric, :string or :boolean"
|
77
|
+
end
|
78
|
+
|
79
|
+
checks = {
|
80
|
+
numeric: -> (value) {value.is_a?(Numeric)},
|
81
|
+
string: -> (value) {value.is_a?(String)},
|
82
|
+
boolean: -> (value) {!!value == value}
|
83
|
+
}
|
84
|
+
|
85
|
+
{message: "should be #{type}", func: -> (value) {value.nil? || checks[type].call(value)}}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/jet_set/version.rb
CHANGED
data/lib/jet_set.rb
CHANGED
@@ -3,6 +3,9 @@ require 'sequel'
|
|
3
3
|
require 'sequel/extensions/inflector'
|
4
4
|
require 'jet_set/environment'
|
5
5
|
require 'jet_set/mapping'
|
6
|
+
require 'jet_set/validations'
|
7
|
+
require 'jet_set/validation_error'
|
8
|
+
require 'jet_set/validation_definition_error'
|
6
9
|
require 'jet_set/version'
|
7
10
|
|
8
11
|
module JetSet
|
metadata
CHANGED
@@ -1,111 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jet_set
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Kalinkin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 5.4.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 5.4.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: hypo
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 1.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 1.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1
|
47
|
+
version: '2.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1
|
54
|
+
version: '2.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '10.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '3.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: sqlite3
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.3'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.3'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: simplecov
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0.16'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0.16'
|
111
111
|
description: ''
|
@@ -143,6 +143,9 @@ files:
|
|
143
143
|
- lib/jet_set/reference.rb
|
144
144
|
- lib/jet_set/row.rb
|
145
145
|
- lib/jet_set/session.rb
|
146
|
+
- lib/jet_set/validation_definition_error.rb
|
147
|
+
- lib/jet_set/validation_error.rb
|
148
|
+
- lib/jet_set/validations.rb
|
146
149
|
- lib/jet_set/version.rb
|
147
150
|
homepage: https://github.com/cylon-v/jet_set
|
148
151
|
licenses:
|
@@ -164,8 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
167
|
- !ruby/object:Gem::Version
|
165
168
|
version: '0'
|
166
169
|
requirements: []
|
167
|
-
|
168
|
-
rubygems_version: 2.7.7
|
170
|
+
rubygems_version: 3.1.2
|
169
171
|
signing_key:
|
170
172
|
specification_version: 4
|
171
173
|
summary: JetSet is a microscopic ORM for DDD projects.
|