fancygrid 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|