activerecord_to_poro 0.0.2 → 0.0.3

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
  SHA1:
3
- metadata.gz: 73555a31ecff01b8d794c304d390d6a742480dff
4
- data.tar.gz: 7966c2cd299ba10bb133ee76e421b928990c826d
3
+ metadata.gz: 22303b2e1fdea401dba91cc9d58cd87f13d3f711
4
+ data.tar.gz: 83b8bf5c084aa93fb5b5614369a049aaa763dd24
5
5
  SHA512:
6
- metadata.gz: 0980c84cee2f41eed81bf1e588b849be5cdd0e435f125a42ade0631f13d970ce6e187e15a690c01c35d7010c2c83e81b458c19ec1abf5db2e07c0572726e31f4
7
- data.tar.gz: c1de463a85bec7018d6bdfa855acd24758ba9a46523a8abf96f45cbeb78811acea5190d87b8941b824c5e4031407b9f3f91164203032978b389188f04a80119d
6
+ metadata.gz: 906060ece82669221ba6883bd97dfeb3ee0a862b634025896cfe97b5ddb4731fdf4c169e34bfd5d1dc8b6abb7551a50a0d3bcf16b5c08fd40b765a69032b9b53
7
+ data.tar.gz: 9b59fdd62577e984c6d0fdfc4a84cc8e31b12c53c29ada165f30de83302765c79e652b036c9551e511c3f1a42cca71f875e8cea640018d0c0b75b8c97ab9d4d2
data/Gemfile CHANGED
@@ -7,4 +7,4 @@ gemspec
7
7
  gem 'simplecov', require: false, group: :test
8
8
  gem 'coveralls', require: false
9
9
 
10
- gem 'yaoc', github: 'slowjack2k/yaoc', branch: 'master'
10
+ gem 'yaoc', github: 'slowjack2k/yaoc', branch: 'master'
data/README.md CHANGED
@@ -48,27 +48,29 @@ end
48
48
 
49
49
  # You can convert them to poro's like this (automatic genereation of a poro class out of you'r AR class)
50
50
 
51
- roles_converter = ActiverecordToPoro::Converter.new(Role)
52
- salutation_converter = ActiverecordToPoro::Converter.new(Salutation)
53
- user_converter = ActiverecordToPoro::Converter.new(User, convert_associations: {roles: roles_converter, salutation: salutation_converter})
51
+ ActiverecordToPoro::ObjectMapper.create(Role, name: :roles_converter)
52
+ ActiverecordToPoro::ObjectMapper.create(Salutation, name: :salutation_converter)
53
+ user_converter = ActiverecordToPoro::ObjectMapper.create(User,
54
+ name: :user_converter,
55
+ convert_associations: {roles: :roles_converter, salutation: :salutation_converter})
54
56
 
55
57
 
56
58
  poro = user_converter.load(User.first)
57
59
 
58
- # Or with you'r custom class
60
+ # Or with you'r custom poro class
59
61
 
60
- roles_converter = ActiverecordToPoro::Converter.new(Role,
61
- load_source: YourPoroClass
62
- )
62
+ roles_converter = ActiverecordToPoro::ObjectMapper.create(Role,
63
+ load_source: YourPoroClass
64
+ )
63
65
 
64
66
 
65
67
  # default 1:1 mapping only or except
66
68
 
