OSDN Git Service

fx Manifest
[pettanr/pettanr.git] / lib / manifest / list.rb
1
2 module Pettanr
3   module Manifest
4     class List
5       def self.set_default my_manifest
6         my_manifest.each {|item_name, list_manifest|
7           raise "undefined type for lists > #{item_name} > #{list_name}\n" unless list_manifest['type']
8           list_manifest['options'] ||= {}
9           list_manifest|['options'].each {|option_name, option_manifest|
10             option_manifest['default_page_size'] ||= 25
11             option_manifest['max_page_size'] ||= 100
12           }
13           @@types[list_manifest['type']].set_default list_manifest['options']
14               # 'required' 'number'
15         }
16       end
17       
18       class BaseList
19         def initialize page, page_size, operators, item_name, list_name, conf, manifest
20           @operators = operators
21           @item_name = item_name
22           @list_name = list_name
23           @conf = conf
24           @manifest = manifest
25           @default_page_size = @conf['default_page_size'] || 25
26           @max_page_size = @conf['max_page_size'] || 100
27           @page = self.page_number(page) 
28           @page_size = self.page_size page_size
29           
30           @model = @item_name.classify.constantize
31           @offset = (@page -1) * @page_size
32           @table_name = @model.table_name
33           if @model.content?
34             @owner_model = @model.owner_model
35             @owner_table_name = @owner_model.table_name if @owner_model
36           end
37         end
38         
39         def page_number prm = nil
40           page = prm.to_i
41           page = 1 if page < 1
42           page
43         end
44         
45         def page_size prm
46           page_size = prm.to_i
47           page_size = @max_page_size if page_size > @max_page_size
48           page_size = @default_page_size if page_size < 1
49           page_size
50         end
51         
52         def where
53           @model.list_where
54         end
55         
56         def includes
57           if @owner_model
58             if @owner_model.owner_model
59               {@owner_model.item_name => {@owner_model.owner_model.item_name => {}}}
60             else
61               {@owner_model.item_name => {}}
62             end
63           else
64             {}
65           end
66         end
67         
68         def order
69           @model.list_order
70         end
71         
72         def items
73           @model.where(self.where()).includes(self.includes).order(self.order).offset(@offset).limit(@page_size)
74         end
75         
76         def paginate
77           c = @model.where(self.where()).includes(self.includes).count
78           Kaminari.paginate_array(Array.new(c, nil)).page(@offset).per(@page_size)
79         end
80         
81         def self.add_action item_name, action_name, list_name, list_conf
82           return
83         end
84       end
85       
86       class PublicList < BaseList
87         
88         def self.set_default option_manifest
89         end
90         
91         def self._add_action item_name, action_name, list_name, list_conf
92           model = item_name.classify.constantize
93           controller_name = model.plural + 'Controller'
94           controller = controller_name.constantize
95           return if controller.method_defined?(action_name)
96           controller.define_method(action_name) do 
97             public_list
98           end
99         end
100       end
101       
102       class PrivateList < BaseList
103         def self.set_default option_manifest
104         end
105         
106         def where 
107           case @model.owner_type
108           when :author
109             operator = @operators.author
110           when :artist
111             operator = @operators.artist
112           end
113           t = if @owner_model
114             if @owner_model.owner_model
115               @owner_model.owner_model.table_name
116             else
117               @owner_model.table_name
118             end
119           else
120             @table_name
121           end
122           [t + '.' + @model.owner_type.to_s + '_id = ?', operator.id]
123         end
124       end
125       
126       class SystemResourceList < BaseList
127         def items
128           @model.enable_list
129         end
130         
131       end
132       
133       class HasManyList < BaseList
134         attr :association_model_name
135         def initialize page, page_size, operators, item_name, list_name, conf, manifest
136           super
137           @list_list_conf = @manifest.list(@item_name).lists[list_name] || {}
138           @association_name = @list_list_conf['association_name']
139           @has_many_conf = @manifest.model(@item_name).associations['has_many'] || {}
140           @association_conf = @has_many_conf[@association_name] || {}
141           @association_model_name = @association_conf['model']
142           @association_model = @association_model_name.classify.constantize
143           @foreign_key = @association_conf['foreign_key']
144          if @association_model.content?
145             @owner_model = @association_model.owner_model
146             @owner_table_name = @owner_model.table_name if @owner_model
147           end
148         end
149         
150         def self.set_default option_manifest
151           option_manifest['association_name'] ||= 100
152         end
153         
154         def where parent_item
155           w = @association_model.list_where
156           w += ' and ' unless w.blank?
157           [w + @association_model.table_name + '.' + @foreign_key + ' = ?', parent_item.id] 
158         end
159         
160         def includes
161     #   @with_model_name ? {@with_model_name.classify.constantize.table_name => {}} : {}
162           w = @owner_model ? {@owner_model.item_name => {}} : {}
163           w.merge({}) 
164         end
165         
166         def items parent_item
167            @association_model.where(self.where(parent_item)).includes(self.includes).order(self.order).offset(@offset).limit(@page_size)
168         end
169         
170         def paginate parent_item
171           Kaminari.paginate_array(Array.new(@association_model.where(self.where(parent_item)).includes(self.includes).count, nil)).page(@offset).per(@page_size)
172         end
173         
174         def self._add_action item_name, action_name, list_name, list_conf
175           model = item_name.classify.constantize
176           controller_name = model.plural + 'Controller'
177           controller = controller_name.constantize
178           association_name = list_conf['association_name']
179           has_many_conf = Pettanr::Application::manifest.model(item_name).associations['has_many'] || {}
180           association_conf = has_many_conf[association_name] || {}
181           association_model_name = association_conf['model']
182           return if controller.method_defined?(action_name)
183           controller.define_method(action_name) do 
184             has_many_list item_name, list_name, association_model_name, params
185           end
186         end
187         
188       end
189       
190       class HasManyThroughList < BaseList
191         attr :association_model_name
192         def initialize page, page_size, operators, item_name, list_name, conf, manifest
193           super
194           @list_list_conf = @manifest.list(@item_name).lists[list_name] || {}
195           @association_name = @list_list_conf['association_name']
196           @has_many_conf = @manifest.model(@item_name).associations['has_many'] || {}
197           @association_conf = @has_many_conf[@association_name] || {}
198           @association_through_model_name = @association_conf['through']
199           @association_through_model = @association_through_model_name.classify.constantize
200           @association_model_name = @association_conf['model']
201           @association_model = @association_model_name.classify.constantize
202           @foreign_key = @association_conf['foreign_key']
203          if @association_model.content?
204             @owner_model = @association_model.owner_model
205             @owner_table_name = @owner_model.table_name if @owner_model
206           end
207         end
208         
209         def where root_item
210           w = @association_model.list_where
211           w += ' and ' unless w.blank?
212           [w + @association_through_model.table_name + '.' + @foreign_key + ' = ?', root_item.id] 
213         end
214         
215         def includes
216           {@association_through_model.table_name => {@item_name => {}}}
217         end
218         
219         def items root_item
220            @association_model.where(self.where(root_item)).includes(self.includes).order(self.order).offset(@offset).limit(@page_size)
221         end
222         
223         def paginate root_item
224           Kaminari.paginate_array(Array.new(@association_model.where(self.where(root_item)).includes(self.includes).count, nil)).page(@offset).per(@page_size)
225         end
226         
227       end
228       
229       class FilterList < BaseList
230         attr :item_name, :from_model
231         def initialize page, page_size, operators, item_name, list_name, conf, manifest
232           super
233           @list_list_conf = @manifest.list(@item_name).lists[list_name] || {}
234           @from = @list_list_conf['from']
235           @from_model = @from.classify.constantize
236           @filter_key = @list_list_conf['filter_key']
237           @includes = @list_list_conf['includes']
238           
239           @with_model_name = @list_list_conf['with']
240         end
241         
242         def self.set_default my_manifest
243           option_manifest['from'] ||= 100
244           option_manifest['filter_key'] ||= 100
245         end
246         
247         def where filter_item
248           w = @model.list_where
249           w += ' and ' unless w.blank?
250           [w + @table_name + '.' + @filter_key + ' = ?', filter_item.id] 
251         end
252         
253         def includes
254           return @includes if @includes
255           w = @owner_model ? {@owner_model.item_name => {}} : {}
256           w.merge({@from => {} }) 
257         end
258         
259         def items filter_item
260           @model.where(self.where(filter_item)).includes(self.includes).order(self.order).offset(@offset).limit(@page_size)
261         end
262         
263         def paginate filter_item
264           Kaminari.paginate_array(Array.new(@model.where(self.where(filter_item)).includes(self.includes).count, nil)).page(@offset).per(@page_size)
265         end
266         
267         def self._add_action item_name, action_name, list_name, list_conf
268           model = item_name.classify.constantize
269           controller_name = model.plural + 'Controller'
270           controller = controller_name.constantize
271           list_list_conf = Pettanr::Application::manifest.list(item_name).lists[list_name] || {}
272           from = list_list_conf['from']
273           filter_model = from.classify.constantize
274           filter_key = list_list_conf['filter_key']
275           return if controller.method_defined?(action_name)
276           controller.define_method(action_name) do 
277             filter_list filter_model, params
278           end
279         end
280         
281       end
282       
283       class ThroughFilterList < FilterList
284         def initialize page, page_size, operators, item_name, list_name, conf, manifest
285           super
286           @through = @list_list_conf['through']
287         end
288         
289         def includes
290           {@through => {@from => {}} }
291         end
292         
293         def where filter_item
294           w = @model.list_where
295           w += ' and ' unless w.blank?
296           [w + @through + '.' + @filter_key + ' = ?', filter_item.id] 
297         end
298         
299       end
300       
301       class ElementFilterList < FilterList
302         def includes
303           {@owner_model.item_name => {}}
304         end
305         
306         def where filter_item
307           w = @model.list_where
308           w += ' and ' unless w.blank?
309           [w + @owner_table_name + '.' + @filter_key + ' = ?', filter_item.id] 
310         end
311         
312       end
313       
314       class PlayList
315         attr :params_offset, :params_count, :offset, :count, :limit
316         def initialize params_offset, params_count, operators, item_name, list_name, conf, manifest
317           @operators = operators
318           @item_name = item_name
319           @list_name = list_name
320           @conf = conf
321           @manifest = manifest
322           
323           @default_page_size = @conf['default_page_size'] || 25
324           @max_page_size = @conf['max_page_size'] || 100
325           @params_offset = params_offset
326           @params_count = params_count
327           @list_list_conf = @manifest.list(@item_name).lists[list_name] || {}
328           @model_name = @list_list_conf['model']
329           @filter_key = @list_list_conf['filter_key']
330           @model = @model_name.classify.constantize
331           @table_name = @model.table_name
332           if @model.content?
333             @owner_model = @model.owner_model
334             @owner_table_name = @owner_model.table_name if @owner_model
335           end
336         end
337         
338         def offset cnt, prm = nil
339           offset = prm.to_i
340           offset = cnt - 1 if offset >= cnt
341           offset = cnt - offset.abs if offset < 0
342           offset = 0 if offset < 0
343           offset
344         end
345         
346         def limit prm
347           prm ||= @default_page_size
348           count = prm.to_i
349           count = @max_page_size if count > @max_page_size
350           count = @default_page_size if count < 1
351           count
352         end
353         
354         def count filter_item
355           @count ||= @model.count(:conditions => self.where(filter_item), :include => self.includes).to_i
356         end
357         
358         def where filter_item
359           w = @model.list_where
360           w += ' and ' unless w.blank?
361           [w + @table_name + '.' + @filter_key + ' = ?', filter_item.id] 
362         end
363         
364         def includes
365           {@owner_model.item_name => {}}
366         end
367         
368         def order
369           @table_name + '.t'
370         end
371         
372         def items filter_item
373           c  = @count || self.count(filter_item)
374           o  = self.offset c, @offset
375           l  = self.limit @count
376           @model.where(self.where(filter_item)).includes(self.includes).order(self.order).offset(o).limit(l)
377         end
378         
379         def prev_offset filter_item
380           c  = @count || self.count(filter_item)
381           o  = self.offset c, @offset
382           l  = self.limit @count
383           if o > 0
384             if o - l < 0
385               0
386             else
387               o - l
388             end
389           else
390             nil
391           end
392         end
393         
394         def next_offset filter_item
395           c  = @count || self.count(filter_item)
396           o  = self.offset c, @offset
397           l  = self.limit @count
398           if o + l > c
399             nil
400           else
401             o + l
402           end
403         end
404         
405         def self.add_action item_name, action_name, list_name, list_conf
406           return
407         end
408       end
409       
410       @@types = {
411         'public' => PublicList, 'private' => PrivateList, 'system_resource' => SystemResourceList,
412         'has_many' => HasManyList, 'has_many_through' => HasManyThroughList, 'filter' => FilterList, 
413         'through_filter' => ThroughFilterList, 'element_filter' => ElementFilterList, 
414         'play' => PlayList
415       }
416       def initialize list_manifest
417         @list_manifest = list_manifest
418         @item_name = @list_manifest.item_name
419         @manifest = @list_manifest.manifest
420         @list_conf = @list_manifest.conf
421         @lists = {}
422         @list_manifest.lists.each {|list_name, conf|
423           type = conf['type']
424           @lists[list_name] = @@types[type]
425         }
426       end
427       
428       def open list_name, page, page_size, operators
429         raise "undefined list for #{@item_name}::#{list_name}\nconf:#{@list_conf}\n" unless @lists[list_name]
430         @lists[list_name].new page, page_size, operators, @item_name, list_name, @list_conf, @manifest
431       end
432       
433         def filer opt =  nil
434           paginate = opt ? @list.paginate(opt) : @list.paginate
435           @filer ||= @manifest.filer_managers[@item_name].open(@item_name, @items, @operators, paginate)
436         end
437         
438       def add_action action_name, list_name
439         @lists[list_name].add_action @item_name, action_name, list_name, @list_conf
440       end
441       
442     end
443   end
444 end
445