@@ -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,57 +46,83 @@ 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
+ puts "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
+ puts "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
+ puts content_id
105
+ puts links . inspect
106
+ puts 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
76
125
return { editions : { content_store : "live" } } unless with_drafts
77
-
78
- <<-SQL . strip_heredoc
79
- CASE WHEN EXISTS (
80
- SELECT 1 FROM editions AS e
81
- WHERE content_store = 'draft'
82
- AND e.document_id = documents.id
83
- )
84
- THEN editions.content_store = 'draft'
85
- ELSE editions.content_store = 'live'
86
- END
87
- SQL
88
126
end
89
127
90
128
def group_results ( results )
@@ -98,10 +136,135 @@ def group_results(results)
98
136
99
137
def result_hash ( row )
100
138
{
101
- content_id : row [ 1 ] ,
102
- locale : row [ 2 ] ,
103
- edition_id : row [ 3 ] ,
139
+ content_id : row [ 1 ] || row [ 2 ] ,
140
+ locale : row [ 3 ] ,
141
+ edition_id : row [ 4 ] ,
142
+ has_own_links : has_own_links_result ( row ) ,
143
+ is_linked_to : is_linked_to_result ( row ) ,
104
144
}
105
145
end
146
+
147
+ def has_own_links_result ( row )
148
+ return false unless could_have_from_children?
149
+
150
+ check_for_from_children? ? row [ 5 ] : nil
151
+ end
152
+
153
+ def is_linked_to_result ( row )
154
+ return false unless could_have_to_children?
155
+
156
+ check_for_from_children? ? row [ 6 ] : row [ 5 ]
157
+ end
158
+
159
+ def check_for_from_children?
160
+ next_allowed_link_types_from && next_allowed_link_types_from . present?
161
+ end
162
+
163
+ def check_for_to_children?
164
+ next_allowed_link_types_to && next_allowed_link_types_to . present?
165
+ end
166
+
167
+ def could_have_from_children?
168
+ next_allowed_link_types_from . nil? || next_allowed_link_types_from . present?
169
+ end
170
+
171
+ def could_have_to_children?
172
+ next_allowed_link_types_to . nil? || next_allowed_link_types_to . present?
173
+ end
174
+
175
+ def has_own_links_field
176
+ if mode == :from
177
+ Arel . sql ( %{
178
+ EXISTS(
179
+ SELECT nested_links.id
180
+ FROM links AS nested_links
181
+ INNER JOIN link_sets AS nested_link_sets
182
+ ON nested_link_sets.id = nested_links.link_set_id
183
+ WHERE nested_link_sets.content_id = links.target_content_id
184
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
185
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
186
+ LIMIT 1
187
+ ) OR EXISTS(
188
+ SELECT nested_links.id
189
+ FROM links AS nested_links
190
+ INNER JOIN documents AS nested_documents
191
+ ON nested_documents.content_id = nested_links.target_content_id
192
+ WHERE nested_documents.content_id = links.target_content_id
193
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
194
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
195
+ LIMIT 1
196
+ )
197
+ } )
198
+ else
199
+ Arel . sql ( %{
200
+ EXISTS(
201
+ SELECT nested_links.id
202
+ FROM links AS nested_links
203
+ INNER JOIN link_sets AS nested_link_sets
204
+ ON nested_link_sets.id = nested_links.link_set_id
205
+ WHERE nested_links.target_content_id = link_sets.content_id
206
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
207
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
208
+ LIMIT 1
209
+ ) OR EXISTS(
210
+ SELECT nested_links.id
211
+ FROM links AS nested_links
212
+ INNER JOIN documents AS nested_documents
213
+ ON nested_documents.content_id = nested_links.target_content_id
214
+ WHERE nested_links.target_content_id = documents.content_id
215
+ #{ and_not_parent ( 'nested_links.target_content_id' ) }
216
+ AND (#{ allowed_links_condition ( next_allowed_link_types_from ) } )
217
+ LIMIT 1
218
+ )
219
+ } )
220
+ end
221
+ end
222
+
223
+ def is_linked_to_field
224
+ query = if mode == :from
225
+ "nested_links.target_content_id = links.target_content_id"
226
+ else
227
+ "(nested_links.target_content_id = link_sets.content_id OR nested_links.target_content_id = documents.content_id)"
228
+ end
229
+
230
+ Arel . sql ( %{
231
+ EXISTS(
232
+ SELECT nested_links.id
233
+ FROM links AS nested_links
234
+ LEFT JOIN link_sets AS nested_link_sets
235
+ ON nested_link_sets.id = nested_links.link_set_id
236
+ LEFT JOIN documents AS nested_documents
237
+ ON nested_documents.content_id = nested_links.target_content_id
238
+ WHERE #{ query }
239
+ #{ and_not_parent ( 'nested_link_sets.content_id' ) }
240
+ AND (#{ allowed_links_condition ( next_allowed_link_types_to ) } )
241
+ LIMIT 1
242
+ )
243
+ } )
244
+ end
245
+
246
+ def and_not_parent ( field )
247
+ return if parent_content_ids . empty?
248
+
249
+ quoted = parent_content_ids . map { |c_id | quote ( c_id ) }
250
+
251
+ "AND #{ field } NOT IN (#{ quoted . join ( ', ' ) } )"
252
+ end
253
+
254
+ def allowed_links_condition ( allowed_links )
255
+ each_link_type = allowed_links . map do |( link_type , next_links ) |
256
+ raise "Empty links for #{ link_type } on #{ content_id } " if next_links . empty?
257
+
258
+ quoted_next_links = next_links . map { |n | quote ( n ) }
259
+
260
+ "(links.link_type = #{ quote ( link_type ) } AND nested_links.link_type IN (#{ quoted_next_links . join ( ', ' ) } ))"
261
+ end
262
+
263
+ each_link_type . join ( " OR " )
264
+ end
265
+
266
+ def quote ( field )
267
+ ActiveRecord ::Base . connection . quote ( field )
268
+ end
106
269
end
107
270
end
0 commit comments