67
- roles_converter = ActiverecordToPoro::Converter.new(Role,
69
+ roles_converter = ActiverecordToPoro::ObjectMapper.create(Role,
68
70
  except: [:lock_version]
69
71
  )
70
72
 
71
- roles_converter = ActiverecordToPoro::Converter.new(Role,
73
+ roles_converter = ActiverecordToPoro::ObjectMapper.create(Role,
72
74
  only: [:name]
73
75
  )
74
76
 
@@ -83,7 +85,7 @@ end
83
85
  roles_converter.extend_mapping do
84
86
  association_rule to: association_name,
85
87
  lazy_loading: true,
86
- converter: association_converter
88
+ converter: association_converter #or :association_converter when you'r converter has a name
87
89
  # optional
88
90
  # from: ...,
89
91
  # reverse_to: ...,
@@ -2,26 +2,57 @@ module ActiverecordToPoro
2
2
  module MapperExtension
3
3
 
4
4
  def association_rule(to: nil,
5
- from: to,
6
- reverse_to: from,
7
- reverse_from: to,
8
- converter: nil,
9
- is_collection: false,
10
- lazy_loading: nil
11
- )
12
-
13
- map_collection = (self.dump_result_source.reflections[from] &&
14
- self.dump_result_source.reflections[from].collection?) || is_collection
15
-
16
- rule to: to,
17
- from: from,
18
- reverse_to: reverse_to,
19
- reverse_from: reverse_from,
20
- reverse_lazy_loading: false, #AR doesn't like ToProcDelegator
21
- object_converter: converter.mapper,
22
- is_collection: map_collection,
23
- lazy_loading: lazy_loading
5
+ from: to,
6
+ reverse_to: from,
7
+ reverse_from: to,
8
+ converter: nil,
9
+ reverse_converter: converter,
10
+ is_collection: false,
11
+ lazy_loading: nil
12
+ )
13
+
14
+ map_collection = ActiverecordToPoro::MapperExtension.is_an_ar_collection?(self.dump_result_source, from) || is_collection
15
+
16
+ options ={
17
+ to: to,
18
+ from: from,
19
+ reverse_to: reverse_to,
20
+ reverse_from: reverse_from,
21
+ reverse_lazy_loading: false, #AR doesn't like ToProcDelegator
22
+ is_collection: map_collection,
23
+ lazy_loading: lazy_loading
24
+ }
25
+
26
+ if converter.nil?
27
+ options[:converter] = noop
28
+ options[:object_converter] = nil
29
+ else
30
+ options[:object_converter] = converter#.mapper
31
+ end
32
+
33
+ if reverse_converter.nil? || ActiverecordToPoro::MapperExtension.is_an_has_many_through(self.dump_result_source, from)
34
+ options[:reverse_converter] = noop
35
+ options[:reverse_object_converter] = nil
36
+ else
37
+ options[:reverse_object_converter] = reverse_converter#.mapper
38
+ end
39
+
40
+ rule options
24
41
 
25
42
  end
43
+
44
+ module_function
45
+
46
+ def is_an_ar_collection?(ar_class, association_name)
47
+ (ar_class.reflections[association_name] &&
48
+ ar_class.reflections[association_name].collection?)
49
+ end
50
+
51
+ def is_an_has_many_through(ar_class, association_name)
52
+ ar_class.reflections[association_name] &&
53
+ ar_class.reflections[association_name].macro == :has_many &&
54
+ ar_class.reflections[association_name].options.has_key?(:through)
55
+ end
56
+
26
57
  end
27
58
  end
@@ -1,21 +1,56 @@
1
1
  module ActiverecordToPoro
2
+ SourceObjectInfo = Yaoc::Helper::StructH(:class_name, :column, :value, :lock_version, :object_id) do
3
+
4
+ include Equalizer.new(:class_name, :column, :value)
5
+
6
+ def to_hash
7
+ {
8
+ class_name: class_name,
9
+ primary_key: {column: column, value: value},
10
+ object_id: object_id,
11
+ lock_version: lock_version
12
+ }
13
+ end
14
+
15
+ def as_scope_hash
16
+ result = column.nil? ? {} : {column => value}
17
+ result[:lock_version] = lock_version unless lock_version.nil?
18
+
19
+ result
20
+ end
21
+ end
22
+
2
23
  class Metadata
3
- attr_accessor :primary_key_column, :primary_key_value
24
+ attr_accessor :source_object_info
4
25
 
26
+ def initialize()
27
+ self.source_object_info = Set.new()
28
+ end
5
29
 
6
30
  def initialize_from_ar(ar_object=nil)
7
31
  unless ar_object.nil?
8
- set_primary_key(ar_object)
32
+ set_source_info(ar_object)
9
33
  end
10
34
  end
11
35
 
12
- def set_primary_key(ar_object)
13
- self.primary_key_column = ar_object.class.primary_key
14
- self.primary_key_value = ar_object.send(self.primary_key_column)
36
+ def for_ar_class(ar_class_name)
37
+ Set.new.find
38
+ source_object_info.find(->{SourceObjectInfo.new}){|data|
39
+ data.class_name == ar_class_name
40
+ }
41
+ end
42
+
43
+ def set_source_info(ar_object)
44
+ self.source_object_info << SourceObjectInfo.new(class_name: ar_object.class.name,
45
+ column: ar_object.class.primary_key,
46
+ value: ar_object.send(ar_object.class.primary_key),
47
+ object_id: ar_object.object_id,
48
+ lock_version: ar_object.respond_to?(:lock_version) ? ar_object.lock_version : nil
49
+ )
15
50
  end
16
51
 
17
52
  def to_hash
18
- { self.primary_key_column => self.primary_key_value }
53
+ { source_objects_info: source_object_info.map(&:to_hash) }
19
54
  end
20
55
 
21
56
  end
@@ -11,12 +11,4 @@ module ActiverecordToPoro
11
11
 
12
12
  end
13
13
 
14
- module MetadataToAr
15
- def _set_metadata_to_ar=(metadata)
16
- metadata.each_pair do |attr, value|
17
- self.send("#{attr}=", value)
18
- @new_record = false
19
- end
20
- end
21
- end
22
14
  end
@@ -0,0 +1,32 @@
1
+ module ActiverecordToPoro
2
+
3
+ module MetadataEnabledAr
4
+
5
+ def _from_attrs_with_metadata(attrs={}, pre_created_object= nil)
6
+ record_by_primary_key = _record_from_metadata!(attrs)
7
+
8
+ record = pre_created_object || record_by_primary_key || new
9
+
10
+ record.tap do |new_obj|
11
+ new_obj.attributes = attrs
12
+ end
13
+
14
+ end
15
+
16
+ def _as_scope(attr)
17
+ attr.empty? ? none : where(attr)
18
+ end
19
+
20
+ def _extract_metadata!(attrs)
21
+ metadata = (attrs || {}).delete(:_set_metadata_to_ar) {|*| Metadata.new}
22
+ metadata.for_ar_class(self.name)
23
+ end
24
+
25
+ def _record_from_metadata!(attrs)
26
+ specific_metadata = _extract_metadata!(attrs)
27
+ _as_scope(specific_metadata.as_scope_hash).first
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,103 @@
1
+ module ActiverecordToPoro
2
+
3
+ module MappingToArClass
4
+ def call(pre_created_object=nil)
5
+ self.target_source._from_attrs_with_metadata(to_hash_or_array(), pre_created_object)
6
+ end
7
+ end
8
+
9
+ class ObjectMapper < Yaoc::ObjectMapper
10
+ include ColumnHelper
11
+ include ActiverecordToPoro::MapperExtension
12
+
13
+ attr_accessor :association_converters,
14
+ :use_lazy_loading,
15
+ :except_attributes,
16
+ :only_attributes
17
+
18
+ class << self
19
+ private :new
20
+ end
21
+
22
+ def self.create(ar_class,
23
+ use_lazy_loading=true,
24
+ except: nil,
25
+ only: nil,
26
+ name: nil,
27
+ load_source: DefaultPoroClassBuilder.new(ar_class).(),
28
+ convert_associations: {})
29
+
30
+ new(load_source, ar_class).tap do|new_mapper|
31
+ new_mapper.fetcher(:public_send)
32
+
33
+ new_mapper.association_converters = convert_associations
34
+ new_mapper.use_lazy_loading = use_lazy_loading
35
+
36
+ new_mapper.except_attributes = Array(except)
37
+ new_mapper.only_attributes = only.nil? ? nil : Array(only) # an empty array can be wanted, so that there is no default mapping @ all
38
+
39
+ new_mapper.add_default_mapping_for_current_class
40
+ new_mapper.add_mapping_for_associations
41
+
42
+ new_mapper.register_as(name)
43
+ end
44
+ end
45
+
46
+ alias_method :extend_mapping, :add_mapping
47
+
48
+ def attributes_for_default_mapping
49
+ self.only_attributes || (
50
+ columns(self.dump_result_source) -
51
+ primary_keys(self.dump_result_source) -
52
+ association_specific_columns(self.dump_result_source) -
53
+ associated_object_accessors(self.dump_result_source) -
54
+ self.except_attributes
55
+ )
56
+ end
57
+
58
+ def load_result_source=(new_load_result)
59
+ @load_result_source = new_load_result.tap do |source|
60
+ unless source.instance_methods.include?(:_metadata)
61
+ source.send(:include, MetadataEnabled)
62
+ end
63
+ end
64
+ end
65
+
66
+ def dump_result_source=(new_dump_result)
67
+ @dump_result_source = new_dump_result.tap do |source|
68
+ unless source.respond_to? :_from_attrs_with_metadata
69
+ source.send(:extend, MetadataEnabledAr)
70
+ end
71
+ end
72
+ end
73
+
74
+ def add_default_mapping_for_current_class
75
+ add_mapping do
76
+ rule to: attributes_for_default_mapping
77
+
78
+ rule to: :_set_metadata,
79
+ converter: ->(source, result){ self.class.fill_result_with_value(result, :_set_metadata_from_ar, source) },
80
+ reverse_converter: ->(source, result){ self.class.fill_result_with_value(result, :_set_metadata_to_ar, source._metadata) }
81
+ end
82
+ end
83
+
84
+ def add_mapping_for_associations
85
+ association_converters.each_pair do |association_name, association_converter|
86
+
87
+ add_mapping do
88
+ association_rule to: association_name,
89
+ lazy_loading: use_lazy_loading,
90
+ converter: association_converter
91
+ end
92
+ end
93
+ end
94
+
95
+ def reverse_converter(fetch_able=nil)
96
+ reverse_converter_builder.converter(fetch_able, dump_result_source).tap do |new_converter|
97
+ new_converter.extend(MappingToArClass)
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiverecordToPoro
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,10 +1,12 @@
1
1
  require 'yaoc'
2
+ require 'equalizer'
2
3
  require 'activerecord_to_poro/version'
3
4
  require 'activerecord_to_poro/metadata_enabled'
5
+ require 'activerecord_to_poro/metadata_enabled_ar'
4
6
  require 'activerecord_to_poro/metadata'
5
7
  require 'activerecord_to_poro/default_poro_class_builder'
6
8
  require 'activerecord_to_poro/mapper_extension'
7
- require 'activerecord_to_poro/converter'
9
+ require 'activerecord_to_poro/object_mapper'
8
10
 
9
11
  module ActiverecordToPoro
10
12
 
@@ -7,19 +7,29 @@ feature 'Map active record associations', %q{
7
7
  } do
8
8
 
9
9
  given!(:mapper){
10
- ActiverecordToPoro::Converter.new(a_active_record_class, convert_associations: {roles: roles_converter, salutation: salutation_converter} )
10
+ ActiverecordToPoro::ObjectMapper.create(a_active_record_class, convert_associations: {roles: roles_converter,
11
+ salutation: salutation_converter}).tap do |m|
12
+ quirk_converter = permissions_converter
13
+
14
+ m.extend_mapping do
15
+ association_rule to: :permissions,
16
+ converter: quirk_converter,
17
+ reverse_converter: nil,
18
+ lazy_loading: true
19
+ end
20
+ end
11
21
  }
12
22
 
13
23
  given!(:roles_converter){
14
- ActiverecordToPoro::Converter.new(Role)
24
+ ActiverecordToPoro::ObjectMapper.create(Role, convert_associations: {permissions: permissions_converter})
15
25
  }
16
26
 
17
27
  given!(:permissions_converter){
18
- ActiverecordToPoro::Converter.new(Permission)
28
+ ActiverecordToPoro::ObjectMapper.create(Permission, name: :permissions_converter)
19
29
  }
20
30
 
21
31
  given!(:salutation_converter){
22
- ActiverecordToPoro::Converter.new(Salutation)
32
+ ActiverecordToPoro::ObjectMapper.create(Salutation)
23
33
  }
24
34
 
25
35
  given!(:a_active_record_class){
@@ -53,22 +63,25 @@ feature 'Map active record associations', %q{
53
63
  }
54
64
 
55
65
  given(:mapper_with_custom_source){
56
- ActiverecordToPoro::Converter.new(a_active_record_class,
57
- load_source: a_custom_poro_class,
58
- except: [:lock_version]
66
+ ActiverecordToPoro::ObjectMapper.create(a_active_record_class,
67
+ load_source: a_custom_poro_class,
68
+ except: [:lock_version]
59
69
  )
60
70
  }
61
71
 
62
72
 
63
73
  scenario "creates a poro out of an ActiveRecord object with associations set" do
64
74
  expect(mapper.load(a_active_record_object).roles.size).to eq 2
75
+ expect(mapper.load(a_active_record_object).permissions.size).to eq 3
65
76
  expect(mapper.load(a_active_record_object).salutation.name).to eq "Mister"
66
77
  end
67
78
 
68
79
  scenario "creates an ActiveRecord object from a poro object with associations set" do
69
80
  poro = mapper.load(a_active_record_object)
70
81
  expect(mapper.dump(poro).roles.size).to eq 2
71
- expect(mapper.dump(poro).permissions.size).to eq 3
82
+
83
+ expect(mapper.dump(poro).roles.first.permissions.size).to eq 2
84
+ expect(mapper.dump(poro).roles.last.permissions.size).to eq 1
72
85
  end
73
86
 
74
87
  scenario "lazy loads associated objects" do
@@ -79,13 +92,12 @@ feature 'Map active record associations', %q{
79
92
  end
80
93
 
81
94
  scenario 'add custom association mappings' do
82
- quirk_converter = permissions_converter
83
95
 
84
96
  mapper_with_custom_source.extend_mapping do
85
97
 
86
98
  association_rule to: :some_other_name,
87
99
  from: :permissions,
88
- converter: quirk_converter,
100
+ converter: :permissions_converter,
89
101
  lazy_loading: true
90
102
 
91
103
  end
@@ -7,13 +7,13 @@ feature "Map active record objects", %q{
7
7
  } do
8
8
 
9
9
  given(:mapper){
10
- ActiverecordToPoro::Converter.new(a_active_record_class)
10
+ ActiverecordToPoro::ObjectMapper.create(a_active_record_class)
11
11
  }
12
12
 
13
13
  given(:mapper_with_custom_source){
14
- ActiverecordToPoro::Converter.new(a_active_record_class,
15
- load_source: custom_poro_class,
16
- except: [:lock_version]
14
+ ActiverecordToPoro::ObjectMapper.create(a_active_record_class,
15
+ load_source: custom_poro_class,
16
+ except: [:lock_version]
17
17
  )
18
18
  }
19
19
 
@@ -35,7 +35,7 @@ feature "Map active record objects", %q{
35
35
 
36
36
  scenario "creates an ActiveRecord object from a poro object" do
37
37
  poro = mapper.load(a_active_record_object)
38
- expect(mapper.dump(poro)).to eq a_active_record_object
38
+ expect(mapper.dump(poro).attributes).to eq a_active_record_object.attributes
39
39
  end
40
40
 
41
41
  scenario "use my own source class for converting ActiveRecord objects" do
@@ -1,8 +1,10 @@
1
- require 'sqlite3'
2
1
  require 'active_record'
3
2
  require 'database_cleaner'
4
3
 
5
4
  db_dir = File.join(File.expand_path(__dir__ ), "ar_support/db/")
5
+ # ENV['DATABASE_URL']="sqlite3://localhost/:memory:?pool=5&timeout=5000"
6
+
7
+
6
8
 
7
9
  ActiveRecord::Base.establish_connection({
8
10
  pool: 5,
@@ -0,0 +1,89 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe ActiverecordToPoro::MapperExtension do
4
+ subject{
5
+ Yaoc::ObjectMapper.new(target, source).tap do |mapper|
6
+ mapper.extend ActiverecordToPoro::MapperExtension
7
+ mapper.fetcher(:public_send)
8
+ end
9
+ }
10
+
11
+ let(:source){ User }
12
+
13
+ let(:target){ActiverecordToPoro::DefaultPoroClassBuilder.new(source).()}
14
+
15
+ let(:default_expected_params){
16
+ {
17
+ :to=>:roles,
18
+ :from=>:roles,
19
+ :reverse_to=>:roles,
20
+ :reverse_from=>:roles,
21
+ :reverse_lazy_loading=>false,
22
+ :is_collection=>true,
23
+ :lazy_loading=>nil,
24
+ :object_converter=>converter,
25
+ :reverse_object_converter=>converter
26
+ }
27
+ }
28
+
29
+ let(:converter){
30
+ double("converter")
31
+ }
32
+
33
+ describe '#association_rule' do
34
+ it "uses defaults" do
35
+ expect(subject).to receive(:rule).with default_expected_params
36
+ subject.association_rule(to: :roles,
37
+ converter: converter
38
+ )
39
+ end
40
+
41
+ it "does not convert forward when converter is nil" do
42
+ expected_params = default_expected_params.merge(converter: kind_of(Proc),
43
+ reverse_converter: kind_of(Proc),
44
+ object_converter: nil,
45
+ reverse_object_converter: nil
46
+ )
47
+
48
+ expect(subject).to receive(:rule).with expected_params
49
+
50
+ subject.association_rule(
51
+ to: :roles,
52
+ converter: nil
53
+ )
54
+ end
55
+
56
+ it "does not convert reverse when reverse converter is nil" do
57
+ expected_params = default_expected_params.merge(
58
+ reverse_converter: kind_of(Proc),
59
+ reverse_object_converter: nil
60
+ )
61
+
62
+ expect(subject).to receive(:rule).with expected_params
63
+
64
+ subject.association_rule(
65
+ to: :roles,
66
+ converter: converter,
67
+ reverse_converter: nil
68
+ )
69
+ end
70
+
71
+ it "disables reverse converter when the association is kind of has many through (no setter from rails)" do
72
+ expected_params = default_expected_params.merge(
73
+ reverse_converter: kind_of(Proc),
74
+ reverse_object_converter: nil,
75
+ to: :permissions,
76
+ from: :permissions,
77
+ reverse_to: :permissions,
78
+ reverse_from: :permissions,
79
+ )
80
+
81
+ expect(subject).to receive(:rule).with expected_params
82
+
83
+ subject.association_rule(
84
+ to: :permissions,
85
+ converter: converter
86
+ )
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,32 @@
1
+ require 'integration_spec_helper'
2
+
3
+ describe ActiverecordToPoro::MetadataEnabledAr do
4
+ subject{
5
+ User.extend ActiverecordToPoro::MetadataEnabledAr
6
+ User
7
+ }
8
+
9
+ let(:ar_object){
10
+ User.create!(name: 'my name', email: 'my_name@example.com')
11
+ }
12
+
13
+ let(:metadata){
14
+ ActiverecordToPoro::Metadata.new.tap do |meta|
15
+ meta.initialize_from_ar(ar_object)
16
+ end
17
+ }
18
+
19
+ describe '._from_attrs_with_metadata' do
20
+ it 'loads a record from db' do
21
+ new_user = subject._from_attrs_with_metadata({_set_metadata_to_ar: metadata })
22
+ expect(new_user.new_record?).to be_falsy
23
+ end
24
+
25
+ it 'uses a precreated object' do
26
+ new_user = subject._from_attrs_with_metadata({_set_metadata_to_ar: metadata }, ar_object)
27
+ expect(new_user.object_id).to eq ar_object.object_id
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -1,19 +1,19 @@
1
1
  require 'integration_spec_helper'
2
2
 
3
- describe ActiverecordToPoro::Converter do
3
+ describe ActiverecordToPoro::ObjectMapper do
4
4
 
5
5
  describe '.new' do
6
6
  subject{
7
- ActiverecordToPoro::Converter
7
+ ActiverecordToPoro::ObjectMapper
8
8
  }
9
9
 
10
10
  it 'removes "except" attributes from default mapping' do
11
- object = subject.new(User, except: :lock_version)
11
+ object = subject.create(User, except: :lock_version)
12
12
  expect(object.attributes_for_default_mapping).not_to include :lock_version
13
13
  end
14
14
 
15
15
  it 'uses "only" attributes for default mapping' do
16
- object = subject.new(User, only: :id)
16
+ object = subject.create(User, only: :id)
17
17
  expect(object.attributes_for_default_mapping).to eq [:id]
18
18
  end
19
19
 
@@ -21,15 +21,15 @@ describe ActiverecordToPoro::Converter do
21
21
 
22
22
  context 'instance methods' do
23
23
  subject!{
24
- ActiverecordToPoro::Converter.new(User, convert_associations: {roles: roles_converter, salutation: salutation_converter})
24
+ ActiverecordToPoro::ObjectMapper.create(User, convert_associations: {roles: roles_converter, salutation: salutation_converter})
25
25
  }
26
26
 
27
27
  let(:roles_converter){
28
- ActiverecordToPoro::Converter.new(Role)
28
+ ActiverecordToPoro::ObjectMapper.create(Role)
29
29
  }
30
30
 
31
31
  let(:salutation_converter){
32
- ActiverecordToPoro::Converter.new(Salutation)
32
+ ActiverecordToPoro::ObjectMapper.create(Salutation)
33
33
  }
34
34
 
35
35
  let(:ar_object){
@@ -50,7 +50,6 @@ describe ActiverecordToPoro::Converter do
50
50
 
51
51
  it 'sets metadata for loaded objects' do
52
52
  expect(loaded_poro_object._metadata).not_to be_nil
53
- expect(loaded_poro_object._metadata.primary_key_value).to eq ar_object.id
54
53
  end
55
54
 
56
55
  it 'converts also associated objects' do
@@ -62,18 +61,19 @@ describe ActiverecordToPoro::Converter do
62
61
  subject.load(ar_object)
63
62
  end
64
63
 
64
+ it 'fills an existing poro' do
65
+ poro_to_fill = subject.load_result_source.new
66
+ expect(subject.load(ar_object, poro_to_fill).object_id).to eq poro_to_fill.object_id
67
+ end
68
+
65
69
  end
66
70
 
67
71
  describe '#dump' do
68
- it 'creates an ActiveRecordObject' do
72
+ it 'creates an ActiveRecord object' do
69
73
  expect(subject.dump(loaded_poro_object)).to be_kind_of ActiveRecord::Base
70
74
  end
71
75
 
72
- it 'sets the primary key when it existed before' do
73
- expect(subject.dump(loaded_poro_object).id).to eq ar_object.id
74
- end
75
-
76
- it 'sets new_record to false when it is an existing record' do
76
+ it 'loads the object from database when primary key and value are given in metadata' do
77
77
  expect(subject.dump(loaded_poro_object).new_record?).to be_falsy
78
78
  end
79
79
 
@@ -82,6 +82,11 @@ describe ActiverecordToPoro::Converter do
82
82
 
83
83
  expect(subject.dump(loaded_poro_object).roles.size).to eq count_roles
84
84
  end
85
+
86
+ it 'fills an existing ActiveRecord object' do
87
+ new_ar_object = User.new
88
+ expect(subject.dump(loaded_poro_object, new_ar_object).object_id).to eq new_ar_object.object_id
89
+ end
85
90
  end
86
91
 
87
92
  end
@@ -1,32 +1,62 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe ActiverecordToPoro::Metadata do
4
- let(:ar_object){
4
+ let(:ar_class){
5
5
  Struct.new(:id) do
6
6
  def self.primary_key
7
7
  "id"
8
8
  end
9
9
 
10
- end.new(1)
10
+ def self.name
11
+ "MyNameIsStruct"
12
+ end
13
+
14
+ end
15
+ }
16
+
17
+ let(:ar_object_1){
18
+ ar_class.new(1)
19
+ }
20
+
21
+ let(:ar_object_2){
22
+ ar_class.new(2)
11
23
  }
12
24
 
25
+
13
26
  describe "#initialize_from_ar" do
14
27
 
15
28
  it "sets the primary_key" do
16
- subject.initialize_from_ar(ar_object)
29
+ subject.initialize_from_ar(ar_object_1)
17
30
 
18
- expect(subject.primary_key_column).to eq "id"
19
- expect(subject.primary_key_value).to eq 1
31
+ expect(subject.to_hash).to include( source_objects_info: [{class_name: "MyNameIsStruct",
32
+ primary_key: {:column=>"id", :value=>1},
33
+ object_id: ar_object_1.object_id,
34
+ lock_version: nil
35
+ }])
36
+ end
37
+
38
+ it "adds multiple objects" do
39
+ subject.initialize_from_ar(ar_object_1)
40
+ subject.initialize_from_ar(ar_object_2)
41
+
42
+ expect(subject.to_hash[:source_objects_info].size).to eq 2
43
+ end
44
+
45
+ it "adds the same object only once" do
46
+ subject.initialize_from_ar(ar_class.new(1))
47
+ subject.initialize_from_ar(ar_class.new(1))
48
+
49
+ expect(subject.to_hash[:source_objects_info].size).to eq 1
20
50
  end
21
51
 
22
52
  end
23
53
 
24
- describe "set_primary_key" do
25
- it "sets the primary_key" do
26
- subject.set_primary_key(ar_object)
54
+ describe '#for_ar_class' do
55
+ it 'returns metadata for a ActiveRecord class' do
56
+ subject.initialize_from_ar(ar_object_1)
27
57
 
28
- expect(subject.primary_key_column).to eq "id"
29
- expect(subject.primary_key_value).to eq 1
58
+ expect(subject.for_ar_class(ar_class.name).to_hash).to include({primary_key: {column: "id", value: 1}})
30
59
  end
31
60
  end
61
+
32
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord_to_poro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dieter Späth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-29 00:00:00.000000000 Z
11
+ date: 2014-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: abstract_type
@@ -278,11 +278,12 @@ files:
278
278
  - Rakefile
279
279
  - activerecord_to_poro.gemspec
280
280
  - lib/activerecord_to_poro.rb
281
- - lib/activerecord_to_poro/converter.rb
282
281
  - lib/activerecord_to_poro/default_poro_class_builder.rb
283
282
  - lib/activerecord_to_poro/mapper_extension.rb
284
283
  - lib/activerecord_to_poro/metadata.rb
285
284
  - lib/activerecord_to_poro/metadata_enabled.rb
285
+ - lib/activerecord_to_poro/metadata_enabled_ar.rb
286
+ - lib/activerecord_to_poro/object_mapper.rb
286
287
  - lib/activerecord_to_poro/version.rb
287
288
  - spec/acceptance/map_ar_associations_spec.rb
288
289
  - spec/acceptance/map_ar_objects_spec.rb
@@ -294,8 +295,10 @@ files:
294
295
  - spec/ar_support/models/role.rb
295
296
  - spec/ar_support/models/salutation.rb
296
297
  - spec/ar_support/models/user.rb
297
- - spec/integration/lib/activerecord_to_poro/converter_spec.rb
298
298
  - spec/integration/lib/activerecord_to_poro/default_poro_class_builder_spec.rb
299
+ - spec/integration/lib/activerecord_to_poro/mapper_extension_spec.rb
300
+ - spec/integration/lib/activerecord_to_poro/metadata_enabled_ar_spec.rb
301
+ - spec/integration/lib/activerecord_to_poro/object_mapper_spec.rb
299
302
  - spec/integration_spec_helper.rb
300
303
  - spec/spec_helper.rb
301
304
  - spec/support/feature.rb
@@ -336,8 +339,10 @@ test_files:
336
339
  - spec/ar_support/models/role.rb
337
340
  - spec/ar_support/models/salutation.rb
338
341
  - spec/ar_support/models/user.rb
339
- - spec/integration/lib/activerecord_to_poro/converter_spec.rb
340
342
  - spec/integration/lib/activerecord_to_poro/default_poro_class_builder_spec.rb
343
+ - spec/integration/lib/activerecord_to_poro/mapper_extension_spec.rb
344
+ - spec/integration/lib/activerecord_to_poro/metadata_enabled_ar_spec.rb
345
+ - spec/integration/lib/activerecord_to_poro/object_mapper_spec.rb
341
346
  - spec/integration_spec_helper.rb
342
347
  - spec/spec_helper.rb
343
348
  - spec/support/feature.rb
@@ -1,112 +0,0 @@
1
- module ActiverecordToPoro
2
- class Converter
3
- include ColumnHelper
4
-
5
- attr_accessor :load_source_class,
6
- :dump_source_class,
7
- :association_converters,
8
- :use_lazy_loading,
9
- :except_attributes,
10
- :only_attributes
11
-
12
- def initialize(ar_class,
13
- use_lazy_loading=true,
14
- except: nil,
15
- only: nil,
16
- load_source: nil,
17
- convert_associations: {})
18
- self.load_source_class = ar_class
19
- self.dump_source_class = load_source || DefaultPoroClassBuilder.new(ar_class).()
20
- self.association_converters = convert_associations
21
- self.use_lazy_loading = use_lazy_loading
22
- self.except_attributes = Array(except)
23
- self.only_attributes = only.nil? ? nil : Array(only) # an empty array can be wanted, so that there is no default mapping @ all
24
- end
25
-
26
- def load(to_convert)
27
- mapper.load(to_convert)
28
- end
29
-
30
- def dump(to_convert)
31
- mapper.dump(to_convert)
32
- end
33
-
34
- def extend_mapping(&block)
35
- mapper.add_mapping &block
36
- end
37
-
38
-
39
- def mapper
40
- @mapper||= Yaoc::ObjectMapper.new(self.dump_source_class, self.load_source_class).tap do |mapper|
41
- mapper.extend ActiverecordToPoro::MapperExtension
42
- mapper.fetcher(:public_send)
43
-
44
- add_default_mapping_for_current_class(mapper)
45
- add_mapping_for_associations(mapper)
46
- end
47
- end
48
-
49
- def attributes_for_default_mapping
50
- self.only_attributes || (
51
- columns(self.load_source_class) -
52
- primary_keys(self.load_source_class) -
53
- association_specific_columns(self.load_source_class) -
54
- associated_object_accessors(self.load_source_class) -
55
- self.except_attributes
56
- )
57
- end
58
-
59
- protected
60
-
61
- def add_default_mapping_for_current_class(mapper)
62
- tmp_quirk = attributes_for_default_mapping
63
-
64
- mapper.add_mapping do
65
- rule to: tmp_quirk
66
-
67
- rule to: :_set_metadata,
68
- converter: ->(source, result){ fill_result_with_value(result, :_set_metadata_from_ar, source) },
69
- reverse_converter: ->(source, result){
70
-
71
- needs_conversion = if source.respond_to?("_needs_conversion?")
72
- source._needs_conversion?
73
- else
74
- ! source.nil? #would trigger lazy loading when it is a ToProcDelegator
75
- end
76
-
77
- fill_result_with_value(result, :_set_metadata_to_ar, source._metadata.to_hash) if needs_conversion
78
- }
79
- end
80
- end
81
-
82
- def add_mapping_for_associations(mapper)
83
- association_converters.each_pair do |association_name, association_converter|
84
-
85
- lazy_quirk = self.use_lazy_loading
86
-
87
- mapper.add_mapping do
88
- association_rule to: association_name,
89
- lazy_loading: lazy_quirk,
90
- converter: association_converter
91
- end
92
- end
93
- end
94
-
95
- def dump_source_class=(new_dump_source)
96
- @dump_source_class = new_dump_source.tap do |source|
97
- unless source.respond_to? :_metadata
98
- source.send(:include, MetadataEnabled)
99
- end
100
- end
101
- end
102
-
103
- def load_source_class=(new_source)
104
- @load_source_class=new_source.tap do |source|
105
- unless source.respond_to? :_set_metadata_to_ar=
106
- source.send(:include, ActiverecordToPoro::MetadataToAr)
107
- end
108
- end
109
- end
110
-
111
- end
112
- end