@@ -3,26 +3,38 @@ class EditionLinks
3
3
def self . from ( content_id ,
4
4
locale :,
5
5
with_drafts :,
6
- allowed_link_types : nil )
6
+ allowed_link_types : nil ,
7
+ parent_content_ids : [ ] ,
8
+ next_allowed_link_types_from : nil ,
9
+ next_allowed_link_types_to : nil )
7
10
new (
8
11
content_id :,
9
12
mode : :from ,
10
13
locale :,
11
14
with_drafts :,
12
15
allowed_link_types :,
16
+ parent_content_ids :,
17
+ next_allowed_link_types_from :,
18
+ next_allowed_link_types_to :,
13
19
) . call
14
20
end
15
21
16
22
def self . to ( content_id ,
17
23
locale :,
18
24
with_drafts :,
19
- allowed_link_types : nil )
25
+ allowed_link_types : nil ,
26
+ parent_content_ids : [ ] ,
27
+ next_allowed_link_types_from : nil ,
28
+ next_allowed_link_types_to : nil )
20
29
new (
21
30
content_id :,
22
31
mode : :to ,
23
32
locale :,
24
33
with_drafts :,
25
34
allowed_link_types :,
35
+ parent_content_ids :,
36
+ next_allowed_link_types_from :,
37
+ next_allowed_link_types_to :,
26
38
) . call
27
39
end
28
40
@@ -34,42 +46,79 @@ def call
34
46
35
47
private
36
48
37
- attr_reader :content_id , :mode , :locale , :with_drafts , :allowed_link_types
49
+ attr_reader :content_id ,
50
+ :mode ,
51
+ :locale ,
52
+ :with_drafts ,
53
+ :allowed_link_types ,
54
+ :parent_content_ids ,
55
+ :next_allowed_link_types_from ,
56
+ :next_allowed_link_types_to
38
57
39
58
def initialize (
40
59
content_id :,
41
60
mode :,
42
61
locale :,
43
62
with_drafts :,
44
- allowed_link_types :
63
+ allowed_link_types :,
64
+ parent_content_ids : [ ] ,
65
+ next_allowed_link_types_from : nil ,
66
+ next_allowed_link_types_to : nil
45
67
)
46
68
@content_id = content_id
47
69
@mode = mode
48
70
@locale = locale
49
71
@with_drafts = with_drafts
50
72
@allowed_link_types = allowed_link_types
73
+ @parent_content_ids = parent_content_ids
74
+ @next_allowed_link_types_from = next_allowed_link_types_from
75
+ @next_allowed_link_types_to = next_allowed_link_types_to
51
76
end
52
77
53
78
def links_results
54
- query = Link . left_joins ( edition : :document )
55
- where ( query )
56
- . order ( link_type : :asc , position : :asc )
57
- . pluck ( :link_type , link_field , "documents.locale" , "editions.id" )
58
- end
79
+ condition = { }
80
+ # condition[:"documents.locale"] = locale if locale
81
+ condition [ :link_type ] = allowed_link_types if allowed_link_types
59
82
60
- def link_field
61
- mode == :from ? :target_content_id : "documents.content_id"
83
+ if mode == :from
84
+ Rails . logger . debug "from"
85
+ Link
86
+ . left_joins ( edition : :document )
87
+ . left_joins ( :link_set )
88
+ . where ( "documents.content_id" : content_id )
89
+ . or ( Link . where ( "link_sets.content_id" : content_id ) )
90
+ . where ( condition )
91
+ . where ( draft_condition )
92
+ . order ( link_type : :asc , position : :asc )
93
+ . pluck ( *fields )
94
+ else
95
+ Rails . logger . debug "to"
96
+ links = Link
97
+ . left_joins ( edition : :document )
98
+ . left_joins ( :link_set )
99
+ . where ( "links.target_content_id" : content_id )
100
+ . where ( condition )
101
+ # .where(draft_condition)
102
+ . order ( link_type : :asc , position : :asc )
103
+ . pluck ( *fields )
104
+ Rails . logger . debug content_id
105
+ Rails . logger . debug links . inspect
106
+ Rails . logger . debug Link . left_joins ( edition : :document ) . left_joins ( :link_set ) . where ( "links.target_content_id" : content_id ) . where ( condition ) . inspect
107
+ links
108
+ end
62
109
end
63
110
64
- def where ( query )
65
- condition = if mode == :from
66
- { "documents.content_id" : content_id }
67
- else
68
- { target_content_id : content_id }
69
- end
70
- condition [ :"documents.locale" ] = locale if locale
71
- condition [ :link_type ] = allowed_link_types if allowed_link_types
72
- query . where ( condition ) . where ( draft_condition )
111
+ def fields
112
+ base_fields = [
113
+ :link_type ,
114
+ mode == :from ? :target_content_id : "documents.content_id" ,
115
+ mode == :from ? :target_content_id : "link_sets.content_id" ,
116
+ "documents.locale" ,
117
+ "editions.id" ,
118
+ ]
119
+ base_fields << has_own_links_field if check_for_from_children?
120
+ base_fields << is_linked_to_field if check_for_to_children?
121
+ base_fields
73
122
end
74
123
75
124
def draft_condition
@@ -98,10 +147,135 @@ def group_results(results)
98
147
99
148
def result_hash ( row )
100
149
{
101
- content_id : row [ 1 ] ,
102
- locale : row [ 2 ] ,
103
- edition_id : row [ 3 ] ,
150
+ content_id : row [ 1 ] || row [ 2 ] ,
151
+ locale : row [ 3 ] ,
152
+ edition_id : row [ 4 ] ,
153
+ has_own_links : has_own_links_result ( row ) ,
154
+ is_linked_to : is_linked_to_result ( row ) ,
104
155
}
105
156
end
157
+
158
+ def has_own_links_result ( row )
159
+ return false unless could_have_from_children?
160
+
161
+ check_for_from_children? ? row [ 5 ] : nil
162
+ end
163
+
164
+ def is_linked_to_result ( row )
165
+ return false unless could_have_to_children?
166
+
167
+ check_for_from_children? ? row [ 6 ] : row [ 5 ]
168
+ end
169
+
170
+ def check_for_from_children?
171
+ next_allowed_link_types_from && next_allowed_link_types_from . present?
172
+ end
173
+
174
+ def check_for_to_children?
175
+ next_allowed_link_types_to && next_allowed_link_types_to . present?
176
+ end
177
+
178
+ def could_have_from_children?
179
+ next_allowed_link_types_from . nil? || next_allowed_link_types_from . present?
180
+ end
181
+
182
+ def could_have_to_children?
183
+ next_allowed_link_types_to . nil? || next_allowed_link_types_to . present?
184
+ end
185
+
186
+ def has_own_links_field
187
+ if mode == :from
188
+ Arel . sql ( %{
189
+ EXISTS(
190
+ SELECT nested_links.id
191
+ FROM links AS nested_links
192
+ INNER JOIN link_sets AS nested_link_sets
193
+ ON nested_link_sets.id = nested_links.link_set_id
194
+ WHERE nested_link_sets.content_id = links.target_content_id
195
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
196
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
197
+ LIMIT 1
198
+ ) OR EXISTS(
199
+ SELECT nested_links.id
200
+ FROM links AS nested_links
201
+ INNER JOIN documents AS nested_documents
202
+ ON nested_documents.content_id = nested_links.target_content_id
203
+ WHERE nested_documents.content_id = links.target_content_id
204
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
205
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
206
+ LIMIT 1
207
+ )
208
+ } )
209
+ else
210
+ Arel . sql ( %{
211
+ EXISTS(
212
+ SELECT nested_links.id
213
+ FROM links AS nested_links
214
+ INNER JOIN link_sets AS nested_link_sets
215
+ ON nested_link_sets.id = nested_links.link_set_id
216
+ WHERE nested_links.target_content_id = link_sets.content_id
217
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
218
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
219
+ LIMIT 1
220
+ ) OR EXISTS(
221
+ SELECT nested_links.id
222
+ FROM links AS nested_links
223
+ INNER JOIN documents AS nested_documents
224
+ ON nested_documents.content_id = nested_links.target_content_id
225
+ WHERE nested_links.target_content_id = documents.content_id
226
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
227
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
228
+ LIMIT 1
229
+ )
230
+ } )
231
+ end
232
+ end
233
+
234
+ def is_linked_to_field
235
+ query = if mode == :from
236
+ "nested_links.target_content_id = links.target_content_id"
237
+ else
238
+ "(nested_links.target_content_id = link_sets.content_id OR nested_links.target_content_id = documents.content_id)"
239
+ end
240
+
241
+ Arel . sql ( %{
242
+ EXISTS(
243
+ SELECT nested_links.id
244
+ FROM links AS nested_links
245
+ LEFT JOIN link_sets AS nested_link_sets
246
+ ON nested_link_sets.id = nested_links.link_set_id
247
+ LEFT JOIN documents AS nested_documents
248
+ ON nested_documents.content_id = nested_links.target_content_id
249
+ WHERE #{ query }
250
+ #{ and_not_parent ( 'nested_link_sets.content_id' ) }
251
+ AND (#{ allowed_links_condition ( next_allowed_link_types_to ) } )
252
+ LIMIT 1
253
+ )
254
+ } )
255
+ end
256
+
257
+ def and_not_parent ( field )
258
+ return if parent_content_ids . empty?
259
+
260
+ quoted = parent_content_ids . map { |c_id | quote ( c_id ) }
261
+
262
+ "AND #{ field } NOT IN (#{ quoted . join ( ', ' ) } )"
263
+ end
264
+
265
+ def allowed_links_condition ( allowed_links )
266
+ each_link_type = allowed_links . map do |( link_type , next_links ) |
267
+ raise "Empty links for #{ link_type } on #{ content_id } " if next_links . empty?
268
+
269
+ quoted_next_links = next_links . map { |n | quote ( n ) }
270
+
271
+ "(links.link_type = #{ quote ( link_type ) } AND nested_links.link_type IN (#{ quoted_next_links . join ( ', ' ) } ))"
272
+ end
273
+
274
+ each_link_type . join ( " OR " )
275
+ end
276
+
277
+ def quote ( field )
278
+ ActiveRecord ::Base . connection . quote ( field )
279
+ end
106
280
end
107
281
end
0 commit comments