Module: Dynamoid::CDK::Schema::Introspector

Defined in:
lib/dynamoid/cdk/schema/introspector.rb

Overview

Reads a Dynamoid model class into a Descriptor: partition and sort keys, GSIs and LSIs, with DynamoDB attribute types resolved exactly the way Dynamoid resolves them for its own tables. Pure metadata — no DynamoDB connection and no AWS CDK.

Class Method Summary collapse

Class Method Details

.attribute(model, name) ⇒ Object

Raises:



28
29
30
31
32
33
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 28

def attribute(model, name)
  field = model.attributes[name.to_sym]
  raise Error, "#{model}: no field #{name.inspect} declared for a key attribute" if field.nil?

  Attribute.new(name: name.to_s, type: dynamodb_type(field))
end

.call(model) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 13

def call(model)
  # Required here rather than at load: {Schema.table_from} builds tables
  # from dumped data, and a CDK app doing only that has no reason to
  # carry Dynamoid. Anyone introspecting a model already has it loaded —
  # the model IS a Dynamoid class.
  require "dynamoid"

  Descriptor.new(
    partition_key: attribute(model, model.hash_key),
    sort_key: (attribute(model, model.range_key) if model.range_key),
    global_secondary_indexes: model.global_secondary_indexes.values.map { |i| gsi(model, i) },
    local_secondary_indexes: model.local_secondary_indexes.values.map { |i| lsi(model, i) }
  )
end

.dynamodb_type(field) ⇒ Object

Resolve a field's DynamoDB key type the way Dynamoid does. Its mapping doesn't emit :binary, but DynamoDB permits binary keys, so fall back to the field type on UnsupportedKeyType — mirroring Dynamoid's own index validation.



39
40
41
42
43
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 39

def dynamodb_type(field)
  Dynamoid::PrimaryKeyTypeMapping.dynamodb_type(field[:type], field)
rescue Dynamoid::Errors::UnsupportedKeyType
  field[:type]
end

.gsi(model, index) ⇒ Object



45
46
47
48
49
50
51
52
53
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 45

def gsi(model, index)
  Index.new(
    name: index.name,
    partition_key: attribute(model, index.hash_key),
    sort_key: (attribute(model, index.range_key) if index.range_key),
    projection_type: index.projection_type,
    non_key_attributes: non_key_attributes(index)
  )
end

.lsi(model, index) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 55

def lsi(model, index)
  Index.new(
    name: index.name,
    partition_key: nil, # an LSI shares the table's partition key
    sort_key: attribute(model, index.range_key),
    projection_type: index.projection_type,
    non_key_attributes: non_key_attributes(index)
  )
end

.non_key_attributes(index) ⇒ Object

DynamoDB wants the projected attribute list only for INCLUDE projections.



66
67
68
69
70
# File 'lib/dynamoid/cdk/schema/introspector.rb', line 66

def non_key_attributes(index)
  return nil unless index.projection_type == :include

  Array(index.projected_attributes).map(&:to_s)
end