jet_set 0.3.2 → 0.4.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 +5 -5
- data/Gemfile +0 -1
- data/README.md +120 -5
- data/jet_set.gemspec +1 -2
- data/lib/jet_set/mapper.rb +10 -4
- data/lib/jet_set/mixin/entity.rb +1 -1
- data/lib/jet_set/row.rb +6 -1
- data/lib/jet_set/session.rb +6 -3
- data/lib/jet_set/version.rb +1 -1
- metadata +5 -6
- data/test.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4c2b21527242c8574e604c1ece2b26ec71d59c7712b76cdfa9e88fdc6a47265b
|
4
|
+
data.tar.gz: bdcba0c32be1c7db5a0b63f206dd7c5e354c30a9af14eb1b0b204a55ea4ce349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6e155d9e2c20157beb3689764a42f8618159fb443b11c41d2ae81a5405fc3fadb55e31a562fcbf58fb0e06a78bf8611ea10eb36378c2b14e4c3e59c6e5b409b
|
7
|
+
data.tar.gz: 076a5aa11cb87fa6773faca5d3b92e218e5e939a6808d1825486c8cc1c8428cbeb1b480fe152f69a3e6f09b9f5431b4ebbec70873c567a44e91c6439f8150120
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# JetSet 
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
JetSet is a data mapping framework for domain-driven developers who think that SQL is the best tool for data querying.
|
4
|
+
JetSet is built on top of [Sequel](https://github.com/jeremyevans/sequel) ORM and it's just an abstraction for making
|
5
|
+
the persistence of mapped objects invisible.
|
7
6
|
|
8
7
|
## Installation
|
9
8
|
|
@@ -23,7 +22,123 @@ Or install it yourself as:
|
|
23
22
|
|
24
23
|
## Usage
|
25
24
|
|
26
|
-
|
25
|
+
### Initialization
|
26
|
+
Open DB connection, see [Sequel docs](https://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html):
|
27
|
+
```ruby
|
28
|
+
@connection = Sequel.connect('sqlite:/') # you can connect to any DB supported by Sequel
|
29
|
+
```
|
30
|
+
|
31
|
+
Create a mapping of your model, a details described [here]:
|
32
|
+
```ruby
|
33
|
+
class Mapping
|
34
|
+
def self.load_mapping
|
35
|
+
JetSet::map do
|
36
|
+
entity User do
|
37
|
+
field :first_name # reqular field
|
38
|
+
collection :invoices, type: Invoice # "has many" association
|
39
|
+
reference :plan, type: Plan, weak: true # "belongs to" association
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
Init JetSet environment on start of your application:
|
47
|
+
```ruby
|
48
|
+
JetSet::init(Mapping.load_mapping, @container)
|
49
|
+
```
|
50
|
+
|
51
|
+
Open JetSet session:
|
52
|
+
```ruby
|
53
|
+
@jet_set = JetSet::open_session(@connection)
|
54
|
+
```
|
55
|
+
For web-applications it's reasonable to bind JetSet session to request lifetime -
|
56
|
+
all modification operations in an MVC action can represent a ["Unit of Work"](https://martinfowler.com/eaaCatalog/unitOfWork.html).
|
57
|
+
|
58
|
+
### Object model
|
59
|
+
Using JetSet you can wrap an application domain model and purely implement "Persistence Ignorance" approach.
|
60
|
+
The model objects are pure Ruby objects without any noisy stuff like annotations, inline mapping, etc:
|
61
|
+
```ruby
|
62
|
+
class User
|
63
|
+
attr_reader :invoices
|
64
|
+
|
65
|
+
def initialize(attrs = {})
|
66
|
+
@first_name = attrs[:first_name]
|
67
|
+
@last_name = attrs[:last_name]
|
68
|
+
@invoices = []
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_invoice(invoice)
|
72
|
+
@invoices << invoice
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Invoice
|
77
|
+
attr_reader :created_at, :amount
|
78
|
+
|
79
|
+
def initialize(attrs = {})
|
80
|
+
@created_at = DateTime.now
|
81
|
+
@amount = attrs[:amount] || 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### Object model tracking and saving
|
87
|
+
Create an objects which is described in the mapping:
|
88
|
+
```ruby
|
89
|
+
user = User.new(first_name: 'Ivan', last_name: 'Ivanov')
|
90
|
+
invoice = Invoice.new(created_at: DateTime.now, user: user, amount: 100.0)
|
91
|
+
```
|
92
|
+
|
93
|
+
Attach them to the session:
|
94
|
+
```ruby
|
95
|
+
@session.attach(invoice, user)
|
96
|
+
```
|
97
|
+
It makes the objects tracked by JetSet.
|
98
|
+
|
99
|
+
Finalize the session:
|
100
|
+
```ruby
|
101
|
+
@session.finalize
|
102
|
+
```
|
103
|
+
It saves all added/changed objects to the database.
|
104
|
+
|
105
|
+
### Object model loading
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
user_query = <<~SQL
|
109
|
+
SELECT
|
110
|
+
u.* AS ENTITY user
|
111
|
+
FROM users u
|
112
|
+
LIMIT 1
|
113
|
+
SQL
|
114
|
+
|
115
|
+
invoices_sql = <<~SQL
|
116
|
+
SELECT
|
117
|
+
i.* AS ENTITY invoice
|
118
|
+
WHERE i.user_id = :user_id
|
119
|
+
SQL
|
120
|
+
|
121
|
+
customer = @session.fetch(User, user_query) do |user|
|
122
|
+
preload(user, :invoices, invoices_sql, user_id: user.id)
|
123
|
+
end
|
124
|
+
```
|
125
|
+
All loaded objects are already attached to the session and you can perform a changes which will be saved after the session finalization:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
customer.invoices[0].apply # changes invoice state
|
129
|
+
@session.finalize
|
130
|
+
```
|
131
|
+
|
132
|
+
Do not load your object model just for drawing a views. For showing a results just use Sequel without any object mappings:
|
133
|
+
```ruby
|
134
|
+
result = @connection[:user].where(role: 'admin').to_a
|
135
|
+
json = JSON.generate(data: result)
|
136
|
+
```
|
137
|
+
In other words, following [CQS](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) approach you can
|
138
|
+
load your model for a command but not for a query.
|
139
|
+
|
140
|
+
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].
|
27
142
|
|
28
143
|
## Development
|
29
144
|
|
data/jet_set.gemspec
CHANGED
@@ -31,8 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.require_paths = ['lib']
|
32
32
|
|
33
33
|
spec.add_dependency 'sequel', '~> 5.4.0'
|
34
|
-
spec.add_dependency 'hypo', '~> 0.
|
35
|
-
|
34
|
+
spec.add_dependency 'hypo', '~> 0.10.0'
|
36
35
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
37
36
|
spec.add_development_dependency 'rake', '~> 10.0'
|
38
37
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
data/lib/jet_set/mapper.rb
CHANGED
@@ -31,20 +31,26 @@ module JetSet
|
|
31
31
|
entity_name = type.name.underscore.to_sym
|
32
32
|
entity_mapping = @mapping.get(entity_name)
|
33
33
|
row = Row.new(row_hash, entity_mapping.fields, prefix)
|
34
|
-
object = @container.resolve(entity_name)
|
35
|
-
entity = @entity_builder.create(object)
|
36
|
-
entity.load_attributes!(row.attributes)
|
37
34
|
|
35
|
+
reference_hash = {}
|
38
36
|
row.reference_names.each do |reference_name|
|
39
37
|
if entity_mapping.references.key? reference_name.to_sym
|
40
38
|
reference_id_name = reference_name + '__id'
|
41
39
|
unless row_hash[reference_id_name.to_sym].nil?
|
42
40
|
type = entity_mapping.references[reference_name.to_sym].type
|
43
|
-
|
41
|
+
reference_hash[reference_name.to_sym] = map(type, row_hash, session, reference_name)
|
44
42
|
end
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
46
|
+
object = @container.resolve(entity_name, row.attributes_hash.merge(reference_hash))
|
47
|
+
entity = @entity_builder.create(object)
|
48
|
+
entity.load_attributes!(row.attributes)
|
49
|
+
|
50
|
+
reference_hash.each do |key, value|
|
51
|
+
entity.set_reference! key.to_s, value
|
52
|
+
end
|
53
|
+
|
48
54
|
session.attach(entity)
|
49
55
|
entity
|
50
56
|
end
|
data/lib/jet_set/mixin/entity.rb
CHANGED
@@ -6,7 +6,7 @@ module JetSet
|
|
6
6
|
module Entity
|
7
7
|
# Loads the entity attributes.
|
8
8
|
# Parameters:
|
9
|
-
# +attributes+::
|
9
|
+
# +attributes+:: an array of key-pairs in format :field => :value
|
10
10
|
def load_attributes!(attributes)
|
11
11
|
attributes.each do |attribute|
|
12
12
|
name = "@#{attribute[:field]}"
|
data/lib/jet_set/row.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module JetSet
|
2
2
|
# A container for fields/references extraction logic
|
3
3
|
class Row
|
4
|
-
attr_reader :attributes, :reference_names
|
4
|
+
attr_reader :attributes, :attributes_hash, :reference_names
|
5
5
|
|
6
6
|
def initialize(row_hash, entity_fields, prefix)
|
7
7
|
keys = row_hash.keys.map {|key| key.to_s}
|
@@ -10,6 +10,11 @@ module JetSet
|
|
10
10
|
.select {|key| entity_fields.include? key.sub(prefix + '__', '')}
|
11
11
|
.map {|key| {field: key.sub(prefix + '__', ''), value: row_hash[key.to_sym]}}
|
12
12
|
|
13
|
+
@attributes_hash = {}
|
14
|
+
@attributes.each do |attr|
|
15
|
+
@attributes_hash[attr[:field].to_sym] = attr[:value]
|
16
|
+
end
|
17
|
+
|
13
18
|
@reference_names = keys.select {|key| !key.start_with?(prefix) && key.include?('__')}
|
14
19
|
.map {|key| key.split('__')[0]}
|
15
20
|
.uniq
|
data/lib/jet_set/session.rb
CHANGED
@@ -14,6 +14,7 @@ module JetSet
|
|
14
14
|
@query_parser = query_parser
|
15
15
|
@entity_builder = entity_builder
|
16
16
|
@dependency_graph = dependency_graph
|
17
|
+
@mutex = Mutex.new
|
17
18
|
end
|
18
19
|
|
19
20
|
# Fetches root entity using a result of +execute+ method.
|
@@ -87,9 +88,11 @@ module JetSet
|
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
91
|
+
@mutex.synchronize do
|
92
|
+
to_attach.each do |object|
|
93
|
+
obj = object.kind_of?(Entity) ? object : @entity_builder.create(object)
|
94
|
+
@objects << obj
|
95
|
+
end
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
data/lib/jet_set/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jet_set
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.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: 2018-
|
11
|
+
date: 2018-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.10.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: 0.10.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,7 +144,6 @@ files:
|
|
144
144
|
- lib/jet_set/row.rb
|
145
145
|
- lib/jet_set/session.rb
|
146
146
|
- lib/jet_set/version.rb
|
147
|
-
- test.rb
|
148
147
|
homepage: https://github.com/cylon-v/jet_set
|
149
148
|
licenses:
|
150
149
|
- MIT
|
@@ -166,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
165
|
version: '0'
|
167
166
|
requirements: []
|
168
167
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.
|
168
|
+
rubygems_version: 2.7.7
|
170
169
|
signing_key:
|
171
170
|
specification_version: 4
|
172
171
|
summary: JetSet is a microscopic ORM for DDD projects.
|