Class: ActiveRecord::Refined::Dialect::Postgresql

Inherits:
Dialect
  • Object
show all
Defined in:
lib/active_record/refined/dialect/postgresql.rb

Overview

PostgreSQL, and the adapters that answer for the same server.

Instance Method Summary collapse

Instance Method Details

#array_comparisons_supported?Boolean

Returns:

  • (Boolean)


8
# File 'lib/active_record/refined/dialect/postgresql.rb', line 8

def array_comparisons_supported? = true

#bit_count(expr, _model) ⇒ Object

PostgreSQL counts the bits of a bit string rather than a number, so the argument is cast, to bit(64) for a negative to come back as the MySQL family has it.



17
18
19
# File 'lib/active_record/refined/dialect/postgresql.rb', line 17

def bit_count(expr, _model)
  AST::Function.new("BIT_COUNT", [AST::Cast.new(expr, "bit(64)")])
end

#bitwise_operators_supported?Boolean

Returns:

  • (Boolean)


9
# File 'lib/active_record/refined/dialect/postgresql.rb', line 9

def bitwise_operators_supported? = true

#bitwise_xor(left, right) ⇒ Object

PostgreSQL's XOR is #, where ^ is exponentiation.



22
23
24
# File 'lib/active_record/refined/dialect/postgresql.rb', line 22

def bitwise_xor(left, right)
  Arel::Nodes::InfixOperation.new("#", left, right)
end

#collate(operand, name, model) ⇒ Object

PostgreSQL's own collation names are case-sensitive and upper, "C", "POSIX", so the name is quoted as an identifier to keep it from folding to lower case. The quoter is asked to spell it, as excluded's VALUES(column) is on MySQL.



119
120
121
122
123
124
# File 'lib/active_record/refined/dialect/postgresql.rb', line 119

def collate(operand, name, model)
  AST.check_name(name, COLLATION_NAME, "collation name")
  quoted = model.with_connection { |connection| connection.quote_column_name(name) }
  Arel::Nodes::InfixOperation.new(
    "COLLATE", operand, Arel::Nodes::SqlLiteral.new(quoted))
end

#excluded(column, _model) ⇒ Object



26
27
28
# File 'lib/active_record/refined/dialect/postgresql.rb', line 26

def excluded(column, _model)
  AST::Column.new(:excluded, column)
end

#grouping_supported?(_kind) ⇒ Boolean

Returns:

  • (Boolean)


106
# File 'lib/active_record/refined/dialect/postgresql.rb', line 106

def grouping_supported?(_kind) = true

#json_aggregate_name(kind) ⇒ Object



91
92
93
# File 'lib/active_record/refined/dialect/postgresql.rb', line 91

def json_aggregate_name(kind)
  kind == :arrayagg ? "jsonb_agg" : "jsonb_object_agg"
end

#json_build(kind, keys, args, _model) ⇒ Object



76
77
78
79
80
# File 'lib/active_record/refined/dialect/postgresql.rb', line 76

def json_build(kind, keys, args, _model)
  Arel::Nodes::NamedFunction.new(
    kind == :array ? "jsonb_build_array" : "jsonb_build_object",
    json_build_body(kind, keys, args))
end

#json_build_argument(value, _model) ⇒ Object

jsonb_build_* takes typed arguments, so a JSON literal is cast; left untyped it would be text, and land as a string.



84
85
86
87
88
89
# File 'lib/active_record/refined/dialect/postgresql.rb', line 84

def json_build_argument(value, _model)
  Arel::Nodes::NamedFunction.new(
    "CAST", [Arel::Nodes::As.new(
      Arel::Nodes.build_quoted(JSON.generate(value)),
      Arel::Nodes::SqlLiteral.new("jsonb"))])
end

#json_contains(document, json, _model) ⇒ Object



41
42
43
# File 'lib/active_record/refined/dialect/postgresql.rb', line 41

def json_contains(document, json, _model)
  Arel::Nodes::Contains.new(document, json)
end

#json_has_key(document, name, _path, _model) ⇒ Object

The ? operator, which a GIN index matches where jsonb_exists never is.



46
47
48
# File 'lib/active_record/refined/dialect/postgresql.rb', line 46

def json_has_key(document, name, _path, _model)
  Arel::Nodes::InfixOperation.new(:"?", document, name)
end

#json_keys(document, model) ⇒ Object



50
51
52
53
54
55
# File 'lib/active_record/refined/dialect/postgresql.rb', line 50

def json_keys(document, model)
  sql = compile(document, model)
  Arel.sql("CASE WHEN jsonb_typeof(#{sql}) = 'object' " \
           "THEN COALESCE((SELECT jsonb_agg(k) FROM jsonb_object_keys(#{sql}) k), " \
           "CAST('[]' AS jsonb)) END")
end

#json_literal(json, _model) ⇒ Object

An untyped JSON literal beside a jsonb operand coerces to jsonb, so it passes as it is.



37
38
39
# File 'lib/active_record/refined/dialect/postgresql.rb', line 37

def json_literal(json, _model)
  json
end

#json_path(document, _dollar_path, steps, json_value, _model) ⇒ Object



30
31
32
33
# File 'lib/active_record/refined/dialect/postgresql.rb', line 30

def json_path(document, _dollar_path, steps, json_value, _model)
  Arel::Nodes::InfixOperation.new(
    json_value ? :"#>" : :"#>>", document, Arel::Nodes.build_quoted(steps))
end

#json_remove(document, _dollar_paths, steps, _model) ⇒ Object

jsonb subtracts an array of keys; an untyped array literal would be read as a single key, so it is cast to text.



68
69
70
71
72
73
74
# File 'lib/active_record/refined/dialect/postgresql.rb', line 68

def json_remove(document, _dollar_paths, steps, _model)
  keys = Arel::Nodes::NamedFunction.new(
    "CAST", [Arel::Nodes::As.new(
      Arel::Nodes.build_quoted(steps), Arel::Nodes::SqlLiteral.new("text[]"))])
  # Grouped because - binds tighter than #>.
  Arel::Nodes::InfixOperation.new(:-, Arel::Nodes::Grouping.new(document), keys)
end

#json_set(document, steps, _dollar_path, value, expression, _model) ⇒ Object

jsonb_set takes jsonb: an expression is turned into it, and a Ruby value goes in as the JSON that says it -- '"x"' rather than 'x'.



59
60
61
62
63
64
# File 'lib/active_record/refined/dialect/postgresql.rb', line 59

def json_set(document, steps, _dollar_path, value, expression, _model)
  set = expression ? Arel::Nodes::NamedFunction.new("to_jsonb", [expression]) :
                     Arel::Nodes.build_quoted(JSON.generate(value))
  Arel::Nodes::NamedFunction.new(
    "jsonb_set", [document, Arel::Nodes.build_quoted(steps), set])
end

#string_agg(operand, separator, orders, string, model) ⇒ Object

STRING_AGG takes text and nothing else -- over an integer column it is a function that does not exist -- so the operand is cast unless the model says it is a string already.



98
99
100
101
102
103
104
# File 'lib/active_record/refined/dialect/postgresql.rb', line 98

def string_agg(operand, separator, orders, string, model)
  unless string
    operand = Arel::Nodes::NamedFunction.new(
      "CAST", [Arel::Nodes::As.new(operand, Arel::Nodes::SqlLiteral.new("text"))])
  end
  string_agg_call("STRING_AGG", operand, separator, orders, model)
end