attio 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,16 +9,120 @@ module Attio
9
9
  #
10
10
  # @example Listing all objects
11
11
  # client.objects.list
12
+ #
13
+ # @example Creating a custom object
14
+ # client.objects.create(
15
+ # api_slug: "projects",
16
+ # singular_noun: "Project",
17
+ # plural_noun: "Projects"
18
+ # )
19
+ #
20
+ # @example Updating a custom object
21
+ # client.objects.update(
22
+ # id_or_slug: "projects",
23
+ # plural_noun: "Active Projects"
24
+ # )
12
25
  class Objects < Base
26
+ # List all objects in the workspace
27
+ #
28
+ # @param params [Hash] Optional query parameters
29
+ # @return [Hash] List of objects
13
30
  def list(**params)
14
31
  request(:get, "objects", params)
15
32
  end
16
33
 
34
+ # Get a single object by ID or slug
35
+ #
36
+ # @param id_or_slug [String] The object ID or slug
37
+ # @return [Hash] The object details
17
38
  def get(id_or_slug:)
18
39
  validate_id_or_slug!(id_or_slug)
19
40
  request(:get, "objects/#{id_or_slug}")
20
41
  end
21
42
 
43
+ # Create a new custom object
44
+ #
45
+ # @param api_slug [String] Unique slug for the object (snake_case)
46
+ # @param singular_noun [String] Singular name of the object
47
+ # @param plural_noun [String] Plural name of the object
48
+ # @return [Hash] The created object with ID and timestamps
49
+ # @raise [ArgumentError] if required parameters are missing
50
+ # @example
51
+ # object = client.objects.create(
52
+ # api_slug: "projects",
53
+ # singular_noun: "Project",
54
+ # plural_noun: "Projects"
55
+ # )
56
+ def create(api_slug:, singular_noun:, plural_noun:)
57
+ validate_required_string!(api_slug, "API slug")
58
+ validate_required_string!(singular_noun, "Singular noun")
59
+ validate_required_string!(plural_noun, "Plural noun")
60
+
61
+ data = {
62
+ api_slug: api_slug,
63
+ singular_noun: singular_noun,
64
+ plural_noun: plural_noun,
65
+ }
66
+
67
+ request(:post, "objects", { data: data })
68
+ end
69
+
70
+ # Update an existing custom object
71
+ #
72
+ # @param id_or_slug [String] The object ID or slug to update
73
+ # @param api_slug [String, nil] New API slug (optional)
74
+ # @param singular_noun [String, nil] New singular noun (optional)
75
+ # @param plural_noun [String, nil] New plural noun (optional)
76
+ # @return [Hash] The updated object
77
+ # @raise [ArgumentError] if no update fields are provided
78
+ # @example Update just the plural noun
79
+ # client.objects.update(
80
+ # id_or_slug: "projects",
81
+ # plural_noun: "Active Projects"
82
+ # )
83
+ # @example Update multiple fields
84
+ # client.objects.update(
85
+ # id_or_slug: "old_slug",
86
+ # api_slug: "new_slug",
87
+ # singular_noun: "New Name",
88
+ # plural_noun: "New Names"
89
+ # )
90
+ def update(id_or_slug:, api_slug: nil, singular_noun: nil, plural_noun: nil)
91
+ validate_id_or_slug!(id_or_slug)
92
+
93
+ data = {}
94
+ data[:api_slug] = api_slug if api_slug
95
+ data[:singular_noun] = singular_noun if singular_noun
96
+ data[:plural_noun] = plural_noun if plural_noun
97
+
98
+ raise ArgumentError, "At least one field to update is required" if data.empty?
99
+
100
+ request(:patch, "objects/#{id_or_slug}", { data: data })
101
+ end
102
+
103
+ # Delete a custom object
104
+ #
105
+ # NOTE: The Attio API v2.0.0 does not currently support deleting custom objects.
106
+ # To delete a custom object, please visit your Attio settings at:
107
+ # Settings > Data Model > Objects
108
+ #
109
+ # @param id_or_slug [String] The object ID or slug to delete
110
+ # @raise [NotImplementedError] Always raised as the API doesn't support this operation
111
+ # @example
112
+ # client.objects.delete(id_or_slug: "projects")
113
+ # # => NotImplementedError: The Attio API does not currently support deleting custom objects.
114
+ # # Please delete objects through the Attio UI at: Settings > Data Model > Objects
115
+ def delete(id_or_slug:)
116
+ validate_id_or_slug!(id_or_slug)
117
+ raise NotImplementedError,
118
+ "The Attio API does not currently support deleting custom objects. " \
119
+ "Please delete objects through the Attio UI at: Settings > Data Model > Objects"
120
+ end
121
+
122
+ # Alias for delete method for consistency with other resources
123
+ # NOTE: See delete method for API limitations
124
+ alias destroy delete
125
+
22
126
  private def validate_id_or_slug!(id_or_slug)
23
127
  raise ArgumentError, "Object ID or slug is required" if id_or_slug.nil? || id_or_slug.to_s.strip.empty?
24
128
  end
@@ -153,6 +153,74 @@ module Attio
153
153
  request(:delete, "objects/#{object}/records/#{id}")
