fancygrid 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -2
- data/Gemfile +6 -9
- data/Gemfile.lock +88 -103
- data/README.md +226 -0
- data/ROADMAP +0 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/app/views/fancygrid/controls.html.haml +34 -0
- data/app/views/fancygrid/fancygrid.html.haml +18 -0
- data/app/views/fancygrid/search.html.haml +24 -0
- data/app/views/fancygrid/sort.html.haml +8 -0
- data/app/views/fancygrid/table.html.haml +25 -0
- data/config/locales/fancygrid.de.yml +17 -19
- data/config/locales/fancygrid.en.yml +14 -17
- data/fancygrid.gemspec +48 -88
- data/lib/assets/javascripts/fancygrid.js +425 -0
- data/lib/assets/javascripts/fancygrid.min.js +15 -0
- data/lib/assets/stylesheets/fancygrid.css +177 -0
- data/lib/fancygrid.rb +63 -44
- data/lib/fancygrid/column.rb +165 -0
- data/lib/fancygrid/controller/helper.rb +46 -0
- data/lib/fancygrid/grid.rb +171 -317
- data/lib/fancygrid/node.rb +85 -490
- data/lib/fancygrid/object_wrapper.rb +24 -0
- data/lib/fancygrid/orm/active_record.rb +39 -0
- data/lib/fancygrid/orm/sql_generator.rb +127 -0
- data/lib/fancygrid/view/helper.rb +44 -0
- data/lib/fancygrid/view_state.rb +161 -0
- data/spec/column_spec.rb +29 -0
- data/spec/dummy/app/controllers/application_controller.rb +48 -0
- data/spec/dummy/app/views/application/index.html.haml +11 -0
- data/spec/dummy/app/views/layouts/application.html.erb +1 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/development.rb +2 -2
- data/spec/dummy/config/environments/test.rb +2 -2
- data/spec/dummy/config/routes.rb +3 -2
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +26 -0
- data/spec/dummy/public/javascripts/jquery-1.4.2.js +6240 -0
- data/spec/dummy/public/javascripts/jquery-fancygrid.js +425 -0
- data/spec/dummy/public/javascripts/jquery-ui.js +41 -0
- data/spec/dummy/public/stylesheets/fancygrid.css +183 -0
- data/spec/node_spec.rb +79 -301
- data/spec/spec_helper.rb +0 -29
- data/spec/view_state_spec.rb +91 -0
- metadata +124 -137
- data/.bundle/config +0 -2
- data/README.rdoc +0 -299
- data/app/views/fancygrid/_cells.html.haml +0 -13
- data/app/views/fancygrid/base/controls.html.haml +0 -40
- data/app/views/fancygrid/base/list_frame.html.haml +0 -37
- data/app/views/fancygrid/base/search.html.haml +0 -33
- data/app/views/fancygrid/base/sort.html.haml +0 -20
- data/app/views/fancygrid/base/table_frame.html.haml +0 -45
- data/config/initializers/fancygrid.rb +0 -67
- data/lib/fancygrid/helper.rb +0 -129
- data/lib/fancygrid/query_generator.rb +0 -340
- data/lib/fancygrid/view.rb +0 -148
- data/lib/generators/install_generator.rb +0 -61
- data/lib/generators/views_generator.rb +0 -25
- data/lib/version.rb +0 -0
- data/public/images/fancygrid/add.png +0 -0
- data/public/images/fancygrid/clear.png +0 -0
- data/public/images/fancygrid/ddn.png +0 -0
- data/public/images/fancygrid/dn.png +0 -0
- data/public/images/fancygrid/dots.png +0 -0
- data/public/images/fancygrid/loading.gif +0 -0
- data/public/images/fancygrid/magnifier.png +0 -0
- data/public/images/fancygrid/next.png +0 -0
- data/public/images/fancygrid/order.png +0 -0
- data/public/images/fancygrid/prev.png +0 -0
- data/public/images/fancygrid/reload.png +0 -0
- data/public/images/fancygrid/remove.png +0 -0
- data/public/images/fancygrid/spacer.gif +0 -0
- data/public/images/fancygrid/submit.png +0 -0
- data/public/images/fancygrid/th_bg.png +0 -0
- data/public/images/fancygrid/up.png +0 -0
- data/public/images/fancygrid/uup.png +0 -0
- data/public/javascripts/fancygrid.js +0 -477
- data/public/javascripts/fancygrid.min.js +0 -17
- data/public/stylesheets/fancygrid.css +0 -289
- data/public/stylesheets/fancygrid.scss +0 -302
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/production.log +0 -0
- data/spec/dummy/log/server.log +0 -0
- data/spec/dummy/log/test.log +0 -1026
- data/spec/dummy/public/javascripts/application.js +0 -2
- data/spec/dummy/public/javascripts/controls.js +0 -965
- data/spec/dummy/public/javascripts/dragdrop.js +0 -974
- data/spec/dummy/public/javascripts/effects.js +0 -1123
- data/spec/dummy/public/javascripts/prototype.js +0 -6001
- data/spec/dummy/public/javascripts/rails.js +0 -175
- data/spec/grid_spec.rb +0 -15
- data/spec/integration/navigation_spec.rb +0 -9
- data/spec/query_generator_spec.rb +0 -358
@@ -1,45 +0,0 @@
|
|
1
|
-
.fg-fancygrid{ :class => fancygrid.name }
|
2
|
-
- if fancygrid.has_complex_search?
|
3
|
-
= render(:template => Fancygrid.search_template, :locals => { :fancygrid => fancygrid })
|
4
|
-
- if fancygrid.has_top_control?
|
5
|
-
= render(:template => Fancygrid.controls_template, :locals => { :fancygrid => fancygrid, :css_class => :"controls top" })
|
6
|
-
|
7
|
-
.fg-tablewrapper
|
8
|
-
%table
|
9
|
-
%tr.fg-header
|
10
|
-
- fancygrid.each_visible_leaf do |leaf|
|
11
|
-
%th{ :class => leaf.css_class, :table => leaf.record_table_name, :column => leaf.name, :order => leaf.applied_sort_order }
|
12
|
-
.fg-head-wrapper.fg-order-tag
|
13
|
-
= leaf.human_name
|
14
|
-
|
15
|
-
- if fancygrid.has_simple_search?
|
16
|
-
%tr.fg-search
|
17
|
-
- fancygrid.each_visible_leaf do |leaf|
|
18
|
-
%td{ :class => leaf.css_class }
|
19
|
-
- next unless leaf.searchable
|
20
|
-
- case leaf.search_input_kind
|
21
|
-
- when :none
|
22
|
-
= text_field_tag( leaf.tag_name, leaf.search_value, :class => :"fg-attribute" )
|
23
|
-
- when :select
|
24
|
-
= select_tag( leaf.tag_name, options_for_select(leaf.search_select_collection, :selected => leaf.search_value), :class => :"fg-attribute" )
|
25
|
-
|
26
|
-
- fancygrid.each_record do |record|
|
27
|
-
%tr.fg-row{ :class => fancygrid.css_proc_evaluate(record) }
|
28
|
-
- fancygrid.each_visible_leaf do |leaf|
|
29
|
-
%td{ :class => leaf.css_class }
|
30
|
-
= render_fancygrid_leaf(record, leaf, &format_block)
|
31
|
-
|
32
|
-
- if fancygrid.has_bottom_control?
|
33
|
-
= render(:template => Fancygrid.controls_template, :locals => { :fancygrid => fancygrid, :css_class => :"controls bottom" })
|
34
|
-
- if fancygrid.has_sort_window?
|
35
|
-
= render(:template => Fancygrid.sort_template, :locals => { :fancygrid => fancygrid })
|
36
|
-
|
37
|
-
- unless fancygrid.is_static?
|
38
|
-
:javascript
|
39
|
-
$(function(){
|
40
|
-
var fancyOptions = #{fancygrid.js_options};
|
41
|
-
$(".fg-fancygrid.#{fancygrid.name}").fancygrid(fancyOptions);
|
42
|
-
if(!fancyOptions.isStatic){
|
43
|
-
$(".fg-fancygrid.#{fancygrid.name}").fancygrid("reloadPage");
|
44
|
-
}
|
45
|
-
});
|
@@ -1,67 +0,0 @@
|
|
1
|
-
Fancygrid.setup do |config|
|
2
|
-
|
3
|
-
# The path to the table template which is rendered when the grid type is set
|
4
|
-
# to :table
|
5
|
-
#
|
6
|
-
# config.table_template = "fancygrid/base/table_frame"
|
7
|
-
|
8
|
-
# The path to the list template which is rendered when the grid type is set
|
9
|
-
# to :list
|
10
|
-
#
|
11
|
-
# config.list_template = "fancygrid/base/list_frame"
|
12
|
-
|
13
|
-
# The path to the controls template which is rendered at the top and the
|
14
|
-
# bottom of a grid
|
15
|
-
#
|
16
|
-
# config.controls_template = "fancygrid/base/controls"
|
17
|
-
|
18
|
-
# The path to the sort template which defines the view of the column sorting window
|
19
|
-
#
|
20
|
-
# config.sort_template = "fancygrid/base/sort"
|
21
|
-
|
22
|
-
# The path to the search template which defines the view of the complex search
|
23
|
-
#
|
24
|
-
# config.search_template = "fancygrid/base/search"
|
25
|
-
|
26
|
-
# The prefix that is used for every cells template. Default value is
|
27
|
-
# "fancygrid" so every template is expected in the "/app/views/fancygrid"
|
28
|
-
# directory
|
29
|
-
#
|
30
|
-
# config.cells_template_directory = "fancygrid"
|
31
|
-
|
32
|
-
# The default cells template name. This is combined with the
|
33
|
-
# 'default_cells_template_directory' to get the full template name
|
34
|
-
#
|
35
|
-
# config.cells_template = "_cells"
|
36
|
-
|
37
|
-
# Specifies the the internationalization namespace where the plugin will
|
38
|
-
# lookup for translations.
|
39
|
-
#
|
40
|
-
# config.i18n_scope = "fancygrid"
|
41
|
-
|
42
|
-
# Value specifying whether the grid name is automatily used as template name
|
43
|
-
# to render a grids cells
|
44
|
-
#
|
45
|
-
# config.use_grid_name_as_cells_template = false
|
46
|
-
|
47
|
-
# Value specifying whether the search is visible or not when the grid is
|
48
|
-
# rendered for the first time.
|
49
|
-
#
|
50
|
-
# config.search_visible = false
|
51
|
-
|
52
|
-
# Specifies the default grid type. Available values are :table and :list
|
53
|
-
# :table will render the data inside a table. Each record will get its own
|
54
|
-
# table row and each attribute its own cell.
|
55
|
-
# :list will render each record inside an unordered list as an li element.
|
56
|
-
# you must provide a rendering block or a template to render each record.
|
57
|
-
#
|
58
|
-
# config.default_grid_type = :table
|
59
|
-
|
60
|
-
# Default options for number of pages selection
|
61
|
-
#
|
62
|
-
# config.default_per_page_options = [5, 10, 15, 20, 25, 30, 40, 50]
|
63
|
-
|
64
|
-
# Default value for number of pagers selection
|
65
|
-
#
|
66
|
-
# config.default_per_page_selection = 20
|
67
|
-
end
|
data/lib/fancygrid/helper.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
require "active_support/hash_with_indifferent_access"
|
2
|
-
|
3
|
-
module Fancygrid
|
4
|
-
|
5
|
-
module Helper
|
6
|
-
|
7
|
-
def fancygrid_params(name)
|
8
|
-
opts = params[:fancygrid] || HashWithIndifferentAccess.new({})
|
9
|
-
opts[name]
|
10
|
-
end
|
11
|
-
|
12
|
-
def fancygrid_remote_call?(name)
|
13
|
-
!fancygrid_params(name).nil?
|
14
|
-
end
|
15
|
-
|
16
|
-
# Creates a fancygrid instance for the given model name, its class and
|
17
|
-
# its table name.
|
18
|
-
# === Example
|
19
|
-
# fancygrid_for :users do |grid|
|
20
|
-
#
|
21
|
-
# # specify attributes to display
|
22
|
-
# grid.attributes( :id, :username, :email )
|
23
|
-
#
|
24
|
-
# # specify the callback url for ajax loading
|
25
|
-
# grid.url = users_path
|
26
|
-
#
|
27
|
-
# # finally call find with some customized find options
|
28
|
-
# grid.find( :order => "users.created_at DESC" )
|
29
|
-
#
|
30
|
-
# end
|
31
|
-
def fancygrid_for(name, klass = nil, table_name = nil)#:yields: grid
|
32
|
-
raise "block missing" unless block_given?
|
33
|
-
|
34
|
-
@fancygrid ||= HashWithIndifferentAccess.new({})
|
35
|
-
@fancygrid[name] ||= Grid.new(name, klass, table_name, params)
|
36
|
-
|
37
|
-
fancygrid_instance = @fancygrid[name]
|
38
|
-
|
39
|
-
yield fancygrid_instance
|
40
|
-
|
41
|
-
view_opts = fancygrid_params(name)
|
42
|
-
view_opts ||= fancygrid_instance.load_view_proc_evaluate
|
43
|
-
|
44
|
-
# load the fancygrid view
|
45
|
-
fancygrid_instance.load_view(view_opts || {})
|
46
|
-
|
47
|
-
# store the view right back
|
48
|
-
fancygrid_instance.store_view_proc_evaluate
|
49
|
-
|
50
|
-
# now the fancygrid setup is complete and the view is loaded
|
51
|
-
# run the database query when we are in the remote state
|
52
|
-
if !fancygrid_instance.is_static? && fancygrid_remote_call?(name)
|
53
|
-
fancygrid_instance.query_for_data
|
54
|
-
end
|
55
|
-
|
56
|
-
fancygrid_instance.sort_leafs!
|
57
|
-
end
|
58
|
-
|
59
|
-
# Renders an existing fancygrid for the given name. You can append a rendering block
|
60
|
-
# or pass a template name as an option for custom rendering.
|
61
|
-
# === Options
|
62
|
-
# * <tt>data</tt> - The data to render
|
63
|
-
# * <tt>template</tt> - The template to use for custom rendering columns
|
64
|
-
# * <tt>url</tt> - The callback url for ajax
|
65
|
-
# * <tt>search_visible</tt> - If true, the search will be visible
|
66
|
-
# * <tt>hide_top_control</tt> - If true, the top control bar will be hidden
|
67
|
-
# * <tt>hide_bottom_control</tt> - If true, the bottom control bar will be hidden
|
68
|
-
# * <tt>grid_type</tt> - may be one of <tt>:list</tt> table <tt>:table</tt> to render a list or a table
|
69
|
-
def fancygrid(name, options=nil, &block)#:yields: column, record, value
|
70
|
-
store_name = name.to_s
|
71
|
-
raise "Missing fancygrid for name '#{store_name}'" if(@fancygrid.nil? || @fancygrid[store_name].nil?)
|
72
|
-
fancygrid_instance = @fancygrid[store_name]
|
73
|
-
|
74
|
-
options ||= {}
|
75
|
-
[:data, :template, :url, :search_visible, :hide_top_control,
|
76
|
-
:hide_bottom_control, :grid_type, :search_formats
|
77
|
-
].each do |option|
|
78
|
-
fancygrid_instance.send(option.to_s + "=", options[option]) if options[option]
|
79
|
-
end
|
80
|
-
|
81
|
-
format_block = block_given? ? block : nil
|
82
|
-
template = Fancygrid.table_template
|
83
|
-
template = Fancygrid.list_template if(fancygrid_instance.grid_type.to_s == "list")
|
84
|
-
|
85
|
-
render(:template => template, :locals => {
|
86
|
-
:fancygrid => fancygrid_instance,
|
87
|
-
:cells_block => format_block, :format_block => format_block
|
88
|
-
})
|
89
|
-
end
|
90
|
-
|
91
|
-
# Renders the given <tt>record</tt>, <tt>leaf</tt> and <tt>value</tt> with the
|
92
|
-
# leafs template or the passed rendering block. The result is a column cell content.
|
93
|
-
def format_fancygrid_value(record, leaf, value=nil, &format_block)
|
94
|
-
if block_given?
|
95
|
-
if defined?(Haml::Helpers) && is_haml?
|
96
|
-
capture_haml(leaf, record, value, &format_block)
|
97
|
-
else
|
98
|
-
capture(leaf, record, value, &format_block)
|
99
|
-
end
|
100
|
-
else
|
101
|
-
render( :template => leaf.root.template, :locals => {
|
102
|
-
:grid => leaf.root, :table => leaf.root,
|
103
|
-
:record => record,
|
104
|
-
:cell => leaf, :column => leaf,
|
105
|
-
:value => value
|
106
|
-
})
|
107
|
-
end
|
108
|
-
end
|
109
|
-
alias :fancy_rendering_for :format_fancygrid_value # backward compatibility
|
110
|
-
|
111
|
-
# Returns the <tt>value</tt> of the given <tt>leaf</tt> if it is not <tt>:formatable</tt>.
|
112
|
-
# Otherwie the <tt>leaf</tt> ist <tt>value</tt> and the <tt>record</tt> will
|
113
|
-
# be passed to the <tt>format_fancygrid_value</tt> method to render and format
|
114
|
-
# the value. The result is a column cell content.
|
115
|
-
def render_fancygrid_leaf(record, leaf, &format_block)
|
116
|
-
value = leaf.value_from(record)
|
117
|
-
return value if(!leaf.formatable && leaf.root.grid_type == :table)
|
118
|
-
format_fancygrid_value(record, leaf, value, &format_block)
|
119
|
-
end
|
120
|
-
alias :fancyvalue_for :render_fancygrid_leaf # backward compatibility
|
121
|
-
|
122
|
-
def fancygrid_button name, translate_scope, default, alt=nil
|
123
|
-
title = I18n.t(translate_scope, :default => default, :scope => Fancygrid.i18n_scope)
|
124
|
-
alt ||= title
|
125
|
-
image_tag('/images/fancygrid/spacer.gif', :size => '16x16', :class => "#{name} fg-button", :title => title, :alt => title ).html_safe
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
@@ -1,340 +0,0 @@
|
|
1
|
-
require "active_support/hash_with_indifferent_access"
|
2
|
-
|
3
|
-
module Fancygrid
|
4
|
-
class QueryGenerator#:nodoc:
|
5
|
-
|
6
|
-
OPERATOR_NAMES = [
|
7
|
-
:equal, :not_equal, :less, :less_equal, :greater, :greater_equal, :starts_with, :ends_with,
|
8
|
-
:like, :is_null, :is_not_null, :is_true, :is_not_true, :is_false, :is_not_false, :in, :not_in
|
9
|
-
]
|
10
|
-
|
11
|
-
attr_accessor :query, :fancygrid
|
12
|
-
|
13
|
-
def initialize(options=nil, grid=nil)
|
14
|
-
options ||= {}
|
15
|
-
options = ActiveSupport::HashWithIndifferentAccess.new(options)
|
16
|
-
|
17
|
-
self.query = {}
|
18
|
-
self.fancygrid = grid
|
19
|
-
|
20
|
-
self.select(options[:select])
|
21
|
-
self.apply_pagination(options[:pagination])
|
22
|
-
self.apply_search_conditions(options[:operator] || :and, options[:conditions])
|
23
|
-
self.apply_sort_order(options[:order])
|
24
|
-
end
|
25
|
-
|
26
|
-
def parse_options(options=nil)#:nodoc:
|
27
|
-
options ||= {}
|
28
|
-
[:conditions, :order, :group, :having, :limit, :offset, :joins, :include, :select, :from, :readonly, :lock].each do |option|
|
29
|
-
self.send(option, options[option]) unless options[option].nil?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Takes a hash like { :page => 2, :per_page => 20 } and translates it into :limit and :offset options which are
|
34
|
-
# then applied to the final query
|
35
|
-
#
|
36
|
-
def apply_pagination(options=nil)
|
37
|
-
options ||= {}
|
38
|
-
options = ActiveSupport::HashWithIndifferentAccess.new(options)
|
39
|
-
self.limit(options[:per_page].to_i)
|
40
|
-
self.offset(options[:page].to_i * self.limit())
|
41
|
-
end
|
42
|
-
|
43
|
-
# Takes a hash like { :column => "users.name", :order => "asc" } and translates it into the :order option and
|
44
|
-
# then applies it to the final query
|
45
|
-
#
|
46
|
-
def apply_sort_order(options=nil)
|
47
|
-
self.order("#{options[:column]} #{options[:order].to_s.upcase}") if options
|
48
|
-
end
|
49
|
-
|
50
|
-
# Takes an operator and an conditions hash like { :<table> => { :<column> => [{ :oparator => <op>, :value => <value> }] } }
|
51
|
-
# and converts them into a query joined by the given operator
|
52
|
-
#
|
53
|
-
def apply_search_conditions(operator, search_conditions)
|
54
|
-
return unless search_conditions
|
55
|
-
|
56
|
-
operator = logical_operator(operator)
|
57
|
-
|
58
|
-
conditions = []
|
59
|
-
arguments = []
|
60
|
-
|
61
|
-
# backward compatibility
|
62
|
-
search_conditions = search_conditions.map do |table, columns|
|
63
|
-
columns.map do |column, value|
|
64
|
-
if value.is_a?(Hash)
|
65
|
-
if value.keys.all? { |key| key.to_s.match(/^\d+$/) }
|
66
|
-
# for hashes like this
|
67
|
-
# :<table> => {
|
68
|
-
# :<column> => {
|
69
|
-
# "0" => { :oparator => <op>, :value => <value> },
|
70
|
-
# "1" => { :oparator => <op>, :value => <value> },
|
71
|
-
# "2" => { :oparator => <op>, :value => <value> }
|
72
|
-
# }
|
73
|
-
# }
|
74
|
-
#
|
75
|
-
value.map{ |key, opts|
|
76
|
-
{ :column => "#{table}.#{column}", :operator => opts[:operator], :value => opts[:value] }
|
77
|
-
}
|
78
|
-
else
|
79
|
-
# for hashes like this
|
80
|
-
# :<table> => {
|
81
|
-
# :<column> => {
|
82
|
-
# :oparator => <op>, :value => <value>
|
83
|
-
# }
|
84
|
-
# }
|
85
|
-
#
|
86
|
-
{ :column => "#{table}.#{column}", :operator => value[:operator], :value => value[:value] }
|
87
|
-
end
|
88
|
-
elsif value.is_a?(Array)
|
89
|
-
# for hashes like this
|
90
|
-
# :<table> => {
|
91
|
-
# :<column> => {
|
92
|
-
# [{ :oparator => <op>, :value => <value> },
|
93
|
-
# { :oparator => <op>, :value => <value> },
|
94
|
-
# { :oparator => <op>, :value => <value> }]
|
95
|
-
# }
|
96
|
-
# }
|
97
|
-
#
|
98
|
-
value.map{ |opts|
|
99
|
-
{ :column => "#{table}.#{column}", :operator => opts[:operator], :value => opts[:value] }
|
100
|
-
}
|
101
|
-
else
|
102
|
-
# for hashes like this
|
103
|
-
# :<table> => {
|
104
|
-
# :<column> => <value>
|
105
|
-
# }
|
106
|
-
#
|
107
|
-
unless value.blank?
|
108
|
-
op = (fancygrid and fancygrid.simple_search_operator(table, column) or :like).to_s
|
109
|
-
{ :column => "#{table}.#{column}", :operator => op, :value => value }
|
110
|
-
else
|
111
|
-
nil
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
search_conditions = search_conditions.flatten
|
117
|
-
|
118
|
-
search_conditions.each do |options|
|
119
|
-
next unless options
|
120
|
-
sql_query, value = comparison_operator(options[:column], options[:operator], options[:value])
|
121
|
-
conditions << sql_query
|
122
|
-
arguments << value if (value)
|
123
|
-
end
|
124
|
-
|
125
|
-
conditions = [conditions.join(operator)] + arguments
|
126
|
-
append_conditions(:and, conditions)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Joins two conditions arrays or strings with the given operator
|
130
|
-
#
|
131
|
-
# === Example
|
132
|
-
#
|
133
|
-
# condition1 = ["first_name = ?", first_name]
|
134
|
-
# condition2 = ["last_name = ?", last_name]
|
135
|
-
#
|
136
|
-
# join_conditions(:and, condition1, condition2)
|
137
|
-
# # => ["(first_name = ?) AND (last_name = ?)", first_name, last_name]
|
138
|
-
#
|
139
|
-
def join_conditions(operator, conditions1, conditions2)
|
140
|
-
conditions1 = Array(conditions1)
|
141
|
-
conditions2 = Array(conditions2)
|
142
|
-
operator = logical_operator(operator).gsub(" ", "")
|
143
|
-
|
144
|
-
if conditions1.empty?
|
145
|
-
return [] if conditions2.empty?
|
146
|
-
return conditions2
|
147
|
-
elsif conditions2.empty?
|
148
|
-
return conditions1
|
149
|
-
end
|
150
|
-
|
151
|
-
left_sql = conditions1.shift
|
152
|
-
right_sql = conditions2.shift
|
153
|
-
|
154
|
-
if left_sql.blank?
|
155
|
-
return [] if right_sql.blank?
|
156
|
-
return [right_sql] + conditions2
|
157
|
-
elsif right_sql.blank?
|
158
|
-
return [left_sql] + conditions1
|
159
|
-
end
|
160
|
-
|
161
|
-
conditions = "(#{left_sql}) #{operator} (#{right_sql})"
|
162
|
-
return [conditions] + conditions1 + conditions2
|
163
|
-
end
|
164
|
-
|
165
|
-
def append_conditions(operator, conditions)
|
166
|
-
self.query[:conditions] = join_conditions(operator, self.query[:conditions], conditions)
|
167
|
-
end
|
168
|
-
|
169
|
-
# An SQL fragment like “administrator = 1”, ["user_name = ?", username], or ["user_name = :user_name", { :user_name => user_name }]
|
170
|
-
#
|
171
|
-
def conditions(conditions=nil)
|
172
|
-
if conditions
|
173
|
-
append_conditions(:and, conditions)
|
174
|
-
end
|
175
|
-
self.query[:conditions]
|
176
|
-
end
|
177
|
-
|
178
|
-
# An SQL fragment like “created_at DESC, name”.
|
179
|
-
#
|
180
|
-
def order(order_by=nil)
|
181
|
-
self.query[:order] = order_by if order_by
|
182
|
-
self.query[:order]
|
183
|
-
end
|
184
|
-
|
185
|
-
# An SQL fragment like “created_at DESC, name”.
|
186
|
-
#
|
187
|
-
def group(group_by=nil)
|
188
|
-
self.query[:group] = group_by if group_by
|
189
|
-
self.query[:group]
|
190
|
-
end
|
191
|
-
|
192
|
-
# An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
|
193
|
-
#
|
194
|
-
def having(having_sql=nil)
|
195
|
-
self.query[:having] = having_sql if having_sql
|
196
|
-
self.query[:having]
|
197
|
-
end
|
198
|
-
|
199
|
-
# An integer determining the limit on the number of rows that should be returned.
|
200
|
-
#
|
201
|
-
def limit(num=nil)
|
202
|
-
self.query[:limit] = num if num
|
203
|
-
self.query[:limit]
|
204
|
-
end
|
205
|
-
|
206
|
-
# An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
|
207
|
-
#
|
208
|
-
def offset(num=nil)
|
209
|
-
self.query[:offset] = num if num
|
210
|
-
self.query[:offset]
|
211
|
-
end
|
212
|
-
|
213
|
-
# Either an SQL fragment for additional joins like “LEFT JOIN comments ON comments.post_id = id” (rarely needed),
|
214
|
-
# named associations in the same form used for the :include option, which will perform an INNER JOIN on the
|
215
|
-
# associated table(s), or an array containing a mixture of both strings and named associations. If the value is a
|
216
|
-
# string, then the records will be returned read-only since they will have attributes that do not correspond to the
|
217
|
-
# table’s columns. Pass :readonly => false to override.
|
218
|
-
#
|
219
|
-
def joins(to_join_with=nil)
|
220
|
-
self.query[:joins] = to_join_with if to_join_with
|
221
|
-
self.query[:joins]
|
222
|
-
end
|
223
|
-
|
224
|
-
# Names associations that should be loaded alongside. The symbols named refer to already defined associations.
|
225
|
-
# See eager loading under Associations.
|
226
|
-
#
|
227
|
-
def include(to_include=nil)
|
228
|
-
self.query[:include] = to_include if to_include
|
229
|
-
self.query[:include]
|
230
|
-
end
|
231
|
-
|
232
|
-
# By default, this is “*” as in “SELECT * FROM”, but can be changed if you, for example, want to do a join but not
|
233
|
-
# include the joined columns. Takes a string with the SELECT SQL fragment (e.g. “id, name”).
|
234
|
-
#
|
235
|
-
def select(select = nil)
|
236
|
-
if select
|
237
|
-
self.query[:select] = Array(self.query[:select])
|
238
|
-
self.query[:select] |= Array(select)
|
239
|
-
|
240
|
-
if self.query[:select].include?("*")
|
241
|
-
self.query[:select] = ["*"]
|
242
|
-
end
|
243
|
-
end
|
244
|
-
self.query[:select]
|
245
|
-
end
|
246
|
-
|
247
|
-
# By default, this is the table name of the class, but can be changed to an alternate table name
|
248
|
-
# (or even the name of a database view).
|
249
|
-
#
|
250
|
-
def from(table_name=nil)
|
251
|
-
self.query[:from] = table_name if table_name
|
252
|
-
self.query[:from]
|
253
|
-
end
|
254
|
-
|
255
|
-
# Mark the returned records read-only so they cannot be saved or updated.
|
256
|
-
#
|
257
|
-
def readonly(value=nil)
|
258
|
-
self.query[:readonly] = value unless value.nil?
|
259
|
-
self.query[:readonly]
|
260
|
-
end
|
261
|
-
|
262
|
-
# An SQL fragment like “FOR UPDATE” or “LOCK IN SHARE MODE”. :lock => true gives connection’s default exclusive
|
263
|
-
# lock, usually “FOR UPDATE”.
|
264
|
-
#
|
265
|
-
def lock(value=nil)
|
266
|
-
self.query[:lock] = value unless value.nil?
|
267
|
-
self.query[:lock]
|
268
|
-
end
|
269
|
-
|
270
|
-
private
|
271
|
-
def comparison_operator(column, operator, value)
|
272
|
-
operator = case operator.to_s
|
273
|
-
when "equal"
|
274
|
-
"="
|
275
|
-
when "not_equal"
|
276
|
-
"!="
|
277
|
-
when "less"
|
278
|
-
"<"
|
279
|
-
when "less_equal"
|
280
|
-
"<="
|
281
|
-
when "greater"
|
282
|
-
">"
|
283
|
-
when "greater_equal"
|
284
|
-
">="
|
285
|
-
when "starts_with"
|
286
|
-
value = "#{value.to_param}%"
|
287
|
-
"LIKE"
|
288
|
-
when "ends_with"
|
289
|
-
value = "%#{value.to_param}"
|
290
|
-
"LIKE"
|
291
|
-
when "like"
|
292
|
-
value = "%#{value.to_param}%"
|
293
|
-
"LIKE"
|
294
|
-
when "is_null"
|
295
|
-
value = nil
|
296
|
-
"IS NULL"
|
297
|
-
when "is_not_null"
|
298
|
-
value = nil
|
299
|
-
"IS NOT NULL"
|
300
|
-
when "is_true"
|
301
|
-
value = nil
|
302
|
-
"IS TRUE"
|
303
|
-
when "is_not_true"
|
304
|
-
value = nil
|
305
|
-
"IS NOT TRUE"
|
306
|
-
when "is_false"
|
307
|
-
value = nil
|
308
|
-
"IS FALSE"
|
309
|
-
when "is_not_false"
|
310
|
-
value = nil
|
311
|
-
"IS NOT FALSE"
|
312
|
-
when "in"
|
313
|
-
value = value.split(",")
|
314
|
-
"IN"
|
315
|
-
when "not_in"
|
316
|
-
value = value.split(",")
|
317
|
-
"NOT IN"
|
318
|
-
else
|
319
|
-
"="
|
320
|
-
end
|
321
|
-
|
322
|
-
if value.nil?
|
323
|
-
return "( #{column} #{operator} )", value
|
324
|
-
else
|
325
|
-
return "( #{column} #{operator} (?) )", value
|
326
|
-
end
|
327
|
-
|
328
|
-
end
|
329
|
-
|
330
|
-
def logical_operator(name)
|
331
|
-
case name.to_s
|
332
|
-
when "all", "and"
|
333
|
-
" AND "
|
334
|
-
else
|
335
|
-
" OR "
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
end
|
340
|
-
end
|