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
137
138
139
140
141
142
143
144
145
|
module ActiveRecord
module QueryMethods
def preload(*associations)
spawn.tap {|r| r.preload_associations += Array.wrap(associations) }
end
def includes(*associations)
spawn.tap {|r| r.includes_associations += Array.wrap(associations) }
end
def eager_load(*associations)
spawn.tap {|r| r.eager_load_associations += Array.wrap(associations) }
end
def readonly(status = true)
spawn.tap {|r| r.readonly = status }
end
def create_with(attributes = {})
spawn.tap {|r| r.create_with_attributes = attributes }
end
def select(selects)
if selects.present?
relation = spawn(@relation.project(selects))
relation.readonly = @relation.joins(relation).present? ? false : @readonly
relation
else
spawn
end
end
def from(from)
from.present? ? spawn(@relation.from(from)) : spawn
end
def having(*args)
return spawn if args.blank?
if [String, Hash, Array].include?(args.first.class)
havings = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first)
else
havings = args.first
end
spawn(@relation.having(havings))
end
def group(groups)
groups.present? ? spawn(@relation.group(groups)) : spawn
end
def order(orders)
orders.present? ? spawn(@relation.order(orders)) : spawn
end
def lock(locks = true)
case locks
when String
spawn(@relation.lock(locks))
when TrueClass, NilClass
spawn(@relation.lock)
else
spawn
end
end
def reverse_order
relation = spawn
relation.instance_variable_set(:@orders, nil)
order_clause = @relation.send(:order_clauses).join(', ')
if order_clause.present?
relation.order(reverse_sql_order(order_clause))
else
relation.order("#{@klass.table_name}.#{@klass.primary_key} DESC")
end
end
def limit(limits)
limits.present? ? spawn(@relation.take(limits)) : spawn
end
def offset(offsets)
offsets.present? ? spawn(@relation.skip(offsets)) : spawn
end
def on(join)
spawn(@relation.on(join))
end
def joins(join, join_type = nil)
return spawn if join.blank?
join_relation = case join
when String
@relation.join(join)
when Hash, Array, Symbol
if @klass.send(:array_of_strings?, join)
@relation.join(join.join(' '))
else
@relation.join(@klass.send(:build_association_joins, join))
end
else
@relation.join(join, join_type)
end
spawn(join_relation).tap { |r| r.readonly = true }
end
def where(*args)
return spawn if args.blank?
builder = PredicateBuilder.new(Arel::Sql::Engine.new(@klass))
conditions = if [String, Array].include?(args.first.class)
merged = @klass.send(:merge_conditions, args.size > 1 ? Array.wrap(args) : args.first)
Arel::SqlLiteral.new(merged) if merged
elsif args.first.is_a?(Hash)
attributes = @klass.send(:expand_hash_conditions_for_aggregates, args.first)
builder.build_from_hash(attributes, table)
else
args.first
end
conditions.is_a?(String) ? spawn(@relation.where(conditions)) : spawn(@relation.where(*conditions))
end
private
def reverse_sql_order(order_query)
order_query.to_s.split(/,/).each { |s|
if s.match(/\s(asc|ASC)$/)
s.gsub!(/\s(asc|ASC)$/, ' DESC')
elsif s.match(/\s(desc|DESC)$/)
s.gsub!(/\s(desc|DESC)$/, ' ASC')
else
s.concat(' DESC')
end
}.join(',')
end
end
end
|