Module: Google::Cloud::Spanner::Convert::ClassMethods

Included in:
Google::Cloud::Spanner::Convert
Defined in:
lib/google/cloud/spanner/convert.rb

Overview

rubocop:disable all

Instance Method Summary collapse

Instance Method Details

#duration_to_number(duration) ⇒ Object



238
239
240
241
242
243
244
# File 'lib/google/cloud/spanner/convert.rb', line 238

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) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/google/cloud/spanner/convert.rb', line 114

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
  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) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/google/cloud/spanner/convert.rb', line 168

def grpc_type_for_field field
  return field.to_grpc_type if field.respond_to? :to_grpc_type

  if Array === field
    Google::Spanner::V1::Type.new(
      code: :ARRAY,
      array_element_type: grpc_type_for_field(field.first)
    )
  else
    Google::Spanner::V1::Type.new(code: field)
  end
end

#grpc_value_to_object(value, type) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/google/cloud/spanner/convert.rb', line 181

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
  end
end

#keys_are_ranges?(keys) ⇒ Boolean

Returns:

  • (Boolean)


297
298
299
300
301
302
303
# File 'lib/google/cloud/spanner/convert.rb', line 297

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) ⇒ Object



230
231
232
233
234
235
236
# File 'lib/google/cloud/spanner/convert.rb', line 230

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) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/google/cloud/spanner/convert.rb', line 50

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
  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
      raise ArgumentError,
            "A hash value cannot be set to type #{field}."
    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) ⇒ Object



39
40
41
42
43
44
45
46
47
48
# File 'lib/google/cloud/spanner/convert.rb', line 39

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) ⇒ Object



226
227
228
# File 'lib/google/cloud/spanner/convert.rb', line 226

def row_to_object row_types, row
  Hash[row_to_pairs(row_types, row)]
end

#row_to_pairs(row_types, row) ⇒ Object



220
221
222
223
224
# File 'lib/google/cloud/spanner/convert.rb', line 220

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) ⇒ Object



246
247
248
249
250
251
252
253
254
255
# File 'lib/google/cloud/spanner/convert.rb', line 246

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) ⇒ Object



257
258
259
260
261
# File 'lib/google/cloud/spanner/convert.rb', line 257

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) ⇒ Object



305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/google/cloud/spanner/convert.rb', line 305

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) ⇒ Object



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/google/cloud/spanner/convert.rb', line 263

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

  Google::Spanner::V1::KeyRange.new range_opts
end

#to_key_set(keys) ⇒ Object



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/google/cloud/spanner/convert.rb', line 280

def to_key_set keys
  return Google::Spanner::V1::KeySet.new(all: true) if keys.nil?
  keys = [keys] unless keys.is_a? Array
  return Google::Spanner::V1::KeySet.new(all: true) if keys.empty?

  if keys_are_ranges? keys
    key_ranges = keys.map { |r| to_key_range(r) }
    return Google::Spanner::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
  Google::Spanner::V1::KeySet.new keys: key_list
end

#to_query_params(params, types = nil) ⇒ Object



31
32
33
34
35
36
37
# File 'lib/google/cloud/spanner/convert.rb', line 31

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