Class: Attio::TypedRecord

Inherits:
Internal::Record show all
Defined in:
lib/attio/resources/typed_record.rb

Overview

Base class for type-specific record classes (e.g., Person, Company) Provides a more object-oriented interface for working with specific Attio objects

Direct Known Subclasses

Company, Deal, Person

Constant Summary

Constants inherited from APIResource

APIResource::SKIP_KEYS

Instance Attribute Summary

Attributes inherited from Internal::Record

#attio_object_id, #object_api_slug

Attributes inherited from APIResource

#created_at, #id, #metadata

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Internal::Record

#add_to_list, #inspect, #lists, #resource_path, resource_path, #to_h

Methods inherited from APIResource

#==, #[], #[]=, api_operations, attr_attio, #changed, #changed?, #changed_attributes, #changes, #each, execute_request, #fetch, #hash, id_param_name, #inspect, #key?, #keys, #persisted?, prepare_params_for_create, prepare_params_for_update, #reset_changes!, resource_name, resource_path, #resource_path, #revert!, #to_h, #to_json, #update_attributes, #update_from, validate_id!, #values

Constructor Details

#initialize(attributes = {}, opts = {}) ⇒ TypedRecord

Override initialize to ensure object type is set



117
118
119
120
121
122
123
# File 'lib/attio/resources/typed_record.rb', line 117

def initialize(attributes = {}, opts = {})
  super
  # Ensure the object type matches the class
  if respond_to?(:object) && object != self.class.object_type
    raise ArgumentError, "Object type mismatch: expected #{self.class.object_type}, got #{object}"
  end
end

Class Method Details

.all(**opts) ⇒ Object

Provide a more intuitive all method



54
55
56
# File 'lib/attio/resources/typed_record.rb', line 54

def all(**opts)
  list(**opts)
end

.create(values: {}, **opts) ⇒ Object

Override create to automatically include object type



31
32
33
# File 'lib/attio/resources/typed_record.rb', line 31

def create(values: {}, **opts)
  super(object: object_type, values: values, **opts)
end

.delete(record_id, **opts) ⇒ Object

Override delete to automatically include object type



41
42
43
44
45
46
# File 'lib/attio/resources/typed_record.rb', line 41

def delete(record_id, **opts)
  # The parent delete expects object in opts for records
  simple_id = record_id.is_a?(Hash) ? record_id["record_id"] : record_id
  execute_request(:DELETE, "objects/#{object_type}/records/#{simple_id}", {}, opts)
  true
end

.find(record_id, **opts) ⇒ Object

Provide a more intuitive find method



49
50
51
# File 'lib/attio/resources/typed_record.rb', line 49

def find(record_id, **opts)
  retrieve(record_id, **opts)
end

.find_by(**conditions) ⇒ Object

Find by a specific attribute value Supports Rails-style hash syntax: find_by(name: "Test")

Raises:

  • (ArgumentError)


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
113
# File 'lib/attio/resources/typed_record.rb', line 65

def find_by(**conditions)
  raise ArgumentError, "find_by requires at least one condition" if conditions.empty?

  # Extract any opts that aren't conditions (like api_key)
  opts = {}
  known_opts = [:api_key, :timeout, :idempotency_key]
  known_opts.each do |opt|
    opts[opt] = conditions.delete(opt) if conditions.key?(opt)
  end

  # Build filter from conditions
  filters = []
  search_query = nil

  conditions.each do |field, value|
    # Check if there's a special filter method for this field
    filter_method = "filter_by_#{field}"
    if respond_to?(filter_method, true) # true = include private methods
      result = send(filter_method, value)
      # Check if this should be a search instead of a filter
      if result == :use_search
        search_query = value
      else
        filters << result
      end
    else
      # Use the field as-is
      filters << {field => value}
    end
  end

  # If we have a search query, use search instead of filter
  if search_query
    search(search_query, **opts).first
  else
    # Combine multiple filters with $and if needed
    final_filter = if filters.length == 1
      filters.first
    elsif filters.length > 1
      {"$and": filters}
    else
      {}
    end

    list(**opts.merge(params: {
      filter: final_filter
    })).first
  end
end

.list(**opts) ⇒ Object

Override list to automatically include object type



21
22
23
# File 'lib/attio/resources/typed_record.rb', line 21

def list(**opts)
  super(object: object_type, **opts)
end

.object_type(type = nil) ⇒ Object

Define the object type for this class



12
13
14
15
16
17
18
# File 'lib/attio/resources/typed_record.rb', line 12

def object_type(type = nil)
  if type
    @object_type = type
  else
    @object_type || raise(NotImplementedError, "#{self} must define object_type")
  end
end

.retrieve(record_id, **opts) ⇒ Object

Override retrieve to automatically include object type



26
27
28
# File 'lib/attio/resources/typed_record.rb', line 26

def retrieve(record_id, **opts)
  super(object: object_type, record_id: record_id, **opts)
end

.search(query, **opts) ⇒ Object

Search with a query string



59
60
61
# File 'lib/attio/resources/typed_record.rb', line 59

def search(query, **opts)
  list(**opts.merge(params: {q: query}))
end

.update(record_id, values: {}, **opts) ⇒ Object

Override update to automatically include object type



36
37
38
# File 'lib/attio/resources/typed_record.rb', line 36

def update(record_id, values: {}, **opts)
  super(object: object_type, record_id: record_id, data: {values: values}, **opts)
end

Instance Method Details

#destroy(**opts) ⇒ Object

Override destroy to include object type



134
135
136
137
138
139
# File 'lib/attio/resources/typed_record.rb', line 134

def destroy(**opts)
  raise InvalidRequestError, "Cannot destroy without an ID" unless persisted?

  # Just call the parent destroy method which handles everything correctly
  super
end

#save(**opts) ⇒ Object

Override save to include object type



126
127
128
129
130
131
# File 'lib/attio/resources/typed_record.rb', line 126

def save(**opts)
  raise InvalidRequestError, "Cannot save without an ID" unless persisted?
  return self unless changed?

  self.class.update(id, values: changed_attributes, **opts)
end