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.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

results = db.execute_query "SELECT * FROM users"

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

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.

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 include:

    • :BOOL
    • :BYTES
    • :DATE
    • :FLOAT64
    • :NUMERIC
    • :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.


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

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

Instance Method Details

#[](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:



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

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

#duplicate_names?Boolean

Detects duplicate names in the keys for the fields.

Returns:

  • (Boolean)

    Returns true if there are duplicate names.



175
176
177
# File 'lib/google/cloud/spanner/fields.rb', line 175

def duplicate_names?
  keys.group_by { |e| e }.select { |_k, v| v.size > 1 }.any?
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.



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

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.



186
187
188
# File 'lib/google/cloud/spanner/fields.rb', line 186

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.

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)


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
304
305
# File 'lib/google/cloud/spanner/fields.rb', line 270

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.



318
319
320
# File 'lib/google/cloud/spanner/fields.rb', line 318

def to_a
  types
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|Fields|Array)] A hash containing the names or indexes and corresponding types.

Raises:



332
333
334
335
# File 'lib/google/cloud/spanner/fields.rb', line 332

def to_h
  raise DuplicateNameError if duplicate_names?
  pairs.to_h
end

#typesArray<Symbol>

Returns the types of the data.

See Data types.

Returns:

  • (Array<Symbol>)

    An array containing the types of the data.



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

def types
  @grpc_fields.map(&:type).map do |type|
    case type.code
    when :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
    when :STRUCT
      Fields.from_grpc type.struct_type.fields
    else
      type.code
    end
  end
end