module Google::Cloud::Spanner::Convert::ClassMethods

rubocop:disable all

Public Instance Methods

duration_to_number(duration) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 248
def duration_to_number duration
  return nil if duration.nil?

  return duration.seconds if duration.nanos == 0

  duration.seconds + (duration.nanos / 1000000000.0)
end
field_for_object(obj) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 117
def field_for_object obj
  case obj
  when NilClass
    raise ArgumentError, "Cannot determine type for nil values."
  when String
    :STRING
  when Symbol
    :STRING
  when TrueClass
    :BOOL
  when FalseClass
    :BOOL
  when Integer
    :INT64
  # BigDecimal must be put before Numeric.
  when BigDecimal
    :NUMERIC
  when Numeric
    :FLOAT64
  when Time
    :TIMESTAMP
  when DateTime
    :TIMESTAMP
  when Date
    :DATE
  when Array
    if obj.empty?
      raise ArgumentError,
            "Cannot determine type for empty array values."
    end
    non_nil_fields = obj.compact.map { |e| field_for_object e }.compact
    if non_nil_fields.empty?
      raise ArgumentError,
            "Cannot determine type for array of nil values."
    end
    if non_nil_fields.uniq.count > 1
      raise ArgumentError,
            "Cannot determine type for array of different values."
    end
    [non_nil_fields.first]
  when Hash
    raw_type_pairs = obj.map do |key, value|
      [key, field_for_object(value)]
    end
    Fields.new Hash[raw_type_pairs]
  when Data
    obj.fields
  else
    if obj.respond_to?(:read) && obj.respond_to?(:rewind)
      :BYTES
    else
      raise ArgumentError,
            "Cannot determine type for #{obj.class} values."
    end
  end
end
grpc_type_for_field(field) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 174
def grpc_type_for_field field
  return field.to_grpc_type if field.respond_to? :to_grpc_type

  if Array === field
    V1::Type.new(
      code: :ARRAY,
      array_element_type: grpc_type_for_field(field.first)
    )
  else
    V1::Type.new(code: field)
  end
end
grpc_value_to_object(value, type) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 187
def grpc_value_to_object value, type
  return nil if value.kind == :null_value

  case type.code
  when :BOOL
    value.bool_value
  when :INT64
    Integer value.string_value
  when :FLOAT64
    if value.kind == :string_value
      if value.string_value == "Infinity"
        Float::INFINITY
      elsif value.string_value == "-Infinity"
        -Float::INFINITY
      elsif value.string_value == "NaN"
        Float::NAN
      else
        Float value.string_value
      end
    else
      value.number_value
    end
  when :TIMESTAMP
    Time.parse value.string_value
  when :DATE
    Date.parse value.string_value
  when :STRING
    value.string_value
  when :BYTES
    StringIO.new Base64.decode64 value.string_value
  when :ARRAY
    value.list_value.values.map do |v|
      grpc_value_to_object v, type.array_element_type
    end
  when :STRUCT
    Data.from_grpc value.list_value.values, type.struct_type.fields
  when :NUMERIC
    BigDecimal value.string_value
  when :JSON
    JSON.parse value.string_value
  end
end
keys_are_ranges?(keys) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 307
def keys_are_ranges? keys
  keys.each do |key|
    return true if key.is_a? ::Range
    return true if key.is_a? Google::Cloud::Spanner::Range
  end
  false
end
number_to_duration(number) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 240
def number_to_duration number
  return nil if number.nil?

  Google::Protobuf::Duration.new \
    seconds: number.to_i,
    nanos: (number.remainder(1) * 1000000000).round
end
object_to_grpc_value(obj, field = nil) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 51
def object_to_grpc_value obj, field = nil
  obj = obj.to_column_value if obj.respond_to? :to_column_value

  if obj.respond_to? :to_grpc_value_and_type
    return obj.to_grpc_value_and_type.first
  end

  case obj
  when NilClass
    Google::Protobuf::Value.new null_value: :NULL_VALUE
  when String
    Google::Protobuf::Value.new string_value: obj.to_s
  when Symbol
    Google::Protobuf::Value.new string_value: obj.to_s
  when TrueClass
    Google::Protobuf::Value.new bool_value: true
  when FalseClass
    Google::Protobuf::Value.new bool_value: false
  when Integer
    Google::Protobuf::Value.new string_value: obj.to_s
  # BigDecimal must be put before Numeric.
  when BigDecimal
    Google::Protobuf::Value.new string_value: obj.to_s("F")
  when Numeric
    if obj == Float::INFINITY
      Google::Protobuf::Value.new string_value: "Infinity"
    elsif obj == -Float::INFINITY
      Google::Protobuf::Value.new string_value: "-Infinity"
    elsif obj.respond_to?(:nan?) && obj.nan?
      Google::Protobuf::Value.new string_value: "NaN"
    else
      Google::Protobuf::Value.new number_value: obj.to_f
    end
  when Time
    Google::Protobuf::Value.new(string_value:
      obj.to_time.utc.strftime("%FT%T.%NZ"))
  when DateTime
    Google::Protobuf::Value.new(string_value:
      obj.to_time.utc.strftime("%FT%T.%NZ"))
  when Date
    Google::Protobuf::Value.new string_value: obj.to_s
  when Array
    arr_field = nil
    arr_field = field.first if Array === field
    Google::Protobuf::Value.new list_value:
      Google::Protobuf::ListValue.new(values:
        obj.map { |o| object_to_grpc_value(o, arr_field) })
  when Hash
    if field.is_a? Fields
      field.struct(obj).to_grpc_value
    else
      Google::Protobuf::Value.new string_value: obj.to_json
    end
  else
    if obj.respond_to?(:read) && obj.respond_to?(:rewind)
      obj.rewind
      content = obj.read.force_encoding("ASCII-8BIT")
      encoded_content = Base64.strict_encode64(content)
      Google::Protobuf::Value.new(string_value: encoded_content)
    else
      raise ArgumentError,
            "A value of type #{obj.class} is not supported."
    end
  end
