Class: ActiveRecord::Refined::Dialect::Oracle

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

Overview

Oracle, reached through oracle_enhanced. Loaded only when a query is built for it.

Instance Method Summary collapse

Instance Method Details

#add_interval(date, amount, unit, subtract, _date_only) ⇒ Object

An INTERVAL literal would do, but its leading field is two digits wide unless told otherwise, so INTERVAL '100' DAY is an error. The functions that make an interval of a number take any size, one for the year-month intervals and one for the day-second.



21
22
23
24
25
26
27
# File 'lib/active_record/refined/dialect/oracle.rb', line 21

def add_interval(date, amount, unit, subtract, _date_only)
  interval = Arel::Nodes::NamedFunction.new(
    unit == :year || unit == :month ? "NUMTOYMINTERVAL" : "NUMTODSINTERVAL",
    [Arel::Nodes.build_quoted(amount), Arel::Nodes.build_quoted(unit.to_s.upcase)])
  Arel::Nodes::Grouping.new(
    Arel::Nodes::InfixOperation.new(subtract ? :- : :+, date, interval))
end

#check_json_aggregate_window(source, model) ⇒ Object

Raises:

  • (NotImplementedError)


96
97
98
99
100
# File 'lib/active_record/refined/dialect/oracle.rb', line 96

def check_json_aggregate_window(source, model)
  raise NotImplementedError,
    "#{source} over a window has no equivalent on " \
    "#{model.connection_db_config.adapter}"
end

#json_argument(value, model) ⇒ Object



48
49
50
# File 'lib/active_record/refined/dialect/oracle.rb', line 48

def json_argument(value, model)
  Arel.sql("#{quote(JSON.generate(value), model)} FORMAT JSON")
end

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

Oracle pairs a key with its value by the VALUE keyword rather than by position, keeps a NULL only when told NULL ON NULL, and returns the native JSON type unless a RETURNING asks for text ruby-oci8 can fetch.



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/active_record/refined/dialect/oracle.rb', line 83

def json_build(kind, keys, args, model)
  model.with_connection do |connection|
    compiled = args.map { |arg| connection.visitor.compile(arg) }
    body =
      if kind == :array
        compiled.join(", ")
      else
        keys.zip(compiled).map { |key, arg| "#{connection.quote(key)} VALUE #{arg}" }.join(", ")
      end
    Arel.sql("JSON_#{kind.to_s.upcase}(#{body} NULL ON NULL RETURNING VARCHAR2(4000))")
  end
end

#json_has_key(document, _name, path, _model) ⇒ Object



44
45
46
# File 'lib/active_record/refined/dialect/oracle.rb', line 44

def json_has_key(document, _name, path, _model)
  Arel::Nodes::NamedFunction.new("JSON_EXISTS", [document, path])
end

#json_path(document, dollar_path, _steps, json_value, model) ⇒ Object

Oracle keeps scalars and structures in different functions: JSON_VALUE reads a scalar out as text, JSON_QUERY a fragment as JSON. dig keeps JSON, so it takes JSON_QUERY with 23ai's ALLOW SCALARS, which returns a scalar leaf as itself rather than wrapping or refusing it.



33
34
35
36
37
38
39
40
41
42
# File 'lib/active_record/refined/dialect/oracle.rb', line 33

def json_path(document, dollar_path, _steps, json_value, model)
  unless json_value
    return Arel::Nodes::NamedFunction.new(
      "JSON_VALUE", [document, Arel::Nodes.build_quoted(dollar_path)])
  end
  Arel.sql(
    "JSON_QUERY(#{compile(document, model)}, " \
    "#{quote(dollar_path, model)} RETURNING VARCHAR2(4000) ALLOW SCALARS " \
    "NULL ON EMPTY)")
end

#json_remove(document, dollar_paths, _steps, model) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/active_record/refined/dialect/oracle.rb', line 71

def json_remove(document, dollar_paths, _steps, model)
  model.with_connection do |connection|
    removes = dollar_paths.map { |path| "REMOVE #{connection.quote(path)}" }
    Arel.sql(
      "JSON_TRANSFORM(#{connection.visitor.compile(document)}, " \
      "#{removes.join(', ')} RETURNING VARCHAR2(4000))")
  end
end

#json_set(document, _steps, dollar_path, value, expression, model) ⇒ Object

JSON_TRANSFORM is Oracle's one editing function; its SET and the value beside it are grammar, so the call is written out, RETURNING text that ruby-oci8 can fetch.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/active_record/refined/dialect/oracle.rb', line 55

def json_set(document, _steps, dollar_path, value, expression, model)
  model.with_connection do |connection|
    set =
      if expression
        connection.visitor.compile(expression)
      elsif json_document_value?(value)
        "#{connection.quote(JSON.generate(value))} FORMAT JSON"
      else
        connection.quote(value)
      end
    Arel.sql(
      "JSON_TRANSFORM(#{connection.visitor.compile(document)}, " \
      "SET #{connection.quote(dollar_path)} = #{set} RETURNING VARCHAR2(4000))")
  end
end