activerecord_to_poro 0.0.2 → 0.0.3

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 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