datamappify 0.10.1 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +11 -0
- data/README.md +55 -29
- data/datamappify.gemspec +4 -4
- data/lib/datamappify/data/errors.rb +3 -0
- data/lib/datamappify/data/provider/active_record/persistence.rb +31 -0
- data/lib/datamappify/data/provider/active_record.rb +16 -0
- data/lib/datamappify/data/provider/common/persistence.rb +57 -0
- data/lib/datamappify/data/provider/common/relational/persistence.rb +85 -0
- data/lib/datamappify/data/provider/common/relational/record/mapper.rb +24 -0
- data/lib/datamappify/data/provider/common/relational/record/writer.rb +67 -0
- data/lib/datamappify/data/provider/sequel/persistence.rb +31 -0
- data/lib/datamappify/data/provider/sequel.rb +18 -0
- data/lib/datamappify/data.rb +0 -1
- data/lib/datamappify/repository/attribute_source_data_class_builder.rb +16 -11
- data/lib/datamappify/repository/attributes_mapper.rb +17 -13
- data/lib/datamappify/repository/dsl.rb +9 -0
- data/lib/datamappify/repository/mapping_hash.rb +8 -0
- data/lib/datamappify/repository.rb +96 -4
- data/lib/datamappify/util.rb +13 -0
- data/lib/datamappify/version.rb +1 -1
- data/spec/entity_spec.rb +9 -8
- data/spec/repository/persistence_spec.rb +156 -56
- data/spec/repository_spec.rb +10 -33
- data/spec/spec_helper.rb +14 -8
- data/spec/support/entities/hero_user.rb +11 -0
- data/spec/support/entities/user.rb +5 -5
- data/spec/support/repositories/active_record/comment_repository.rb +6 -0
- data/spec/support/repositories/active_record/group_repository.rb +6 -0
- data/spec/support/repositories/active_record/role_repository.rb +6 -0
- data/spec/support/repositories/active_record/user_repository.rb +11 -0
- data/spec/support/repositories/hero_user_repository.rb +9 -0
- data/spec/support/repositories/sequel/comment_repository.rb +6 -0
- data/spec/support/repositories/sequel/group_repository.rb +6 -0
- data/spec/support/repositories/sequel/role_repository.rb +6 -0
- data/spec/support/repositories/sequel/user_repository.rb +11 -0
- data/spec/support/{active_record_tables.rb → tables/active_record.rb} +15 -9
- data/spec/support/tables/sequel.rb +76 -0
- metadata +64 -41
- data/lib/datamappify/data/base.rb +0 -7
- data/lib/datamappify/repository/persistence.rb +0 -137
- data/spec/support/repositories/comment_repository.rb +0 -7
- data/spec/support/repositories/group_repository.rb +0 -7
- data/spec/support/repositories/role_repository.rb +0 -7
- data/spec/support/repositories/user_repository.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 657efe5662156ed237a7ff2a7abf02304ea48053
|
4
|
+
data.tar.gz: a5a1ab8c879d4948099679cdc12276970e80f8f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d0fdeabfd8ba423d31bc70b7948c28419a10ae635e0189aa0e70be80db3c39a850532b2135c83c1df574204b0d7e48d84a67bd207e57ab7a3a150a7e0949869
|
7
|
+
data.tar.gz: b7ee5ed125413a9a5207355c018450d2440d738bc5fa9438a648c38848070eb708b28b5716b3f8f860ea21e4053a60cb803271323e430ccc9fcfa5bb3aa18476
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --order random
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## master
|
2
2
|
|
3
|
+
## 0.20.0 [2013-03-19]
|
4
|
+
|
5
|
+
- __Completely rewritten Repository__
|
6
|
+
- Repository now handles data construction from different ORM objects
|
7
|
+
- ActiveRecord has now been demoted to being a data provider, it is no longer tightly coupled with Repository, this means __we could have multiple data providers__!
|
8
|
+
- Repository is now much more robust
|
9
|
+
- As a result of robustness, it fixed an issue where updating an existing entity with new data records from mapped attributes will not persist the new data records correctly
|
10
|
+
- `#save` and `#destroy` now support accepting an array as their argument
|
11
|
+
- Added support for Sequel!
|
12
|
+
- Added support for mapping entity attributes to different ORMs!
|
13
|
+
|
3
14
|
## 0.10.1 [2013-03-16]
|
4
15
|
|
5
16
|
- Fixed `#save` for creating new objects.
|
data/README.md
CHANGED
@@ -1,24 +1,20 @@
|
|
1
|
-
# Datamappify [![Gem Version](https://badge.fury.io/rb/datamappify.png)](http://badge.fury.io/rb/datamappify) [![Build Status](https://api.travis-ci.org/fredwu/datamappify.png)](http://travis-ci.org/fredwu/datamappify) [![Code Climate](https://codeclimate.com/github/fredwu/datamappify.png)](https://codeclimate.com/github/fredwu/datamappify)
|
1
|
+
# Datamappify [![Gem Version](https://badge.fury.io/rb/datamappify.png)](http://badge.fury.io/rb/datamappify) [![Build Status](https://api.travis-ci.org/fredwu/datamappify.png)](http://travis-ci.org/fredwu/datamappify) [![Coverage Status](https://coveralls.io/repos/fredwu/datamappify/badge.png)](https://coveralls.io/r/fredwu/datamappify) [![Code Climate](https://codeclimate.com/github/fredwu/datamappify.png)](https://codeclimate.com/github/fredwu/datamappify)
|
2
2
|
|
3
3
|
Separate domain logic from data persistence, based on the [Repository Pattern](http://martinfowler.com/eaaCatalog/repository.html).
|
4
4
|
|
5
|
-
|
5
|
+
Datamappify is NOT associated with the [Datamapper](https://github.com/datamapper/) project.
|
6
|
+
|
7
|
+
__Datamappify is current in Proof-of-Concept stage, do NOT use it for anything other than experimentation.__
|
6
8
|
|
7
9
|
## Overview
|
8
10
|
|
9
|
-
Datamappify is a thin layer on top of
|
11
|
+
Datamappify is a thin layer on top of [Virtus](https://github.com/solnic/virtus) and existing ORMs (ActiveRecord, etc). The design goal is to utilise the powerfulness of existing ORMs but separate domain logic (behaviour) from data persistence.
|
10
12
|
|
11
13
|
Datamappify consists of three components:
|
12
14
|
|
13
|
-
-
|
14
|
-
-
|
15
|
-
-
|
16
|
-
|
17
|
-
__Entity__ is your model, it is responsible for mainly storing behaviour. Some structure (i.e. model relationships) is also stored here for convenience.
|
18
|
-
|
19
|
-
__Data__ as the name suggests, holds your model data. It is an ActiveRecord object.
|
20
|
-
|
21
|
-
__Repository__ is responsible for data retrieval and persistence, e.g. `find`, `save` and `destroy`, etc.
|
15
|
+
- __Entity__ is your model, it is responsible for mainly storing behaviour.
|
16
|
+
- __Data__ as the name suggests, holds your model data. It is an ActiveRecord object.
|
17
|
+
- __Repository__ is responsible for data retrieval and persistence, e.g. `find`, `save` and `destroy`, etc.
|
22
18
|
|
23
19
|
## Installation
|
24
20
|
|
@@ -38,15 +34,18 @@ Or install it yourself as:
|
|
38
34
|
|
39
35
|
### Entity
|
40
36
|
|
37
|
+
Entity uses [Virtus](https://github.com/solnic/virtus) DSL for defining attributes and [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations.html) DSL for validations.
|
38
|
+
|
41
39
|
```ruby
|
42
40
|
class User
|
43
41
|
include Datamappify::Entity
|
44
42
|
|
45
|
-
attribute :first_name,
|
46
|
-
attribute :last_name,
|
47
|
-
attribute :
|
48
|
-
attribute :
|
49
|
-
attribute :
|
43
|
+
attribute :first_name, String
|
44
|
+
attribute :last_name, String
|
45
|
+
attribute :age, Integer
|
46
|
+
attribute :passport, String
|
47
|
+
attribute :driver_license, String
|
48
|
+
attribute :health_care, String
|
50
49
|
|
51
50
|
validates :first_name, :presence => true,
|
52
51
|
:length => { :minimum => 2 }
|
@@ -61,6 +60,8 @@ end
|
|
61
60
|
|
62
61
|
### Repository
|
63
62
|
|
63
|
+
Map entity attributes to DB columns - better yet, you can even map attributes to __different ORMs__!
|
64
|
+
|
64
65
|
```ruby
|
65
66
|
class UserRepository
|
66
67
|
include Datamappify::Repository
|
@@ -68,39 +69,63 @@ class UserRepository
|
|
68
69
|
# specify the entity class
|
69
70
|
for_entity User
|
70
71
|
|
72
|
+
# specify the default data provider for unmapped attributes
|
73
|
+
default_provider :ActiveRecord
|
74
|
+
|
71
75
|
# specify any attributes that need to be mapped
|
72
76
|
#
|
73
77
|
# for example:
|
74
|
-
# - '
|
75
|
-
# - '
|
76
|
-
# -
|
77
|
-
|
78
|
-
map_attribute :
|
78
|
+
# - 'last_name' is mapped to the 'User' ActiveRecord class and its 'surname' attribute
|
79
|
+
# - 'driver_license' is mapped to the 'UserDriverLicense' ActiveRecord class and its 'number' attribute
|
80
|
+
# - 'passport' is mapped to the 'UserPassport' Sequel class and its 'number' attribute
|
81
|
+
# - attributes not specified here are mapped automatically to 'ActiveRecord::User'
|
82
|
+
map_attribute :last_name, 'ActiveRecord::User#surname'
|
83
|
+
map_attribute :driver_license, 'ActiveRecord::UserDriverLicense#number'
|
84
|
+
map_attribute :passport, 'Sequel::UserPassport#number'
|
85
|
+
map_attribute :health_care, 'Sequel::UserHealthCare#number'
|
79
86
|
end
|
80
|
-
|
81
|
-
user_repository = UserRepository.instance
|
82
87
|
```
|
83
88
|
|
84
|
-
#### Retrieving
|
89
|
+
#### Retrieving entities
|
90
|
+
|
91
|
+
Pass in an id or an array of ids.
|
85
92
|
|
86
93
|
```ruby
|
87
|
-
user
|
94
|
+
user = UserRepository.instance.find(1)
|
95
|
+
users = UserRepository.instance.find([1, 2, 3])
|
88
96
|
```
|
89
97
|
|
90
|
-
#### Saving/updating
|
98
|
+
#### Saving/updating entities
|
99
|
+
|
100
|
+
Pass in an entity or an array of entities.
|
101
|
+
|
102
|
+
There is also `save!` that raises `Datamappify::Data::EntityNotSaved`.
|
91
103
|
|
92
104
|
```ruby
|
93
|
-
|
105
|
+
UserRepository.instance.save(user)
|
106
|
+
UserRepository.instance.save([user, user2, user3])
|
94
107
|
```
|
95
108
|
|
96
109
|
#### Destroying an entity
|
97
110
|
|
111
|
+
Pass in an entity, an id, an array of entities or an array of ids.
|
112
|
+
|
113
|
+
There is also `destroy!` that raises `Datamappify::Data::EntityNotDestroyed`.
|
114
|
+
|
98
115
|
Note that due to the attributes mapping, any data found in mapped ActiveRecord objects are not touched.
|
99
116
|
|
100
117
|
```ruby
|
101
|
-
|
118
|
+
UserRepository.instance.destroy(1)
|
119
|
+
UserRepository.instance.destroy([1, 2, 3])
|
120
|
+
UserRepository.instance.destroy(user)
|
121
|
+
UserRepository.instance.destroy([user, user2, user3])
|
102
122
|
```
|
103
123
|
|
124
|
+
## Supported ORMs
|
125
|
+
|
126
|
+
- ActiveRecord
|
127
|
+
- Sequel
|
128
|
+
|
104
129
|
## Changelog
|
105
130
|
|
106
131
|
Refer to [CHANGELOG](CHANGELOG.md).
|
@@ -117,6 +142,7 @@ Refer to [CHANGELOG](CHANGELOG.md).
|
|
117
142
|
|
118
143
|
- [Curator](https://github.com/braintree/curator)
|
119
144
|
- [Edr](https://github.com/nulogy/edr)
|
145
|
+
- [Minimapper](https://github.com/joakimk/minimapper)
|
120
146
|
|
121
147
|
## Author
|
122
148
|
|
data/datamappify.gemspec
CHANGED
@@ -20,16 +20,16 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "virtus", "~> 0.5"
|
22
22
|
spec.add_dependency "activesupport", ">= 4.0.0.beta1", "< 5"
|
23
|
-
spec.add_dependency "activerecord", ">= 4.0.0.beta1", "< 5"
|
24
23
|
|
25
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
25
|
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "minitest-colorize"
|
29
|
-
spec.add_development_dependency "testrbl"
|
26
|
+
spec.add_development_dependency "rspec"
|
30
27
|
spec.add_development_dependency "pry"
|
31
28
|
spec.add_development_dependency "simplecov"
|
32
29
|
spec.add_development_dependency "cane"
|
30
|
+
spec.add_development_dependency "coveralls"
|
33
31
|
spec.add_development_dependency "sqlite3"
|
32
|
+
spec.add_development_dependency "sequel"
|
33
|
+
spec.add_development_dependency "activerecord", ">= 4.0.0.beta1", "< 5"
|
34
34
|
spec.add_development_dependency "database_cleaner", ">= 1.0.0.RC1", "< 2"
|
35
35
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'datamappify/data/provider/common/relational/persistence'
|
2
|
+
require 'datamappify/data/provider/common/relational/record/mapper'
|
3
|
+
require 'datamappify/data/provider/common/relational/record/writer'
|
4
|
+
|
5
|
+
module Datamappify
|
6
|
+
module Data
|
7
|
+
module Provider
|
8
|
+
module ActiveRecord
|
9
|
+
class Persistence < Data::Provider::Common::Relational::Persistence
|
10
|
+
def destroy(ids)
|
11
|
+
data_class.destroy(ids)
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?(id)
|
15
|
+
data_class.exists?(id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def transaction(&block)
|
19
|
+
data_class.transaction(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def record_attributes_method
|
25
|
+
:attributes
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'datamappify/data/provider/active_record/persistence'
|
2
|
+
|
3
|
+
module Datamappify
|
4
|
+
module Data
|
5
|
+
module ActiveRecord
|
6
|
+
end
|
7
|
+
|
8
|
+
module Provider
|
9
|
+
module ActiveRecord
|
10
|
+
def self.build_data_class(data_class_name)
|
11
|
+
Datamappify::Data::ActiveRecord.const_set(data_class_name, Class.new(::ActiveRecord::Base))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Data
|
3
|
+
module Provider
|
4
|
+
module Common
|
5
|
+
class Persistence
|
6
|
+
def initialize(provider_class_name, entities, data_class_name)
|
7
|
+
@provider_class_name = provider_class_name
|
8
|
+
@entities = entities
|
9
|
+
@data_class_name = data_class_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(data_fields_mapping)
|
13
|
+
raise Data::MethodNotImplemented
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(data_fields_mapping)
|
17
|
+
raise Data::MethodNotImplemented
|
18
|
+
end
|
19
|
+
|
20
|
+
def update(data_fields_mapping)
|
21
|
+
raise Data::MethodNotImplemented
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy(id_or_entity)
|
25
|
+
raise Data::MethodNotImplemented
|
26
|
+
end
|
27
|
+
|
28
|
+
def exists?(id)
|
29
|
+
raise Data::MethodNotImplemented
|
30
|
+
end
|
31
|
+
|
32
|
+
def transaction(&block)
|
33
|
+
raise Data::MethodNotImplemented
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(symbol, *args)
|
37
|
+
data_class.send symbol, *args
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def data_class
|
43
|
+
"Datamappify::Data::#{@provider_class_name}::#{@data_class_name}".constantize
|
44
|
+
end
|
45
|
+
|
46
|
+
def entity_class_name
|
47
|
+
@entities[0].class.name
|
48
|
+
end
|
49
|
+
|
50
|
+
def is_entity_class?
|
51
|
+
@data_class_name == entity_class_name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'datamappify/data/provider/common/persistence'
|
2
|
+
|
3
|
+
module Datamappify
|
4
|
+
module Data
|
5
|
+
module Provider
|
6
|
+
module Common
|
7
|
+
module Relational
|
8
|
+
class Persistence < Data::Provider::Common::Persistence
|
9
|
+
def find(data_fields_mapping)
|
10
|
+
records = find_records(data_fields_mapping)
|
11
|
+
|
12
|
+
entities_walker do |entity|
|
13
|
+
if record = find_record_for_entity(entity, records)
|
14
|
+
Common::Relational::RecordMapper.new(
|
15
|
+
entity, record.send(record_attributes_method)
|
16
|
+
).map_attributes(data_fields_mapping)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(data_fields_mapping)
|
22
|
+
entities_walker do |entity|
|
23
|
+
if has_data_to_insert?(entity, data_fields_mapping)
|
24
|
+
Common::Relational::RecordWriter.new(
|
25
|
+
entity, data_class, key_field_name
|
26
|
+
).insert_record(data_fields_mapping)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(data_fields_mapping)
|
32
|
+
records = find_records(data_fields_mapping)
|
33
|
+
|
34
|
+
entities_walker do |entity|
|
35
|
+
record_writer = Common::Relational::RecordWriter.new(entity, data_class, key_field_name)
|
36
|
+
|
37
|
+
if record = find_record_for_entity(entity, records)
|
38
|
+
record_writer.update_record(record, data_fields_mapping)
|
39
|
+
elsif has_data_to_insert?(entity, data_fields_mapping)
|
40
|
+
record_writer.insert_record(data_fields_mapping)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def find_record_for_entity(entity, records)
|
48
|
+
records.find { |r| r.send(key_field_name) == entity.id }
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_records(data_fields_mapping)
|
52
|
+
data_class.select(
|
53
|
+
*field_names(data_fields_mapping)
|
54
|
+
).where(
|
55
|
+
key_field_name => @entities.map(&:id)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def entities_walker
|
60
|
+
walker_method = is_entity_class? ? :keep_if : :each
|
61
|
+
|
62
|
+
@entities.send(walker_method) do |entity|
|
63
|
+
yield(entity)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def key_field_name
|
68
|
+
is_entity_class? ? :id : "#{entity_class_name.underscore}_id".to_sym
|
69
|
+
end
|
70
|
+
|
71
|
+
def field_names(data_fields_mapping)
|
72
|
+
(data_fields_mapping.field_names << key_field_name << :id).uniq
|
73
|
+
end
|
74
|
+
|
75
|
+
def has_data_to_insert?(entity, data_fields_mapping)
|
76
|
+
attribute_names = entity.attributes.keys & data_fields_mapping.attribute_names
|
77
|
+
|
78
|
+
attribute_names.any? && Util.attributes_filtered_by(entity, attribute_names).values.compact.any?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Data
|
3
|
+
module Provider
|
4
|
+
module Common
|
5
|
+
module Relational
|
6
|
+
class RecordMapper
|
7
|
+
def initialize(entity, record_attributes)
|
8
|
+
@entity = entity
|
9
|
+
@record_attributes = record_attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def map_attributes(data_fields_mapping)
|
13
|
+
@record_attributes.each do |name, value|
|
14
|
+
return unless data_fields_mapping.has_key?(name.to_sym)
|
15
|
+
|
16
|
+
@entity.send(:"#{data_fields_mapping[name.to_sym]}=", value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Data
|
3
|
+
module Provider
|
4
|
+
module Common
|
5
|
+
module Relational
|
6
|
+
class RecordWriter
|
7
|
+
def initialize(entity, data_class, key_field_name)
|
8
|
+
@entity = entity
|
9
|
+
@data_class = data_class
|
10
|
+
@key_field_name = key_field_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def insert_record(data_fields_mapping)
|
14
|
+
if is_foreign_record?
|
15
|
+
insert_foreign_record(data_fields_mapping)
|
16
|
+
else
|
17
|
+
new_record = insert_primary_record(data_fields_mapping)
|
18
|
+
update_entity_with_new_record_id(new_record.id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_record(record, data_fields_mapping)
|
23
|
+
update_record_with_fields(record, data_fields_mapping)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def is_foreign_record?
|
29
|
+
@key_field_name != :id
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_an_empty_primary_key?(attribute_name)
|
33
|
+
(attribute_name == :id) && @entity.attributes[attribute_name].nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def insert_foreign_record(data_fields_mapping)
|
37
|
+
new_record = @data_class.new
|
38
|
+
new_record.send "#{@key_field_name}=", @entity.id
|
39
|
+
update_record_with_fields(new_record, data_fields_mapping)
|
40
|
+
end
|
41
|
+
|
42
|
+
def insert_primary_record(data_fields_mapping)
|
43
|
+
update_record_with_fields(@data_class.new, data_fields_mapping)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_record_with_fields(record, data_fields_mapping)
|
47
|
+
data_fields_mapping.field_names.each do |field_name|
|
48
|
+
attribute_name = data_fields_mapping[field_name]
|
49
|
+
|
50
|
+
unless is_an_empty_primary_key?(attribute_name)
|
51
|
+
record.send "#{field_name}=", @entity.attributes[attribute_name]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
record.save
|
56
|
+
record
|
57
|
+
end
|
58
|
+
|
59
|
+
def update_entity_with_new_record_id(id)
|
60
|
+
@entity.id = id
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'datamappify/data/provider/common/relational/persistence'
|
2
|
+
require 'datamappify/data/provider/common/relational/record/mapper'
|
3
|
+
require 'datamappify/data/provider/common/relational/record/writer'
|
4
|
+
|
5
|
+
module Datamappify
|
6
|
+
module Data
|
7
|
+
module Provider
|
8
|
+
module Sequel
|
9
|
+
class Persistence < Data::Provider::Common::Relational::Persistence
|
10
|
+
def destroy(ids)
|
11
|
+
data_class.where(:id => ids).destroy
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?(id)
|
15
|
+
data_class.where(:id => id).any?
|
16
|
+
end
|
17
|
+
|
18
|
+
def transaction(&block)
|
19
|
+
data_class.db.transaction(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def record_attributes_method
|
25
|
+
:values
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'datamappify/data/provider/sequel/persistence'
|
2
|
+
|
3
|
+
module Datamappify
|
4
|
+
module Data
|
5
|
+
module Sequel
|
6
|
+
end
|
7
|
+
|
8
|
+
module Provider
|
9
|
+
module Sequel
|
10
|
+
def self.build_data_class(data_class_name)
|
11
|
+
Datamappify::Data::Sequel.const_set(
|
12
|
+
data_class_name, Class.new(::Sequel::Model(data_class_name.pluralize.underscore.to_sym))
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/datamappify/data.rb
CHANGED
@@ -1,22 +1,27 @@
|
|
1
1
|
module Datamappify
|
2
2
|
module Repository
|
3
3
|
class AttributeSourceDataClassBuilder
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def initialize(provider_class_name, data_class_name)
|
5
|
+
@provider_class_name = provider_class_name
|
6
|
+
@data_class_name = data_class_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def build(data_fields_mapping)
|
10
|
+
require "datamappify/data/provider/#{@provider_class_name.underscore}"
|
7
11
|
|
8
|
-
|
12
|
+
unless data_class_is_defined?
|
13
|
+
provider_module.build_data_class(@data_class_name)
|
9
14
|
end
|
15
|
+
end
|
10
16
|
|
11
|
-
|
17
|
+
private
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
19
|
+
def provider_module
|
20
|
+
@provider_module ||= "Datamappify::Data::Provider::#{@provider_class_name}".constantize
|
21
|
+
end
|
16
22
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
23
|
+
def data_class_is_defined?
|
24
|
+
provider_module.const_defined?(@data_class_name, false)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
@@ -6,27 +6,29 @@ module Datamappify
|
|
6
6
|
def initialize(repository)
|
7
7
|
@repository = repository
|
8
8
|
|
9
|
-
|
9
|
+
map_non_custom_entity_attributes
|
10
|
+
map_custom_entity_attributes
|
10
11
|
end
|
11
12
|
|
12
13
|
def build_data_classes
|
13
|
-
@repository.data_mapping.each do |
|
14
|
-
|
14
|
+
@repository.data_mapping.each do |provider_class_name, data_class_mapping|
|
15
|
+
data_class_mapping.each do |data_class_name, data_fields_mapping|
|
16
|
+
AttributeSourceDataClassBuilder.new(provider_class_name, data_class_name).build(data_fields_mapping)
|
17
|
+
end
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
private
|
19
22
|
|
20
|
-
def map_entity_attributes
|
21
|
-
map_non_custom_entity_attributes
|
22
|
-
map_custom_entity_attributes
|
23
|
-
end
|
24
|
-
|
25
23
|
def map_non_custom_entity_attributes
|
26
|
-
@repository.
|
24
|
+
provider_name = @repository.default_provider_class_name
|
25
|
+
data_class_name = @repository.entity_class.name
|
26
|
+
|
27
|
+
@repository.data_mapping[provider_name] ||= {}
|
28
|
+
@repository.data_mapping[provider_name][data_class_name] ||= MappingHash.new
|
27
29
|
|
28
30
|
non_custom_attributes.each do |attribute_name|
|
29
|
-
@repository.data_mapping[
|
31
|
+
@repository.data_mapping[provider_name][data_class_name][attribute_name] = attribute_name
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -41,10 +43,12 @@ module Datamappify
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def map_custom_entity_attribute(attribute_name, source)
|
44
|
-
|
46
|
+
namespaced_data_class_name, data_field_name = source.split('#')
|
47
|
+
provider_name, data_class_name = namespaced_data_class_name.split('::')
|
45
48
|
|
46
|
-
@repository.data_mapping[
|
47
|
-
@repository.data_mapping[
|
49
|
+
@repository.data_mapping[provider_name] ||= {}
|
50
|
+
@repository.data_mapping[provider_name][data_class_name] ||= MappingHash.new
|
51
|
+
@repository.data_mapping[provider_name][data_class_name][data_field_name.to_sym] = attribute_name
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|