/
one_to_many.rb
136 lines (114 loc) · 3.55 KB
/
one_to_many.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module CassandraObject
class OneToManyAssociation
def initialize(association_name, owner_class, options)
@association_name = association_name.to_s
@owner_class = owner_class
@target_class_name = options[:class_name] || association_name.to_s.singularize.camelize
@options = options
define_methods!
end
def find(owner, options = {})
reversed = options.has_key?(:reversed) ? options[:reversed] : reversed?
cursor = CassandraObject::Cursor.new(target_class, column_family, owner.key.to_s, @association_name, :start_after => options[:start_after], :reversed => reversed)
cursor.find(options[:limit] || 100)
end
def add(owner, record, set_inverse = true)
connection.insert(column_family, owner.key.to_s, {@association_name=>{new_key=>record.key.to_s}})
if has_inverse? && set_inverse
inverse.set_inverse(record, owner)
end
end
def new_key
SimpleUUID::UUID.new
end
def column_family
@owner_class.to_s + "Relationships"
end
def connection
@owner_class.connection
end
def target_class
@target_class ||= @target_class_name.constantize
end
def new_proxy(owner)
OneToManyAssociationProxy.new(self, owner)
end
def has_inverse?
@options[:inverse_of]
end
def inverse
has_inverse? && target_class.associations[@options[:inverse_of]]
end
def set_inverse(owner, record)
add(owner, record, false)
end
def reversed?
@options[:reversed] == true
end
def define_methods!
@owner_class.class_eval <<-eos
def #{@association_name}
@_#{@association_name} ||= self.class.associations[:#{@association_name}].new_proxy(self)
end
eos
end
end
class OneToManyAssociationProxy
def initialize(association, owner)
@association = association
@owner = owner
end
include Enumerable
def each
target.each do |i|
yield i
end
end
def <<(record)
@association.add(@owner, record)
if loaded?
@target << record
end
end
# Get the targets of this association proxy
#
# @param [Hash] options the options with which to modify this query
# @option options [String] :start_after the key after which to start returning results
# @option options [Boolean] :reversed (false or association default) return the results in reverse order
# @option options [Integer] :limit the max number of results to return
# @return [Array<CassandraObject::Base>] an array of objects of type self#target_class
#
def all(options = {})
@association.find(@owner, options)
end
# Create a record of the associated type with
# the supplied attributes and add it to this
# association
#
# @param [Hash] attributes the attributes with which to create the object
# @return [CassandraObject::Base] the newly created object
#
def create(attributes)
returning @association.target_class.create(attributes) do |record|
if record.valid?
self << record
end
end
end
def create!(attributes)
returning @association.target_class.create!(attributes) do |record|
self << record
end
end
def target
@target ||= begin
@loaded = true
@association.find(@owner)
end
end
alias to_a target
def loaded?
defined?(@loaded) && @loaded
end
end
end