mongoid_alize 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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