airrecord 0.2.4 → 0.2.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +31 -44
- data/airrecord.gemspec +1 -1
- data/lib/airrecord/table.rb +32 -6
- data/lib/airrecord/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1224190a9be6b7349af9ab26640516b13961d88bc3b42d188c5879777e90fe04
|
4
|
+
data.tar.gz: 119beef65efdc6d110cc4e5c1865e92308c3e2a043b0e2e853484480488307d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 577ae326c6cb761f7557c9b75a6a3e1fc46373aba67b6300430d9d0efac54e21eea30885237d40c233ef1c33f2d4bd3766984f0697211ebbff8bd6d7af160bcf
|
7
|
+
data.tar.gz: 11c1ce89e39a1f0e66f8c3b34cbf53eb21f69a2e91f98ae5460af85f1df2b62e37a1c01940263da8dba7c0499e822f8a3280ef55345cc93f76401c2d36579252
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 1.0.0 (unreleased)
|
2
|
+
|
3
|
+
* 1.0.0 will introduce breaking changes, including removing support for symbols. To update, change snake-case symbols to their correct column names (for example, `record["First Name"]` instead of `record[:first_name]`)
|
4
|
+
|
5
|
+
# 0.2.5
|
6
|
+
|
7
|
+
* Deprecate using symbols instead of strings
|
8
|
+
|
1
9
|
# 0.2.4
|
2
10
|
|
3
11
|
* Don't flag as dirty if change is equal
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ class Tea < Airrecord::Table
|
|
20
20
|
self.base_key = "app1"
|
21
21
|
self.table_name = "Teas"
|
22
22
|
|
23
|
-
has_many
|
23
|
+
has_many "Brews", class: 'Brew', column: "Brews"
|
24
24
|
|
25
25
|
def self.chinese
|
26
26
|
all(filter: '{Country} = "China"')
|
@@ -31,11 +31,11 @@ class Tea < Airrecord::Table
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def location
|
34
|
-
[self[
|
34
|
+
[self["Village"], self["Country"], self["Region"]].compact.join(", ")
|
35
35
|
end
|
36
36
|
|
37
37
|
def green?
|
38
|
-
self[
|
38
|
+
self["Type"] == "Green"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -43,22 +43,22 @@ class Brew < Airrecord::Table
|
|
43
43
|
self.base_key = "app1"
|
44
44
|
self.table_name = "Brews"
|
45
45
|
|
46
|
-
belongs_to
|
46
|
+
belongs_to "Tea", class: 'Tea', column: 'Tea'
|
47
47
|
|
48
48
|
def self.hot
|
49
49
|
all(filter: "{Temperature} > 90")
|
50
50
|
end
|
51
51
|
|
52
52
|
def done_brewing?
|
53
|
-
self[
|
53
|
+
self["Created At"] + self["Duration"] > Time.now
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
teas = Tea.all
|
58
58
|
tea = teas.first
|
59
|
-
tea[
|
59
|
+
tea["Country"] # access atribute
|
60
60
|
tea.location # instance methods
|
61
|
-
tea[
|
61
|
+
tea["Brews"] # associated brews
|
62
62
|
```
|
63
63
|
|
64
64
|
A short-hand API for definitions and more ad-hoc querying is also available:
|
@@ -67,7 +67,7 @@ A short-hand API for definitions and more ad-hoc querying is also available:
|
|
67
67
|
Tea = Airrecord.table("api_key", "app_key", "Teas")
|
68
68
|
|
69
69
|
Tea.all.each do |record|
|
70
|
-
puts "#{record.id}: #{record[
|
70
|
+
puts "#{record.id}: #{record["Name"]}"
|
71
71
|
end
|
72
72
|
|
73
73
|
Tea.find("rec3838")
|
@@ -107,7 +107,7 @@ class Tea < Airrecord::Table
|
|
107
107
|
self.table_name = "Teas"
|
108
108
|
|
109
109
|
def location
|
110
|
-
[self[
|
110
|
+
[self["Village"], self["Country"], self["Region"]].compact.join(", ")
|
111
111
|
end
|
112
112
|
end
|
113
113
|
```
|
@@ -130,13 +130,13 @@ To use `filterbyFormula` to filter returned records:
|
|
130
130
|
|
131
131
|
```ruby
|
132
132
|
# Retrieve all teas from China
|
133
|
-
Tea.all(filter: '{Country}
|
133
|
+
Tea.all(filter: '{Country} = "China"')
|
134
134
|
|
135
135
|
# Retrieve all teas created in the past week
|
136
136
|
Tea.all(filter: "DATETIME_DIFF(CREATED_TIME(), TODAY(), 'days') < 7")
|
137
137
|
|
138
138
|
# Retrieve all teas that don't have a country defined
|
139
|
-
Tea.all(filter: "{Country}
|
139
|
+
Tea.all(filter: "{Country} = \"\"")
|
140
140
|
```
|
141
141
|
|
142
142
|
This filtering can, of course, also be done in Ruby directly after calling
|
@@ -158,17 +158,16 @@ The `sort` option can be used to sort results returned from the Airtable API.
|
|
158
158
|
|
159
159
|
```ruby
|
160
160
|
# Sort teas by the Name column in ascending order
|
161
|
-
Tea.all(sort: { Name
|
161
|
+
Tea.all(sort: { "Name" => "asc" })
|
162
162
|
|
163
163
|
# Sort teas by Type (green, black, oolong, ..) in descending order
|
164
|
-
Tea.all(sort: { Type
|
164
|
+
Tea.all(sort: { "Type" => "desc" })
|
165
165
|
|
166
166
|
# Sort teas by price in descending order
|
167
|
-
Tea.all(sort: { Price
|
167
|
+
Tea.all(sort: { "Price" => "desc" })
|
168
168
|
```
|
169
169
|
|
170
|
-
Note again that the key _must_ be the full column name.
|
171
|
-
not work here.
|
170
|
+
Note again that the key _must_ be the full column name.
|
172
171
|
|
173
172
|
As mentioned above, by default Airrecord will return results from all pages.
|
174
173
|
This can be slow if you have 1000s of records. You may wish to use the `view`
|
@@ -181,7 +180,7 @@ calls. Airrecord will _always_ fetch the maximum possible amount of records
|
|
181
180
|
Tea.all(paginate: false)
|
182
181
|
|
183
182
|
# Give me only the most recent teas
|
184
|
-
Tea.all(sort: { "Created At"
|
183
|
+
Tea.all(sort: { "Created At" => "desc" }, paginate: false)
|
185
184
|
```
|
186
185
|
|
187
186
|
### Creating
|
@@ -192,16 +191,15 @@ Creating a new record is done through `#create`.
|
|
192
191
|
tea = Tea.new("Name" => "Feng Gang", "Type" => "Green", "Country" => "China")
|
193
192
|
tea.create # creates the record
|
194
193
|
tea.id # id of the new record
|
195
|
-
tea[
|
194
|
+
tea["Name"] # "Feng Gang"
|
196
195
|
```
|
197
196
|
|
198
|
-
Note that
|
199
|
-
|
200
|
-
Airrecord will throw an error that no column matches it.
|
197
|
+
Note that column names need to match the exact column names in Airtable,
|
198
|
+
otherwise Airrecord will throw an error that no column matches it.
|
201
199
|
|
202
|
-
|
203
|
-
|
204
|
-
still not been released.
|
200
|
+
_Earlier versions of airrecord provided methods for snake-cased column names
|
201
|
+
and symbols, however this proved error-prone without a proper schema API from
|
202
|
+
Airtable which has still not been released._
|
205
203
|
|
206
204
|
### Updating
|
207
205
|
|
@@ -210,11 +208,7 @@ Airtable with `#save`.
|
|
210
208
|
|
211
209
|
```ruby
|
212
210
|
tea = Tea.find("someid")
|
213
|
-
tea[
|
214
|
-
|
215
|
-
# Since the Village column is not set, we do not have access to a snake-cased
|
216
|
-
# variant since the mapping is not determined. For all we know, the correct column
|
217
|
-
# name could be "VilLlaGe". Therefore, we must use the proper column name.
|
211
|
+
tea["Name"] = "Feng Gang Organic"
|
218
212
|
tea["Village"] = "Feng Gang"
|
219
213
|
|
220
214
|
tea.save # persist to Airtable
|
@@ -236,7 +230,7 @@ providing the URL. Unfortunately, it does not allow uploading directly.
|
|
236
230
|
|
237
231
|
```ruby
|
238
232
|
word = World.find("cantankerous")
|
239
|
-
word["Pronounciation"] = [{url: "https://s3.ca-central-1.amazonaws.com/word-pronunciations/cantankerous.mp3}]
|
233
|
+
word["Pronounciation"] = [{url: "https://s3.ca-central-1.amazonaws.com/word-pronunciations/cantankerous.mp3"}]
|
240
234
|
word.save
|
241
235
|
```
|
242
236
|
|
@@ -274,14 +268,14 @@ class Tea < Airrecord::Table
|
|
274
268
|
self.base_key = "app1"
|
275
269
|
self.table_name = "Teas"
|
276
270
|
|
277
|
-
has_many
|
271
|
+
has_many "Brews", class: 'Brew', column: "Brews"
|
278
272
|
end
|
279
273
|
|
280
274
|
class Brew < Airrecord::Table
|
281
275
|
self.base_key = "app1"
|
282
276
|
self.table_name = "Brews"
|
283
277
|
|
284
|
-
belongs_to
|
278
|
+
belongs_to "Tea", class: 'Tea', column: 'Tea'
|
285
279
|
end
|
286
280
|
```
|
287
281
|
|
@@ -296,14 +290,14 @@ To retrieve records from associations to a record:
|
|
296
290
|
|
297
291
|
```ruby
|
298
292
|
tea = Tea.find('rec84')
|
299
|
-
tea[
|
293
|
+
tea["Brews"] # brews associated with tea
|
300
294
|
```
|
301
295
|
|
302
296
|
This in turn works the other way too:
|
303
297
|
|
304
298
|
```ruby
|
305
299
|
brew = Brew.find('rec849')
|
306
|
-
brew[
|
300
|
+
brew["Tea"] # the associated tea instance
|
307
301
|
```
|
308
302
|
|
309
303
|
### Creating associated records
|
@@ -313,7 +307,8 @@ You can easily associate records with each other:
|
|
313
307
|
```ruby
|
314
308
|
tea = Tea.find('rec849829')
|
315
309
|
# This will create a brew associated with the specific tea
|
316
|
-
Brew.
|
310
|
+
brew = Brew.new("Tea" => tea, "Temperature" => "80", "Time" => "4m", "Rating" => "5")
|
311
|
+
brew.create
|
317
312
|
```
|
318
313
|
|
319
314
|
### Ad-hoc API
|
@@ -327,20 +322,12 @@ around.
|
|
327
322
|
Tea = Airrecord.table("api_key", "app_key", "Teas")
|
328
323
|
|
329
324
|
Tea.all.each do |record|
|
330
|
-
puts "#{record.id}: #{record[
|
325
|
+
puts "#{record.id}: #{record["Name"]}"
|
331
326
|
end
|
332
327
|
|
333
328
|
Tea.find("rec3838")
|
334
329
|
```
|
335
330
|
|
336
|
-
### Snake-cased helper methods
|
337
|
-
|
338
|
-
When retrieving an existing record from Airtable, snake-cased helper names are
|
339
|
-
available to index attributes. These are _only_ available on retrieved records,
|
340
|
-
and _only_ if the column was set. If it's `nil`, it will not exist. That means
|
341
|
-
if you want to set column that has a `nil` value for a column type, you'll have
|
342
|
-
to fully type it out.
|
343
|
-
|
344
331
|
### Production Middlewares
|
345
332
|
|
346
333
|
For production use-cases, it's worth considering adding retries and circuit
|
data/airrecord.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = %q{Airtable client}
|
13
13
|
spec.description = %q{Airtable client to make Airtable interactions a breeze}
|
14
|
-
spec.homepage = "https://github.com/sirupsen/
|
14
|
+
spec.homepage = "https://github.com/sirupsen/airrecord"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
data/lib/airrecord/table.rb
CHANGED
@@ -8,10 +8,24 @@ module Airrecord
|
|
8
8
|
# Right now I bet there's a bunch of bugs around similar named column keys (in
|
9
9
|
# terms of capitalization), it's inconsistent and non-obvious that `create`
|
10
10
|
# doesn't use the same column keys as everything else.
|
11
|
+
#
|
12
|
+
# 2018-11-01
|
13
|
+
# deprecate_symbols: long-term plan is to force everyone to use raw strings,
|
14
|
+
# to match the Airtable behavior. For now we'll just warn when using symbols
|
15
|
+
# with a deprecation notice.
|
16
|
+
|
11
17
|
class Table
|
18
|
+
def deprecate_symbols
|
19
|
+
self.class.deprecate_symbols
|
20
|
+
end
|
21
|
+
|
12
22
|
class << self
|
13
23
|
attr_accessor :base_key, :table_name, :api_key, :associations
|
14
24
|
|
25
|
+
def deprecate_symbols
|
26
|
+
warn Kernel.caller.first + ": warning: Using symbols with airrecord is deprecated."
|
27
|
+
end
|
28
|
+
|
15
29
|
def client
|
16
30
|
@@clients ||= {}
|
17
31
|
@@clients[api_key] ||= Client.new(api_key)
|
@@ -20,7 +34,7 @@ module Airrecord
|
|
20
34
|
def has_many(name, options)
|
21
35
|
@associations ||= []
|
22
36
|
@associations << {
|
23
|
-
field: name.to_sym,
|
37
|
+
field: name.to_sym, # todo: deprecate_symbols
|
24
38
|
}.merge(options)
|
25
39
|
end
|
26
40
|
|
@@ -49,6 +63,7 @@ module Airrecord
|
|
49
63
|
|
50
64
|
if sort
|
51
65
|
options[:sort] = sort.map { |field, direction|
|
66
|
+
deprecate_symbols if field.is_a? Symbol
|
52
67
|
{ field: field.to_s, direction: direction }
|
53
68
|
}
|
54
69
|
end
|
@@ -106,8 +121,10 @@ module Airrecord
|
|
106
121
|
value = nil
|
107
122
|
|
108
123
|
if fields[key]
|
124
|
+
deprecate_symbols if key.is_a? Symbol
|
109
125
|
value = fields[key]
|
110
126
|
elsif column_mappings[key]
|
127
|
+
deprecate_symbols if key.is_a? Symbol
|
111
128
|
value = fields[column_mappings[key]]
|
112
129
|
end
|
113
130
|
|
@@ -125,11 +142,13 @@ module Airrecord
|
|
125
142
|
end
|
126
143
|
|
127
144
|
def []=(key, value)
|
145
|
+
deprecate_symbols if key.is_a? Symbol
|
128
146
|
if fields[key]
|
129
147
|
return if fields[key] == value # no-op
|
130
148
|
@updated_keys << key
|
131
149
|
fields[key] = value
|
132
150
|
elsif column_mappings[key]
|
151
|
+
deprecate_symbols
|
133
152
|
return if fields[column_mappings[key]] == value # no-op
|
134
153
|
@updated_keys << column_mappings[key]
|
135
154
|
fields[column_mappings[key]] = value
|
@@ -196,19 +215,25 @@ module Airrecord
|
|
196
215
|
value = [ value ] unless value.is_a?(Enumerable)
|
197
216
|
assocs = value.map { |assoc|
|
198
217
|
assoc.respond_to?(:id) ? assoc.id : assoc
|
199
|
-
}
|
218
|
+
}
|
200
219
|
[key, assocs]
|
201
220
|
else
|
202
221
|
[key, value]
|
203
222
|
end
|
204
223
|
}]
|
205
224
|
end
|
206
|
-
|
225
|
+
|
207
226
|
def ==(other)
|
208
227
|
self.class == other.class &&
|
209
228
|
serializable_fields == other.serializable_fields
|
210
229
|
end
|
211
230
|
|
231
|
+
alias_method :eql?, :==
|
232
|
+
|
233
|
+
def hash
|
234
|
+
serializable_fields.hash
|
235
|
+
end
|
236
|
+
|
212
237
|
protected
|
213
238
|
|
214
239
|
def association(key)
|
@@ -221,15 +246,15 @@ module Airrecord
|
|
221
246
|
|
222
247
|
def fields=(fields)
|
223
248
|
@updated_keys = []
|
224
|
-
@column_mappings = Hash[fields.keys.map { |key| [underscore(key), key] }]
|
249
|
+
@column_mappings = Hash[fields.keys.map { |key| [underscore(key), key] }] # TODO remove (deprecate_symbols)
|
225
250
|
@fields = fields
|
226
251
|
end
|
227
252
|
|
228
|
-
def self.underscore(key)
|
253
|
+
def self.underscore(key) # TODO remove (deprecate_symbols)
|
229
254
|
key.to_s.strip.gsub(/\W+/, "_").downcase.to_sym
|
230
255
|
end
|
231
256
|
|
232
|
-
def underscore(key)
|
257
|
+
def underscore(key) # TODO remove (deprecate_symbols)
|
233
258
|
self.class.underscore(key)
|
234
259
|
end
|
235
260
|
|
@@ -249,6 +274,7 @@ module Airrecord
|
|
249
274
|
value
|
250
275
|
end
|
251
276
|
end
|
277
|
+
|
252
278
|
end
|
253
279
|
|
254
280
|
def self.table(api_key, base_key, table_name)
|
data/lib/airrecord/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: airrecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Eskildsen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -115,7 +115,7 @@ files:
|
|
115
115
|
- lib/airrecord/client.rb
|
116
116
|
- lib/airrecord/table.rb
|
117
117
|
- lib/airrecord/version.rb
|
118
|
-
homepage: https://github.com/sirupsen/
|
118
|
+
homepage: https://github.com/sirupsen/airrecord
|
119
119
|
licenses:
|
120
120
|
- MIT
|
121
121
|
metadata: {}
|