Class: Babik::Selection::Operation::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/babik/queryset/lib/selection/operation/base.rb

Overview

Base class

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(field, sql_operation, value) ⇒ Base

Construct a SQL operation

Parameters:

  • field (String)

    Name of the field. Prefixed with the table or table alias.

  • sql_operation (String)

    Template string with the SQL code or the operation. Something like ?field = ?value.



16
17
18
19
20
21
22
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 16

def initialize(field, sql_operation, value)
  @field = field
  @value = value
  @sql_operation_template = sql_operation.dup
  @sql_operation = sql_operation.dup
  _init_sql_operation
end

Instance Attribute Details

#fieldObject (readonly)

Returns the value of attribute field.



10
11
12
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 10

def field
  @field
end

#sql_operationObject (readonly)

Returns the value of attribute sql_operation.



10
11
12
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 10

def sql_operation
  @sql_operation
end

#sql_operation_templateObject (readonly)

Returns the value of attribute sql_operation_template.



10
11
12
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 10

def sql_operation_template
  @sql_operation_template
end

#valueObject (readonly)

Returns the value of attribute value.



10
11
12
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 10

def value
  @value
end

Class Method Details

.date_special_cases(field, operator, value) ⇒ Object

Special conversion of operations for date lookup



103
104
105
106
107
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 103

def self.date_special_cases(field, operator, value)
  return field, 'between', [value.beginning_of_day, value.end_of_day] if operator == 'date' && value.is_a?(::Date)
  return field, 'between', [Time(value.year, 1, 1).beginning_of_day, Time(value.year, 12, 31).end_of_day] if operator == 'year' && value.is_a?(::Date)
  [field, operator, value]
end

.escape(str) ⇒ Object

Escape a string



110
111
112
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 110

def self.escape(str)
  Babik::Database.escape(str)
end

.factory(field, operator, value) ⇒ Object

Operation factory



45
46
47
48
49
50
51
52
53
54
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 45

def self.factory(field, operator, value)
  # Some operators can have a secondary operator, like the year lookup that can be followed by
  # a gt, lt, equal, etc. Check this case, and get it to prepare its passing to the operation.
  raw_main_operator, secondary_operator = self.initialize_operators(operator)
  # The field, operator or value can change in some special cases, e.g. if operator is equals and the value
  # is an array, the operator should be 'in' actually.
  field, main_operator, value = self.special_cases(field, raw_main_operator, value)
  # At last, initialize operation
  self.initialize_operation(field, main_operator, secondary_operator, value)
end

.initialize_operation(field, operator, secondary_operator, value) ⇒ Babik::Selection::Operation::Base

Initialize the operation

Parameters:

  • field (String)

    Field name that takes part in the selection operation.

  • operator (Symbol)

    Operator name that defines which operation will be used.

  • secondary_operator (Symbol)

    Some operations have a particular operation that’s it.

  • value (String, Integer)

    Value used in the selection.

Returns:



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 84

def self.initialize_operation(field, operator, secondary_operator, value)
  operation_class_name = Babik::Selection::Operation::CORRESPONDENCE[operator.to_sym]
  raise "Unknown lookup #{operator}" unless operation_class_name
  operation_class = Object.const_get("Babik::Selection::Operation::#{operation_class_name}")
  # If there is a secondary operator, pass it to the operation
  if secondary_operator || operation_class.operator?
    return operation_class.new(field, secondary_operator, value)
  end
  # Otherwise, return the operation
  operation_class.new(field, value)
end

.initialize_operators(operator) ⇒ Array<String>

Initialize the operators (both main and secondary) When the operator is an Array, it means it actually is two different operators. The first one will be applied to the main operation, and the second one, to the lookup. e.g. selector ‘created_at__time__gt’ contains two operators, ‘time’ and ‘gt’.

Returns:

  • (Array<String>)

    Array with both operations. First element will be the main operation, the second one will be the secondary operation. If there is no secondary operation, the second item will be nil.



69
70
71
72
73
74
75
76
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 69

def self.initialize_operators(operator)
  secondary_operator = nil
  if operator.class == Array
    secondary_operator = operator[1]
    operator = operator[0]
  end
  [operator, secondary_operator]
end

.operator?Boolean

Inform if the operation has a operator

Returns:

  • (Boolean)

    True if the operation needs an operator, false otherwise.



58
59
60
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 58

def self.operator?
  self.const_defined?('HAS_OPERATOR') && self.const_get('HAS_OPERATOR')
end

.special_cases(field, operator, value) ⇒ Object

Special conversion of operations



97
98
99
100
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 97

def self.special_cases(field, operator, value)
  return field, 'in', value if operator == 'equal' && [Babik::QuerySet::Base, Array].include?(value.class)
  self.date_special_cases(field, operator, value)
end

Instance Method Details

#_init_sql_operationObject

Replace the SQL operation template and store the result in sql_operation attribute



25
26
27
28
29
30
31
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 25

def _init_sql_operation
  @sql_operation = @sql_operation_template.sub('?field', @field).sub('?value', '?')
  # Use Rails SQL escaping and avoid possible SQL-injection issues
  # and also several DB-related issues (like MySQL escaping quotes by \' instead of '')
  # Only if it has not been already replaced
  @sql_operation = ActiveRecord::Base.sanitize_sql([@sql_operation, @value]) if @sql_operation.include?('?')
end

#db_engineObject

Return the database engine: sqlite3, mysql, postgres, mssql, etc.



40
41
42
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 40

def db_engine
  Babik::Database.config[:adapter]
end

#to_sString

Convert the operation to string

Returns:

  • (String)

    Return the replaced SQL operation.



35
36
37
# File 'lib/babik/queryset/lib/selection/operation/base.rb', line 35

def to_s
  @sql_operation
end