154
154
  end
155
155
 
156
+ # Assert (upsert) a record based on a matching attribute.
157
+ #
158
+ # This method creates or updates a record based on a matching attribute,
159
+ # providing upsert functionality. If a record with the matching attribute
160
+ # value exists, it will be updated; otherwise, a new record will be created.
161
+ #
162
+ # @param object [String] The object type (e.g., 'people', 'companies')
163
+ # @param matching_attribute [String] The attribute to match against for upsert
164
+ # @param data [Hash] The record data to create or update
165
+ #
166
+ # @return [Hash] The created or updated record data
167
+ # @raise [ArgumentError] if object, matching_attribute, or data is invalid
168
+ #
169
+ # @example Assert a person by email
170
+ # record = client.records.assert(
171
+ # object: 'people',
172
+ # matching_attribute: 'email',
173
+ # data: {
174
+ # name: 'Jane Doe',
175
+ # email: 'jane@example.com',
176
+ # company: { target_object: 'companies', target_record_id: 'company123' }
177
+ # }
178
+ # )
179
+ def assert(object:, matching_attribute:, data:)
180
+ validate_required_string!(object, "Object type")
181
+ validate_required_string!(matching_attribute, "Matching attribute")
182
+ validate_record_data!(data)
183
+
184
+ request_body = {
185
+ data: data,
186
+ matching_attribute: matching_attribute,
187
+ }
188
+
189
+ request(:put, "objects/#{object}/records", request_body)
190
+ end
191
+
192
+ # Update a record using PUT (replace operation).
193
+ #
194
+ # This method performs a complete replacement of the record, unlike the
195
+ # regular update method which uses PATCH. For multiselect fields, this
196
+ # overwrites the values instead of appending to them.
197
+ #
198
+ # @param object [String] The object type (e.g., 'people', 'companies')
199
+ # @param id [String] The record ID to replace
200
+ # @param data [Hash] The complete record data to replace with
201
+ #
202
+ # @return [Hash] The updated record data
203
+ # @raise [ArgumentError] if object, id, or data is invalid
204
+ #
205
+ # @example Replace a person's data
206
+ # record = client.records.update_with_put(
207
+ # object: 'people',
208
+ # id: 'abc123',
209
+ # data: {
210
+ # name: 'Jane Smith',
211
+ # email: 'jane.smith@example.com',
212
+ # tags: ['customer', 'vip'] # This will replace all existing tags
213
+ # }
214
+ # )
215
+ def update_with_put(object:, id:, data:)
216
+ validate_required_string!(object, "Object type")
217
+ validate_id!(id, "Record")
218
+ validate_record_data!(data)
219
+
220
+ request_body = { data: data }
221
+ request(:put, "objects/#{object}/records/#{id}", request_body)
222
+ end
223
+
156
224
  # Validates that the data parameter is present and is a hash.
157
225
  #
158
226
  # @param data [Hash, nil] The data to validate
@@ -5,16 +5,25 @@ module Attio
5
5
  # API resource for managing workspace information
6
6
  #
7
7
  # Workspaces are the top-level organizational unit in Attio.
8
+ # Note: The workspace information is retrieved via the Meta API (/v2/self)
8
9
  #
9
10
  # @example Getting workspace information
10
11
  # client.workspaces.get
11
12
  class Workspaces < Base
13
+ # Get current workspace information
14
+ #
15
+ # This method retrieves workspace info from the /v2/self endpoint
16
+ # which provides workspace context along with token information.
17
+ #
18
+ # @return [Hash] Workspace information from the self endpoint
12
19
  def get
13
- request(:get, "workspace")
20
+ request(:get, "self")
14
21
  end
15
22
 
23
+ # @deprecated Use client.workspace_members.list instead
16
24
  def members(**params)
17
- request(:get, "workspace/members", params)
25
+ warn "[DEPRECATION] `workspaces.members` is deprecated. Use `workspace_members.list` instead."
26
+ request(:get, "workspace_members", params)
18
27
  end
19
28
  end
20
29
  end
data/lib/attio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Attio
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/attio.rb CHANGED
@@ -9,6 +9,7 @@ require "attio/client"
9
9
 
10
10
  # Resources
11
11
  require "attio/resources/base"
12
+ require "attio/resources/meta"
12
13
  require "attio/resources/records"
13
14
  require "attio/resources/objects"
14
15
  require "attio/resources/lists"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ernest Sim
@@ -55,6 +55,7 @@ files:
55
55
  - Gemfile
56
56
  - Gemfile.lock
57
57
  - LICENSE.txt
58
+ - META_IMPLEMENTATION_PLAN.md
58
59
  - README.md
59
60
  - Rakefile
60
61
  - SECURITY.md
@@ -125,6 +126,7 @@ files:
125
126
  - lib/attio/resources/comments.rb
126
127
  - lib/attio/resources/deals.rb
127
128
  - lib/attio/resources/lists.rb
129
+ - lib/attio/resources/meta.rb
128
130
  - lib/attio/resources/notes.rb
129
131
  - lib/attio/resources/objects.rb
130
132
  - lib/attio/resources/records.rb