airrecord 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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: {}
|