mongoid_alize 0.1.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.
@@ -0,0 +1,34 @@
1
+ module Mongoid
2
+ module Alize
3
+ class Callback
4
+
5
+ attr_accessor :fields
6
+
7
+ attr_accessor :klass
8
+ attr_accessor :relation
9
+
10
+ attr_accessor :inverse_klass
11
+ attr_accessor :inverse_relation
12
+
13
+ def initialize(_klass, _relation, _fields)
14
+ self.klass = _klass
15
+ self.relation = _relation
16
+ self.fields = _fields
17
+
18
+ reflect = _klass.relations[_relation.to_s]
19
+ self.inverse_klass = reflect.klass
20
+ self.inverse_relation = reflect.inverse
21
+ end
22
+
23
+ def attach
24
+ # implement in subclasses
25
+ end
26
+
27
+ protected
28
+
29
+ def joined_fields
30
+ (fields + [:_id]).map {|f| "'#{f}'" }.join(", ")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module From
5
+ class Many < FromCallback
6
+
7
+ protected
8
+
9
+ def define_callback
10
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
11
+ def #{callback_name}
12
+ self.#{prefixed_name} = self.#{relation}.map do |model|
13
+ model.attributes.slice(#{joined_fields})
14
+ end
15
+ end
16
+
17
+ protected :#{callback_name}
18
+ CALLBACK
19
+ end
20
+
21
+ def define_fields
22
+ unless !!klass.fields[prefixed_name]
23
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
24
+ field :#{prefixed_name}, :type => Array
25
+ CALLBACK
26
+ end
27
+ end
28
+
29
+ def prefixed_name
30
+ "#{relation}_fields"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module From
5
+ class One < FromCallback
6
+
7
+ protected
8
+
9
+ def define_callback
10
+ field_sets = ""
11
+ fields.each do |name|
12
+ field_sets << "self.set(:#{prefixed_field_name(name)}, relation && relation.read_attribute(:#{name}))\n"
13
+ end
14
+
15
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
16
+ def #{callback_name}
17
+ relation = self.#{relation}
18
+ #{field_sets}
19
+ true
20
+ end
21
+
22
+ protected :#{callback_name}
23
+ CALLBACK
24
+ end
25
+
26
+ def define_fields
27
+ fields.each do |name|
28
+ prefixed_name = prefixed_field_name(name)
29
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
30
+ field :#{prefixed_name}, :type => #{inverse_field_type(name)}
31
+ CALLBACK
32
+ end
33
+ end
34
+
35
+ def prefixed_field_name(name)
36
+ "#{relation}_#{name}"
37
+ end
38
+
39
+ def inverse_field_type(name)
40
+ field = inverse_klass.fields[name.to_s]
41
+ field.options[:type] ? field.type : String
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module To
5
+ class ManyFromMany < ToManyCallback
6
+ protected
7
+
8
+ def iterable_relation
9
+ "self.#{relation}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module To
5
+ class ManyFromOne < ToManyCallback
6
+ protected
7
+
8
+ def iterable_relation
9
+ "self.#{relation} ? [self.#{relation}] : []"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module To
5
+ class OneFromMany < ToOneCallback
6
+ protected
7
+
8
+ def iterable_relation
9
+ "self.#{relation}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Callbacks
4
+ module To
5
+ class OneFromOne < ToOneCallback
6
+ protected
7
+
8
+ def iterable_relation
9
+ "self.#{relation} ? [self.#{relation}] : []"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module Mongoid
2
+ module Alize
3
+ class FromCallback < Callback
4
+
5
+ def attach
6
+ define_fields
7
+
8
+ define_callback
9
+ set_callback
10
+ end
11
+
12
+ protected
13
+
14
+ def set_callback
15
+ klass.set_callback(:create, :before, callback_name)
16
+ end
17
+
18
+ def callback_name
19
+ "denormalize_from_#{relation}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,68 @@
1
+ module Mongoid
2
+ module Alize
3
+ module Macros
4
+
5
+ def alize(relation, *fields)
6
+
7
+ fields = default_alize_fields(relation) if fields.empty?
8
+
9
+ one = Mongoid::Relations::One
10
+ many = Mongoid::Relations::Many
11
+
12
+ def (many = many.dup).==(klass)
13
+ [Mongoid::Relations::Many,
14
+ Mongoid::Relations::Referenced::Many].map(&:name).include?(klass.name)
15
+ end
16
+
17
+ klass = self
18
+ reflect = klass.relations[relation.to_s]
19
+
20
+ from_one = Mongoid::Alize::Callbacks::From::One
21
+ from_many = Mongoid::Alize::Callbacks::From::Many
22
+
23
+ relation_superclass = reflect.relation.superclass
24
+ callback_klass =
25
+ case [relation_superclass]
26
+ when [one] then from_one
27
+ when [many] then from_many
28
+ end
29
+
30
+ callback_klass.
31
+ new(klass, relation, fields).
32
+ attach
33
+
34
+ inverse_klass = reflect.klass
35
+ inverse_relation = reflect.inverse
36
+
37
+ if inverse_klass &&
38
+ (inverse_reflect = inverse_klass.relations[inverse_relation.to_s])
39
+
40
+ to_one_from_one = Mongoid::Alize::Callbacks::To::OneFromOne
41
+ to_one_from_many = Mongoid::Alize::Callbacks::To::OneFromMany
42
+ to_many_from_one = Mongoid::Alize::Callbacks::To::ManyFromOne
43
+ to_many_from_many = Mongoid::Alize::Callbacks::To::ManyFromMany
44
+
45
+ inverse_relation_superclass = inverse_reflect.relation.superclass
46
+ inverse_callback_klass =
47
+ case [relation_superclass, inverse_relation_superclass]
48
+ when [one, one] then to_one_from_one
49
+ when [many, one] then to_many_from_one
50
+ when [one, many] then to_one_from_many
51
+ when [many, many] then to_many_from_many
52
+ end
53
+
54
+ inverse_callback_klass.
55
+ new(inverse_klass, inverse_relation, fields).
56
+ attach
57
+ end
58
+ end
59
+
60
+ def default_alize_fields(relation)
61
+ self.relations[relation.to_s].klass.
62
+ fields.reject { |name, field|
63
+ name =~ /^_/
64
+ }.keys
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,32 @@
1
+ module Mongoid
2
+ module Alize
3
+ class ToCallback < Callback
4
+
5
+ def attach
6
+ define_callback
7
+ set_callback
8
+
9
+ define_destroy_callback
10
+ set_destroy_callback
11
+ end
12
+
13
+ protected
14
+
15
+ def set_callback
16
+ klass.set_callback(:save, :after, callback_name)
17
+ end
18
+
19
+ def set_destroy_callback
20
+ klass.set_callback(:destroy, :after, destroy_callback_name)
21
+ end
22
+
23
+ def callback_name
24
+ "denormalize_to_#{relation}"
25
+ end
26
+
27
+ def destroy_callback_name
28
+ "denormalize_destroy_to_#{relation}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module Mongoid
2
+ module Alize
3
+ class ToManyCallback < ToCallback
4
+ protected
5
+
6
+ def define_callback
7
+ _callback(callback_name,
8
+ "inverse.push(:#{prefixed_name}, self.attributes.slice(#{joined_fields}))")
9
+ end
10
+
11
+ def define_destroy_callback
12
+ _callback(destroy_callback_name)
13
+ end
14
+
15
+ def _callback(_callback_name, push_content="")
16
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
17
+ def #{_callback_name}
18
+
19
+ (#{iterable_relation}).each do |inverse|
20
+
21
+ # this pull works in the DB, but not in memory
22
+ # ($pull w/ expression not currently supported by Mongoid)
23
+ inverse.pull(:#{prefixed_name}, { "_id" => self.id })
24
+
25
+ # manually do the pull in memory for now
26
+ if inverse.#{prefixed_name}
27
+ inverse.#{prefixed_name}.reject! do |hash|
28
+ hash["_id"] == self.id
29
+ end
30
+ end
31
+
32
+ #{push_content}
33
+ end
34
+ end
35
+
36
+ protected :#{_callback_name}
37
+ CALLBACK
38
+ end
39
+
40
+ def prefixed_name
41
+ "#{inverse_relation}_fields"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ module Mongoid
2
+ module Alize
3
+ class ToOneCallback < ToCallback
4
+ protected
5
+
6
+ def define_callback
7
+ _callback(callback_name, to_one_field_sets)
8
+ end
9
+
10
+ def define_destroy_callback
11
+ _callback(destroy_callback_name, to_one_destroy_field_sets)
12
+ end
13
+
14
+ def to_one_field_sets
15
+ fields.map { |field|
16
+ "relation.set(:#{prefixed_field_name(field)}, self.read_attribute(:#{field}))"
17
+ }.join("\n")
18
+ end
19
+
20
+ def to_one_destroy_field_sets
21
+ fields.map { |field|
22
+ "relation.set(:#{prefixed_field_name(field)}, nil)"
23
+ }.join("\n")
24
+ end
25
+
26
+ def _callback(_callback_name, field_sets)
27
+ klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
28
+ def #{_callback_name}
29
+ (#{iterable_relation}).each do |relation|
30
+ #{field_sets}
31
+ end
32
+ true
33
+ end
34
+
35
+ protected :#{_callback_name}
36
+ CALLBACK
37
+ end
38
+
39
+ def prefixed_field_name(name)
40
+ "#{inverse_relation}_#{name}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ require 'mongoid/alize/callback'
2
+
3
+ require 'mongoid/alize/from_callback.rb'
4
+
5
+ require 'mongoid/alize/to_callback.rb'
6
+ require 'mongoid/alize/to_one_callback.rb'
7
+ require 'mongoid/alize/to_many_callback.rb'
8
+
9
+ require 'mongoid/alize/callbacks/from/one.rb'
10
+ require 'mongoid/alize/callbacks/from/many.rb'
11
+
12
+ require 'mongoid/alize/callbacks/to/one_from_one.rb'
13
+ require 'mongoid/alize/callbacks/to/one_from_many.rb'
14
+ require 'mongoid/alize/callbacks/to/many_from_one.rb'
15
+ require 'mongoid/alize/callbacks/to/many_from_many.rb'
16
+
17
+ require 'mongoid/alize/macros'
18
+
19
+ module Mongoid
20
+ module Alize
21
+ extend ActiveSupport::Concern
22
+
23
+ included do
24
+ extend Mongoid::Alize::Macros
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ class Head
2
+ include Mongoid::Document
3
+ include Mongoid::Alize
4
+
5
+ field :size, type: Integer
6
+ field :weight
7
+
8
+ # to whom it's attached
9
+ belongs_to :person
10
+
11
+ # in who's possession it is
12
+ belongs_to :captor, :class_name => "Person", :inverse_of => :heads
13
+
14
+ # who'd otherwise like to possess it
15
+ has_and_belongs_to_many :wanted_by, :class_name => "Person", :inverse_of => :wants
16
+
17
+ # who it sees
18
+ has_many :sees, :class_name => "Person", :inverse_of => :seen_by
19
+
20
+ # a relation with no inverse
21
+ has_many :admirer, :class_name => "Person", :inverse_of => nil
22
+ end