Module: Airrel::FormulaBuilder

Extended by:
FormulaBuilder
Included in:
FormulaBuilder
Defined in:
lib/airrel/formula_builder.rb

Instance Method Summary collapse

Instance Method Details

#all(*formulas) ⇒ Object

helper methods for building formulas programmatically



73
# File 'lib/airrel/formula_builder.rb', line 73

def all(*formulas) = "AND(#{formulas.join(", ")})"

#any(*formulas) ⇒ Object



75
# File 'lib/airrel/formula_builder.rb', line 75

def any(*formulas) = "OR(#{formulas.join(", ")})"

#blank(field) ⇒ Object



91
# File 'lib/airrel/formula_builder.rb', line 91

def blank(field) = "{#{field}} = BLANK()"

#build_predicate(field, value) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/airrel/formula_builder.rb', line 16

def build_predicate(field, value)
  case value
  when nil
    "{#{field}} = BLANK()"
  when true
    "{#{field}} = TRUE()"
  when false
    "{#{field}} = FALSE()"
  when String
    "{#{field}} = #{escape_string(value)}"
  when Numeric
    "{#{field}} = #{value}"
  when Range
    if value.exclude_end?
      "AND({#{field}} >= #{escape_value(value.begin)}, {#{field}} < #{escape_value(value.end)})"
    else
      "AND({#{field}} >= #{escape_value(value.begin)}, {#{field}} <= #{escape_value(value.end)})"
    end
  when Array
    # IN query - use OR
    or_conditions = value.map { |v| build_predicate(field, v) }
    "OR(#{or_conditions.join(", ")})"
  else
    # fallback - convert to string and escape
    "{#{field}} = #{escape_string(value.to_s)}"
  end
end

#contains(field, value) ⇒ Object

for multi-select fields (checks if array contains value)



100
# File 'lib/airrel/formula_builder.rb', line 100

def contains(field, value) = "FIND(#{escape_string(value.to_s)}, {#{field}})"

#contains_all(field, *values) ⇒ Object

check if multi-select contains ALL of the values



109
110
111
112
# File 'lib/airrel/formula_builder.rb', line 109

def contains_all(field, *values)
  formulas = values.map { |v| contains(field, v) }
  formulas.size == 1 ? formulas.first : all(*formulas)
end

#contains_any(field, *values) ⇒ Object

check if multi-select contains ANY of the values



103
104
105
106
# File 'lib/airrel/formula_builder.rb', line 103

def contains_any(field, *values)
  formulas = values.map { |v| contains(field, v) }
  formulas.size == 1 ? formulas.first : any(*formulas)
end

#eq(field, value) ⇒ Object



79
# File 'lib/airrel/formula_builder.rb', line 79

def eq(field, value) = build_predicate(field, value)

#escape_string(str) ⇒ Object

escape a string value for use in airtable formulas airtable uses backslash escaping: \ escapes the next character so we need to escape backslashes first, then quotes



47
48
49
50
51
# File 'lib/airrel/formula_builder.rb', line 47

def escape_string(str)
  # escape backslashes first (\ -> \\), then quotes (' -> \', " -> \")
  escaped = str.to_s.gsub("\\", "\\\\\\\\").gsub(/['"]/, '\\\\\0')
  "'#{escaped}'"
end

#escape_value(value) ⇒ Object

escape any value (delegates to appropriate method)



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/airrel/formula_builder.rb', line 54

def escape_value(value)
  case value
  when String
    escape_string(value)
  when Numeric
    value.to_s
  when nil
    "BLANK()"
  when true
    "TRUE()"
  when false
    "FALSE()"
  else
    escape_string(value.to_s)
  end
end

#find(field, search_string) ⇒ Object



95
# File 'lib/airrel/formula_builder.rb', line 95

def find(field, search_string) = "FIND(#{escape_string(search_string)}, {#{field}})"

#gt(field, value) ⇒ Object



83
# File 'lib/airrel/formula_builder.rb', line 83

def gt(field, value) = "{#{field}} > #{value}"

#gte(field, value) ⇒ Object



85
# File 'lib/airrel/formula_builder.rb', line 85

def gte(field, value) = "{#{field}} >= #{value}"

#hash_to_formula(conditions, field_mappings = {}) ⇒ Object



7
8
9
10
11
12
13
14
# File 'lib/airrel/formula_builder.rb', line 7

def hash_to_formula(conditions, field_mappings = {})
  formulas = conditions.map do |key, value|
    field_name = field_mappings[key.to_s] || key.to_s
    build_predicate(field_name, value)
  end

  formulas.size == 1 ? formulas.first : "AND(#{formulas.join(", ")})"
end

#lt(field, value) ⇒ Object



87
# File 'lib/airrel/formula_builder.rb', line 87

def lt(field, value) = "{#{field}} < #{value}"

#lte(field, value) ⇒ Object



89
# File 'lib/airrel/formula_builder.rb', line 89

def lte(field, value) = "{#{field}} <= #{value}"

#neq(field, value) ⇒ Object



81
# File 'lib/airrel/formula_builder.rb', line 81

def neq(field, value) = none(eq(field, value))

#none(formula) ⇒ Object



77
# File 'lib/airrel/formula_builder.rb', line 77

def none(formula) = "NOT(#{formula})"

#present(field) ⇒ Object



93
# File 'lib/airrel/formula_builder.rb', line 93

def present(field) = none(blank(field))

#search(field, search_string) ⇒ Object



97
# File 'lib/airrel/formula_builder.rb', line 97

def search(field, search_string) = "SEARCH(#{escape_string(search_string)}, {#{field}})"