end
object_to_grpc_value_and_type(obj, field = nil) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 40
def object_to_grpc_value_and_type obj, field = nil
  obj = obj.to_column_value if obj.respond_to? :to_column_value

  if obj.respond_to? :to_grpc_value_and_type
    return obj.to_grpc_value_and_type
  end

  field ||= field_for_object obj
  [object_to_grpc_value(obj, field), grpc_type_for_field(field)]
end
row_to_object(row_types, row) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 236
def row_to_object row_types, row
  Hash[row_to_pairs(row_types, row)]
end
row_to_pairs(row_types, row) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 230
def row_to_pairs row_types, row
  row_types.zip(row).map do |field, value|
    [field.name.to_sym, grpc_value_to_object(value, field.type)]
  end
end
time_to_timestamp(time) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 256
def time_to_timestamp time
  return nil if time.nil?

  # Force the object to be a Time object.
  time = time.to_time

  Google::Protobuf::Timestamp.new \
    seconds: time.to_i,
    nanos: time.nsec
end
timestamp_to_time(timestamp) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 267
def timestamp_to_time timestamp
  return nil if timestamp.nil?

  Time.at timestamp.seconds, Rational(timestamp.nanos, 1000)
end
to_input_params_and_types(params, types) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 315
def to_input_params_and_types params, types
  input_params = nil
  input_param_types = nil
  unless params.nil?
    input_param_pairs = to_query_params params, types
    input_params = Google::Protobuf::Struct.new \
      fields: Hash[input_param_pairs.map { |k, v| [k, v.first] }]
    input_param_types = Hash[
        input_param_pairs.map { |k, v| [k, v.last] }]
  end

  [input_params, input_param_types]
end
to_key_range(range) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 273
def to_key_range range
  range_opts = {
    start_closed: object_to_grpc_value(Array(range.begin)).list_value,
    end_closed: object_to_grpc_value(Array(range.end)).list_value }

  if range.respond_to?(:exclude_begin?) && range.exclude_begin?
    range_opts[:start_open] = range_opts[:start_closed]
    range_opts.delete :start_closed
  end
  if range.exclude_end?
    range_opts[:end_open] = range_opts[:end_closed]
    range_opts.delete :end_closed
  end

  V1::KeyRange.new range_opts
end
to_key_set(keys) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 290
def to_key_set keys
  return V1::KeySet.new(all: true) if keys.nil?
  keys = [keys] unless keys.is_a? Array
  return V1::KeySet.new(all: true) if keys.empty?

  if keys_are_ranges? keys
    key_ranges = keys.map { |r| to_key_range(r) }
    return V1::KeySet.new(ranges: key_ranges)
  end

  key_list = keys.map do |key|
    key = [key] unless key.is_a? Array
    object_to_grpc_value(key).list_value
  end
  V1::KeySet.new keys: key_list
end
to_query_params(params, types = nil) click to toggle source
# File lib/google/cloud/spanner/convert.rb, line 32
def to_query_params params, types = nil
  types ||= {}
  formatted_params = params.map do |key, obj|
    [String(key), object_to_grpc_value_and_type(obj, types[key])]
  end
  Hash[formatted_params]
end
to_request_options(options, tag_type: nil) click to toggle source

Build request options by replacing tag to respecitve statistics collection tag type.

@param [Hash] options Common request options.

* `:tag` (String) A tag used for statistics collection.

@param [Symbol] tag_type Request tag type.

Possible values are `request_tag`, `transaction_tag`

@return [Hash, nil]

# File lib/google/cloud/spanner/convert.rb, line 340
def to_request_options options, tag_type: nil
  return unless options

  return options unless options.key? :tag

  options.transform_keys { |k| k == :tag ? tag_type : k }
end