Class: Google::Cloud::Spanner::Fields

Inherits:
Object
  • Object
show all
Defined in:
lib/google/cloud/spanner/fields.rb

Overview

# Fields

Represents the field names and types of data returned by Cloud Spanner.

See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

results = db.execute "SELECT * FROM users"

results.fields.pairs.each do |name, type|
  puts "Column #{name} is type #{type}"
end

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(types) ⇒ Fields

Creates Google::Cloud::Spanner::Fields object from types. See Client#fields.

This object can be used to create Data objects by providing values that match the field types. See #struct.

See [Data Types - Constructing a STRUCT](cloud.google.com/spanner/docs/data-types#constructing-a-struct).

Examples:

Create a STRUCT value with named fields using Fields object:

require "google/cloud/spanner"

named_type = Google::Cloud::Spanner::Fields.new(
  { id: :INT64, name: :STRING, active: :BOOL }
)
named_data = named_type.struct(
  { id: 42, name: nil, active: false }
)

Create a STRUCT value with anonymous field names:

require "google/cloud/spanner"

anon_type = Google::Cloud::Spanner::Fields.new(
  [:INT64, :STRING, :BOOL]
)
anon_data = anon_type.struct [42, nil, false]

Create a STRUCT value with duplicate field names:

require "google/cloud/spanner"

dup_type = Google::Cloud::Spanner::Fields.new(
  [[:x, :INT64], [:x, :STRING], [:x, :BOOL]]
)
dup_data = dup_type.struct [42, nil, false]

Parameters:

  • types (Array, Hash)

    Accepts an array or hash types.

    Arrays can contain just the type value, or a sub-array of the field’s name and type value. Hash keys must contain the field name as a ‘Symbol` or `String`, or the field position as an `Integer`. Hash values must contain the type value. If a Hash is used the fields will be created using the same order as the Hash keys.

    Supported type values incude:

    • ‘:BOOL`

    • ‘:BYTES`

    • ‘:DATE`

    • ‘:FLOAT64`

    • ‘:INT64`

    • ‘:STRING`

    • ‘:TIMESTAMP`

    • ‘Array` - Lists are specified by providing the type code in an array. For example, an array of integers are specified as `[:INT64]`.

    • Google::Cloud::Spanner::Fields - Nested Structs are specified by providing a Fields object.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/google/cloud/spanner/fields.rb', line 103

def initialize types
  types = types.to_a if types.is_a? Hash

  unless types.is_a? Array
    raise ArgumentError, "can only accept Array or Hash"
  end

  sorted_types, unsorted_types = types.partition do |type|
    type.is_a?(Array) && type.count == 2 && type.first.is_a?(Integer)
  end

  verify_sorted_types! sorted_types, types.count

  @grpc_fields = Array.new(types.count) do |index|
    sorted_type = sorted_types.assoc index
    if sorted_type
      to_grpc_field sorted_type.last
    else
      to_grpc_field unsorted_types.shift
    end
  end
end

Class Method Details

.from_grpc(fields) ⇒ Object

Google::Spanner::V1::Metadata::Row_type::Fields.



386
387
388
389
390
# File 'lib/google/cloud/spanner/fields.rb', line 386

def self.from_grpc fields
  new([]).tap do |f|
    f.instance_variable_set :@grpc_fields, Array(fields)
  end
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



342
343
344
345
# File 'lib/google/cloud/spanner/fields.rb', line 342

def == other
  return false unless other.is_a? Fields
  pairs == other.pairs
end

#[](key) ⇒ Symbol?

Returns the type code for the provided name (String) or index (Integer). Do not pass a name to this method if the data has more than one member with the same name. (See #duplicate_names?)

Parameters:

  • key (String, Integer)

    The name (String) or zero-based index position (Integer) of the value.

Returns:

  • (Symbol, nil)

    The type code, or nil if no value is found.

Raises:



201
202
203
204
205
206
207
208
# File 'lib/google/cloud/spanner/fields.rb', line 201

def [] key
  return types[key] if key.is_a? Integer
  name_count = @grpc_fields.find_all { |f| f.name == String(key) }.count
  return nil if name_count.zero?
  raise DuplicateNameError if name_count > 1
  index = @grpc_fields.find_index { |f| f.name == String(key) }
  types[index]
end

#countObject Also known as: size



336
337
338
# File 'lib/google/cloud/spanner/fields.rb', line 336

def count
  @grpc_fields.count
end

#duplicate_names?Boolean

Detects duplicate names in the keys for the fields.

Returns:

  • (Boolean)

    Returns ‘true` if there are duplicate names.



173
174
175
# File 'lib/google/cloud/spanner/fields.rb', line 173

def duplicate_names?
  keys.count != keys.uniq.count
end

#hashObject



349
350
351
352
353
# File 'lib/google/cloud/spanner/fields.rb', line 349

def hash
  # The Protobuf object looks to maintain consistent hash values
  # for objects with the same configuration.
  to_grpc_type.hash
end

#inspectObject



368
369
370
# File 'lib/google/cloud/spanner/fields.rb', line 368

def inspect
  "#<#{self.class.name} #{self}>"
end

#keysArray<(String,Integer)>

Returns the names of the data values, or in cases in which values are unnamed, the zero-based index position of values.

Returns:

  • (Array<(String,Integer)>)

    An array containing the names (String) or position (Integer) for the corresponding values of the data.



158
159
160
161
162
163
164
165
166
# File 'lib/google/cloud/spanner/fields.rb', line 158

def keys
  @grpc_fields.map.with_index do |field, index|
    if field.name.empty?
      index
    else
      field.name.to_sym
    end
  end
end

#pairsArray<Array>

Returns the names or positions and their corresponding types as an array of arrays.

Returns:

  • (Array<Array>)

    An array containing name/position and types pairs.



184
185
186
# File 'lib/google/cloud/spanner/fields.rb', line 184

def pairs
  keys.zip types
end

#struct(data) ⇒ Data Also known as: data, new

Creates a new Data object given the data values matching the fields. Can be provided as either an Array of values, or a Hash where the hash keys match the field name or match the index position of the field.

For more information, see [Data Types - Constructing a STRUCT](cloud.google.com/spanner/docs/data-types#constructing-a-struct).

Examples:

Create a STRUCT value with named fields using Fields object:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

named_type = db.fields(
  { id: :INT64, name: :STRING, active: :BOOL }
)
named_data = named_type.struct(
  { id: 42, name: nil, active: false }
)

Create a STRUCT value with anonymous field names:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

anon_type = db.fields [:INT64, :STRING, :BOOL]
anon_data = anon_type.struct [42, nil, false]

Create a STRUCT value with duplicate field names:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

dup_type = db.fields [[:x, :INT64], [:x, :STRING], [:x, :BOOL]]
dup_data = dup_type.struct [42, nil, false]

Parameters:

  • data (Array, Hash)

    Accepts an array or hash data values.

    Arrays can contain just the data value, nested arrays will be treated as lists of values. Values must be provided in the same order as the fields, and there is no way to associate values to the field names.

    Hash keys must contain the field name as a ‘Symbol` or `String`, or the field position as an `Integer`. Hash values must contain the data value. Hash values will be matched to the fields, so they don’t need to match the same order as the fields.

Returns:

  • (Data)

    A new Data object.

Raises:

  • (ArgumentError)


268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/google/cloud/spanner/fields.rb', line 268

def struct data
  # create local copy of types so they are parsed just once.
  cached_types = types
  if data.nil?
    return Data.from_grpc nil, @grpc_fields
  elsif data.is_a? Array
    # Convert data in the order it was recieved
    values = data.map.with_index do |datum, index|
      Convert.object_to_grpc_value_and_type(datum, cached_types[index]).first
    end
    return Data.from_grpc values, @grpc_fields
  elsif data.is_a? Hash
    # Pull values from hash in order of the fields,
    # we can't always trust the Hash to be in order.
    values = @grpc_fields.map.with_index do |field, index|
      if data.key? index
        Convert.object_to_grpc_value_and_type(data[index],
                                      cached_types[index]).first
      elsif !field.name.to_s.empty?
        if data.key? field.name.to_s
          Convert.object_to_grpc_value_and_type(data[field.name.to_s],
                                        cached_types[index]).first
        elsif data.key? field.name.to_s.to_sym
          Convert.object_to_grpc_value_and_type(data[field.name.to_s.to_sym],
                                        cached_types[index]).first
        else
          raise "data value for field #{field.name} missing"
        end
      else
        raise "data value for field #{index} missing"
      end
    end
    return Data.from_grpc values, @grpc_fields
  end
  raise ArgumentError, "can only accept Array or Hash"
end

#to_aArray<Symbol|Array<Symbol>|Fields|Array<Fields>>

Returns the type codes as an array. Do not use this method if the data has more than one member with the same name. (See #duplicate_names?)

Returns:

  • (Array<Symbol|Array<Symbol>|Fields|Array<Fields>>)

    An array containing the type codes.



316
317
318
# File 'lib/google/cloud/spanner/fields.rb', line 316

def to_a
  types
end

#to_grpc_typeObject



374
375
376
377
378
379
380
381
# File 'lib/google/cloud/spanner/fields.rb', line 374

def to_grpc_type
  Google::Spanner::V1::Type.new(
    code: :STRUCT,
    struct_type: Google::Spanner::V1::StructType.new(
      fields: @grpc_fields
    )
  )
end

#to_hHash<(Symbol|Integer) => (Symbol|Array<Symbol>|Fields|Array<Fields>)] A hash containing the names or indexes and corresponding types.

Returns the names or indexes and corresponding type codes as a hash.

Returns:

  • (Hash<(Symbol|Integer) => (Symbol|Array<Symbol>|Fields|Array<Fields>)] A hash containing the names or indexes and corresponding types.)

    Hash<(Symbol|Integer) => (Symbol|Array<Symbol>|Fields|Array<Fields>)] A hash containing the names or indexes and corresponding types.

Raises:



330
331
332
333
# File 'lib/google/cloud/spanner/fields.rb', line 330

def to_h
  raise DuplicateNameError if duplicate_names?
  Hash[pairs]
end

#to_sObject



356
357
358
359
360
361
362
363
364
365
# File 'lib/google/cloud/spanner/fields.rb', line 356

def to_s
  named_types = pairs.map do |key, type|
    if key.is_a? Integer
      type.inspect
    else
      "(#{key})#{type.inspect}"
    end
  end
  "(#{named_types.join ', '})"
end

#typesArray<Symbol>

Returns the types of the data.

See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Returns:

  • (Array<Symbol>)

    An array containing the types of the data.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/google/cloud/spanner/fields.rb', line 134

def types
  @grpc_fields.map(&:type).map do |type|
    if type.code == :ARRAY
      if type.array_element_type.code == :STRUCT
        [Fields.from_grpc(type.array_element_type.struct_type.fields)]
      else
        [type.array_element_type.code]
      end
    elsif type.code == :STRUCT
      Fields.from_grpc type.struct_type.fields
    else
      type.code
    end
  end
end