quickbase_record 0.3.3 → 0.4.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.
- checksums.yaml +8 -8
- data/.gitignore +1 -1
- data/README.md +57 -12
- data/lib/quickbase_record/field.rb +9 -0
- data/lib/quickbase_record/fields/date_field.rb +12 -0
- data/lib/quickbase_record/fields/field.rb +13 -0
- data/lib/quickbase_record/fields/file_attachment_field.rb +11 -0
- data/lib/quickbase_record/fields/number_field.rb +11 -0
- data/lib/quickbase_record/fields/string_field.rb +11 -0
- data/lib/quickbase_record/model.rb +11 -7
- data/lib/quickbase_record/queries.rb +65 -36
- data/lib/quickbase_record/table_definition.rb +44 -0
- data/lib/quickbase_record/version.rb +1 -1
- data/lib/quickbase_record.rb +0 -1
- data/quickbase_record.gemspec +1 -0
- data/spec/fakes/classroom_fake.rb +8 -7
- data/spec/fakes/student_fake.rb +0 -8
- data/spec/fakes/teacher_fake.rb +8 -8
- data/spec/field_spec.rb +39 -14
- data/spec/model_spec.rb +9 -8
- data/spec/queries_spec.rb +23 -10
- metadata +23 -3
- data/lib/quickbase_record/field_mapping.rb +0 -9
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OWYxNzdkYjc3ZjQxY2QxM2JhNmE3ZWEzNWU5YTU0ZDhmYWQ4YTY3YQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTgwYzI4Njk3Y2IxZWZhMzFkMWYxNjY3YzNjNjUxZTY5M2UxYzg5NA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MGYwNzM3N2JjM2ViZjUwZTI0MjZhYTkyMDBlMmM0MWU0MjhlMmYwNTU1MmFh
|
10
|
+
ZTU0N2EyYzc0YmYyMGZmYzZhOTkxYmJiYTQ5NzljNDkwYzYyNjFmYjJmZjlh
|
11
|
+
OWQwNjQ2ZjQwMjg3ZmMwZDI1N2U0ODVmMmYzM2VmYzM2MjAxNTc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NjQ4Nzc5Mjk2NTQwMTYxYjczOGQ3ZjcwMDEzYmQyNDI5ZmM3NjViZTYzMjZk
|
14
|
+
NzU0YmY3NzEwYzgxMDgxZWFlNDY4NTNlOGZhNTg4OTg2MThlYjZmZTdiZDQ3
|
15
|
+
MGNkNTVlZjVhY2Y1ZmUyZGU1NjlhYTFlOWVmNjgzNWU1Y2U2MGY=
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -20,22 +20,27 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
+
* [Methods](#available-methods)
|
24
|
+
|
23
25
|
### Initialize the API Client
|
24
|
-
QuickbaseRecord is built on top of the [Advantage Quickbase](https://github.com/AdvantageIntegratedSolutions/Quickbase-Gem) gem to make the API calls to QuickBase, so you'll need to configure QuickbaseRecord with your app's realm name and provide a valid username and
|
26
|
+
QuickbaseRecord is built on top of the [Advantage Quickbase](https://github.com/AdvantageIntegratedSolutions/Quickbase-Gem) gem to make the API calls to QuickBase, so you'll need to configure QuickbaseRecord with your app's realm name and provide a valid username, password, and token (if applicable). This can be done in a single initializer file with a call to `QuickbaseRecords.configure`.
|
25
27
|
|
26
28
|
```
|
27
29
|
# config/initializers/quickbase_record.rb
|
28
30
|
|
29
31
|
QuickbaseRecord.configure do |config|
|
30
|
-
config.realm = "
|
31
|
-
config.username = "valid_username"
|
32
|
-
config.password = "valid_password"
|
33
|
-
config.token = "
|
32
|
+
config.realm = "quickbase_app_realm_name"
|
33
|
+
config.username = "valid_username"
|
34
|
+
config.password = "valid_password"
|
35
|
+
config.token = "quickbase_app_token_if_applicable"
|
34
36
|
end
|
35
37
|
```
|
36
38
|
|
37
39
|
### Include it in your Class
|
38
|
-
Simply `include QuickbaseRecord::Model` in your class and use the `.define_fields` method to supply the table's DBID and a mapping of desired field names => QuickBase FIDs
|
40
|
+
Simply `include QuickbaseRecord::Model` in your class and use the `.define_fields` method to supply the table's DBID and a mapping of desired field names => QuickBase FIDs.
|
41
|
+
|
42
|
+
**(NEW IN 0.4.0)**
|
43
|
+
.define_fields follows a similar pattern to ActiveRecord migrations. It takes a block where data types and field names are definied with a corresponding QuickBase FID.
|
39
44
|
|
40
45
|
```
|
41
46
|
# app/models/post.rb
|
@@ -43,18 +48,58 @@ Simply `include QuickbaseRecord::Model` in your class and use the `.define_field
|
|
43
48
|
class Post
|
44
49
|
include QuickbaseRecord::Model
|
45
50
|
|
46
|
-
define_fields
|
47
|
-
dbid
|
48
|
-
id
|
49
|
-
content
|
50
|
-
author
|
51
|
+
define_fields do |t|
|
52
|
+
t.dbid 'abcde12345'
|
53
|
+
t.number :id, 3, :primary_key
|
54
|
+
t.string :content, 7
|
55
|
+
t.string :author, 8
|
56
|
+
t.string :title, 9
|
57
|
+
t.string :title_plus_author, 10, :read_only
|
51
58
|
})
|
52
59
|
|
53
60
|
# code...
|
54
61
|
end
|
55
62
|
```
|
56
63
|
|
57
|
-
|
64
|
+
### .define_fields
|
65
|
+
.define_fields(:field_name, fid, *options)
|
66
|
+
|
67
|
+
The following data types are currently supported:
|
68
|
+
|
69
|
+
* **dbid**
|
70
|
+
- The dbid for the QuickBase table
|
71
|
+
- **Does not take multiple arguments, only a string of the dbid**
|
72
|
+
|
73
|
+
* **string**
|
74
|
+
- All values are converted to a String
|
75
|
+
|
76
|
+
* **number**
|
77
|
+
- All values are converted to a Numeric (and knows if it needs to be a float)
|
78
|
+
* **date**
|
79
|
+
- All values are converted to a string representation of the date value: "07/30/2015" or nil for empty values
|
80
|
+
* **file_attachment**
|
81
|
+
- Doesn't really do anything, only makes you feel better :) File attachments are explained below.
|
82
|
+
|
83
|
+
Additional options may be added to field definitions:
|
84
|
+
|
85
|
+
* **:primary_key**
|
86
|
+
- This is a required option for one field.
|
87
|
+
* **:read_only**
|
88
|
+
- Fields marked as :read_only will not respond to #save or #update_attributes calls.
|
89
|
+
- Useful for formula/lookup/other fields in your QuickBase table that you can't write to.
|
90
|
+
|
91
|
+
|
92
|
+
**IMPORTANT: You must supply a "dbid" data type and mark a single field as :primary_key**
|
93
|
+
|
94
|
+
### Queries
|
95
|
+
To query for records you can use the .find, .where, or .qid methods on the class. See below for examples.
|
96
|
+
|
97
|
+
If you want to see the QuickBase query string output of a .where() argument you can pass your query hash to the .build_query() method and it will return the QuickBase query.
|
98
|
+
|
99
|
+
```
|
100
|
+
Post.build_query(author: 'Cullen', title: 'Some Title')
|
101
|
+
=> "{'8'.EX.'Cullen'}AND{'9'.EX.'Some Title'}"
|
102
|
+
```
|
58
103
|
|
59
104
|
### What You Get
|
60
105
|
Classes that include QuickbaseRecord::Model and define their fields will have a handful of class and instance methods for interacting with your QuickBase application similar to ActiveRecord. The goal is to be able to use QuickBase as a database and treat your models the same way you would with a traditional database.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Field
|
2
|
+
attr_accessor :field_name, :fid, :options
|
3
|
+
|
4
|
+
def initialize(args={})
|
5
|
+
@field_name = args[:field_name]
|
6
|
+
@fid = args[:fid]
|
7
|
+
@options = args[:options]
|
8
|
+
end
|
9
|
+
|
10
|
+
def convert(value)
|
11
|
+
Raise "#{self.class} must implement #convert to be a true subclass of Field"
|
12
|
+
end
|
13
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'table_definition'
|
2
|
+
|
1
3
|
module QuickbaseRecord
|
2
4
|
module Model
|
3
5
|
extend ActiveSupport::Concern
|
@@ -13,19 +15,21 @@ module QuickbaseRecord
|
|
13
15
|
end
|
14
16
|
|
15
17
|
module ClassMethods
|
18
|
+
attr_accessor :fields, :dbid
|
16
19
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
fields(fields)
|
20
|
+
def define_fields
|
21
|
+
table_definition = TableDefinition.new
|
22
|
+
yield table_definition
|
23
|
+
@dbid = table_definition.fields[:dbid]
|
24
|
+
@fields = table_definition.fields.reject { |field_name, field| field_name == :dbid }
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def initialize(attributes={})
|
27
29
|
create_attr_accesssors
|
28
30
|
assign_attributes(attributes) if attributes
|
31
|
+
|
32
|
+
super()
|
29
33
|
end
|
30
34
|
|
31
35
|
def persisted?
|
@@ -33,7 +37,7 @@ module QuickbaseRecord
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def create_attr_accesssors
|
36
|
-
self.class.fields.each do |field_name,
|
40
|
+
self.class.fields.each do |field_name, field|
|
37
41
|
self.class.send(:attr_accessor, field_name)
|
38
42
|
end
|
39
43
|
end
|
@@ -5,19 +5,18 @@ module QuickbaseRecord
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
include QuickbaseRecord::Client
|
7
7
|
|
8
|
-
|
9
8
|
module ClassMethods
|
10
|
-
def dbid
|
11
|
-
@dbid ||= fields[:dbid]
|
12
|
-
end
|
13
|
-
|
14
9
|
def clist
|
15
|
-
@clist ||= fields.reject{ |field_name| field_name == :dbid }.values.join('.')
|
10
|
+
@clist ||= fields.reject{ |field_name, field| field_name == :dbid }.values.collect {|field| field.fid }.join('.')
|
16
11
|
end
|
17
12
|
|
18
|
-
def find(id, query_options
|
13
|
+
def find(id, query_options={})
|
19
14
|
query_options = build_query_options(query_options[:query_options])
|
20
|
-
|
15
|
+
if query_options[:clist]
|
16
|
+
clist = query_options.delete(:clist)
|
17
|
+
else
|
18
|
+
clist = self.clist
|
19
|
+
end
|
21
20
|
query = { query: build_query(id: id), clist: clist }.merge(query_options)
|
22
21
|
query_response = qb_client.do_query(dbid, query).first
|
23
22
|
|
@@ -34,7 +33,11 @@ module QuickbaseRecord
|
|
34
33
|
options = {}
|
35
34
|
end
|
36
35
|
|
37
|
-
|
36
|
+
if options[:clist]
|
37
|
+
clist = options.delete(:clist)
|
38
|
+
else
|
39
|
+
clist = self.clist
|
40
|
+
end
|
38
41
|
|
39
42
|
query = { query: build_query(query_hash), clist: clist }.merge(options)
|
40
43
|
query_response = qb_client.do_query(dbid, query)
|
@@ -44,19 +47,19 @@ module QuickbaseRecord
|
|
44
47
|
build_collection(query_response)
|
45
48
|
end
|
46
49
|
|
47
|
-
def create(attributes
|
50
|
+
def create(attributes={})
|
48
51
|
object = new(attributes)
|
49
52
|
object.save
|
50
53
|
return object
|
51
54
|
end
|
52
55
|
|
53
56
|
def qid(id)
|
54
|
-
|
55
|
-
query_response = qb_client.do_query(dbid,
|
57
|
+
query_options = { qid: id, clist: clist }
|
58
|
+
query_response = qb_client.do_query(dbid, query_options)
|
56
59
|
|
57
60
|
return [] if query_response.first.nil?
|
58
61
|
|
59
|
-
|
62
|
+
build_array_of_new_objects(query_response)
|
60
63
|
end
|
61
64
|
|
62
65
|
def build_query(query_hash)
|
@@ -96,7 +99,7 @@ module QuickbaseRecord
|
|
96
99
|
if result[option_name]
|
97
100
|
result[option_name] << ".#{convert_field_name_to_fid(value)}"
|
98
101
|
else
|
99
|
-
result[option_name] = convert_field_name_to_fid(value)
|
102
|
+
result[option_name] = convert_field_name_to_fid(value).to_s
|
100
103
|
end
|
101
104
|
end
|
102
105
|
end
|
@@ -111,6 +114,13 @@ module QuickbaseRecord
|
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
117
|
+
def build_array_of_new_objects(query_response)
|
118
|
+
query_response.map do |response|
|
119
|
+
converted_response = convert_quickbase_response(response)
|
120
|
+
new(converted_response)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
114
124
|
def join_with_and(fid, value, comparator="EX")
|
115
125
|
"{'#{fid}'.#{comparator}.'#{value}'}"
|
116
126
|
end
|
@@ -136,18 +146,20 @@ module QuickbaseRecord
|
|
136
146
|
end
|
137
147
|
|
138
148
|
def convert_field_name_to_fid(field_name)
|
139
|
-
|
149
|
+
fields[field_name.to_sym].fid
|
140
150
|
end
|
141
151
|
|
142
|
-
def
|
143
|
-
|
152
|
+
def covert_fid_to_field_name(fid)
|
153
|
+
fields.select { |field_name, field| field.fid == fid.to_i }.values.first.field_name
|
144
154
|
end
|
145
155
|
|
146
156
|
def convert_quickbase_response(response)
|
147
157
|
result = {}
|
148
158
|
|
149
159
|
response.each do |fid, value|
|
150
|
-
|
160
|
+
field = fields.select { |field_name, field| field.fid == fid.to_i }.values.first
|
161
|
+
field_name = field.field_name
|
162
|
+
value = field.convert(value)
|
151
163
|
result[field_name] = value
|
152
164
|
end
|
153
165
|
|
@@ -160,17 +172,17 @@ module QuickbaseRecord
|
|
160
172
|
|
161
173
|
return query_string unless uses_field_name
|
162
174
|
|
163
|
-
fields.each do |field_name,
|
164
|
-
field_name = field_name.to_s
|
175
|
+
fields.each do |field_name, field|
|
165
176
|
match_string = "\{'?(#{field_name})'?\..*\.'?.*'?\}"
|
177
|
+
|
166
178
|
if query_string.scan(/#{match_string}/).length > 0
|
167
|
-
query_string.gsub!(field_name, fid.to_s)
|
179
|
+
query_string.gsub!(field_name.to_s, field.fid.to_s)
|
168
180
|
match_found = true
|
169
181
|
end
|
170
182
|
end
|
171
183
|
|
172
184
|
if !match_found
|
173
|
-
raise ArgumentError, "Invalid arguments on #{self}.
|
185
|
+
raise ArgumentError, "Invalid arguments on #{self}.query() - no matching field name found. \nMake sure the field is part of your class configuration."
|
174
186
|
end
|
175
187
|
|
176
188
|
return query_string
|
@@ -178,20 +190,32 @@ module QuickbaseRecord
|
|
178
190
|
end
|
179
191
|
|
180
192
|
# INSTANCE METHODS
|
193
|
+
def writable_fields
|
194
|
+
@writable_fields ||= self.class.fields.reject{ |field_name, field| field.options.include?(:read_only) }
|
195
|
+
end
|
196
|
+
|
197
|
+
def primary_key_field_name
|
198
|
+
@primary_key_field ||= self.class.fields.select { |field_name, field| field.options.include?(:primary_key) }.keys.first
|
199
|
+
end
|
200
|
+
|
201
|
+
def record_id_field_name
|
202
|
+
@record_id_field_name ||= self.class.fields.select { |field_name, field| field.fid == 3 }.keys.first
|
203
|
+
end
|
204
|
+
|
181
205
|
def save
|
206
|
+
primary_key = public_send(primary_key_field_name)
|
182
207
|
current_object = {}
|
183
|
-
self.class.fields.each do |field_name,
|
184
|
-
current_object[fid
|
208
|
+
self.class.fields.each do |field_name, field|
|
209
|
+
current_object[field.fid] = public_send(field_name)
|
185
210
|
end
|
186
211
|
|
187
|
-
if current_object[
|
212
|
+
if current_object[3] #object has a record_id, so we'll edit it
|
188
213
|
remove_unwritable_fields(current_object)
|
189
|
-
qb_client.edit_record(self.class.dbid,
|
214
|
+
qb_client.edit_record(self.class.dbid, primary_key, current_object)
|
190
215
|
else
|
191
216
|
remove_unwritable_fields(current_object)
|
192
217
|
new_rid = qb_client.add_record(self.class.dbid, current_object)
|
193
|
-
|
194
|
-
public_send("#{id_field_name}=", new_rid)
|
218
|
+
public_send("#{record_id_field_name}=", new_rid)
|
195
219
|
end
|
196
220
|
|
197
221
|
return self
|
@@ -199,8 +223,7 @@ module QuickbaseRecord
|
|
199
223
|
|
200
224
|
def delete
|
201
225
|
# we have to use [record id] because of the advantage_quickbase gem
|
202
|
-
|
203
|
-
rid = public_send(id_field_name)
|
226
|
+
rid = public_send(record_id_field_name)
|
204
227
|
return false unless rid
|
205
228
|
|
206
229
|
successful = qb_client.delete_record(self.class.dbid, rid)
|
@@ -213,20 +236,26 @@ module QuickbaseRecord
|
|
213
236
|
self.assign_attributes(attributes)
|
214
237
|
updated_attributes = {}
|
215
238
|
attributes.each { |field_name, value| updated_attributes[self.class.convert_field_name_to_fid(field_name)] = value }
|
216
|
-
|
239
|
+
primary_key = public_send(primary_key_field_name)
|
240
|
+
record_id = public_send(record_id_field_name)
|
217
241
|
|
218
|
-
if
|
219
|
-
|
242
|
+
if record_id
|
243
|
+
remove_unwritable_fields(updated_attributes)
|
244
|
+
qb_client.edit_record(self.class.dbid, primary_key, updated_attributes)
|
220
245
|
else
|
221
|
-
|
246
|
+
remove_unwritable_fields(updated_attributes)
|
247
|
+
new_id = qb_client.add_record(self.class.dbid, updated_attributes)
|
248
|
+
public_send("#{record_id_field_name}=", new_id)
|
222
249
|
end
|
223
250
|
|
224
251
|
return self
|
225
252
|
end
|
226
253
|
|
227
254
|
def remove_unwritable_fields(hash)
|
228
|
-
|
229
|
-
|
255
|
+
writable_fids = writable_fields.values.collect { |field| field.fid }
|
256
|
+
|
257
|
+
hash.delete_if do |fid, value|
|
258
|
+
value.nil? || !writable_fids.include?(fid)
|
230
259
|
end
|
231
260
|
end
|
232
261
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'quickbase_record/fields/string_field'
|
2
|
+
require 'quickbase_record/fields/number_field'
|
3
|
+
require 'quickbase_record/fields/date_field'
|
4
|
+
require 'quickbase_record/fields/file_attachment_field'
|
5
|
+
|
6
|
+
class TableDefinition
|
7
|
+
attr_accessor :fields
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@fields = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def dbid(dbid_string)
|
14
|
+
fields[:dbid] = dbid_string
|
15
|
+
end
|
16
|
+
|
17
|
+
def string(field_name, fid, *options)
|
18
|
+
field_name = field_name.to_sym
|
19
|
+
fid = fid.to_i
|
20
|
+
|
21
|
+
fields[field_name] = StringField.new(field_name: field_name, fid: fid, options: options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def number(field_name, fid, *options)
|
25
|
+
field_name = field_name.to_sym
|
26
|
+
fid = fid.to_i
|
27
|
+
|
28
|
+
fields[field_name] = NumberField.new(field_name: field_name, fid: fid, options: options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_attachment(field_name, fid, *options)
|
32
|
+
field_name = field_name.to_sym
|
33
|
+
fid = fid.to_i
|
34
|
+
|
35
|
+
fields[field_name] = FileAttachmentField.new(field_name: field_name, fid: fid, options: options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def date(field_name, fid, *options)
|
39
|
+
field_name = field_name.to_sym
|
40
|
+
fid = fid.to_i
|
41
|
+
|
42
|
+
fields[field_name] = DateField.new(field_name: field_name, fid: fid, options: options)
|
43
|
+
end
|
44
|
+
end
|
data/lib/quickbase_record.rb
CHANGED
@@ -3,7 +3,6 @@ require 'active_support/all'
|
|
3
3
|
require 'active_model'
|
4
4
|
require 'quickbase' # This is the file name for the 'advantage_quickbase' gem. Idk why Ben named it this way...
|
5
5
|
require_relative 'quickbase_record/configuration'
|
6
|
-
require_relative 'quickbase_record/field_mapping'
|
7
6
|
require_relative 'quickbase_record/client'
|
8
7
|
require_relative 'quickbase_record/queries'
|
9
8
|
require_relative 'quickbase_record/model'
|
data/quickbase_record.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "shoulda-matchers"
|
24
25
|
|
25
26
|
spec.add_runtime_dependency "advantage_quickbase"
|
26
27
|
spec.add_runtime_dependency "activesupport"
|
@@ -4,11 +4,12 @@ class ClassroomFake
|
|
4
4
|
include QuickbaseRecord::Model
|
5
5
|
|
6
6
|
# primary key is not record id
|
7
|
-
define_fields
|
8
|
-
dbid
|
9
|
-
date_created
|
10
|
-
record_id
|
11
|
-
id
|
12
|
-
subject
|
13
|
-
|
7
|
+
define_fields do |t|
|
8
|
+
t.dbid 'bj4yju38j'
|
9
|
+
t.date :date_created, 1, :read_only
|
10
|
+
t.number :record_id, 3, :read_only
|
11
|
+
t.number :id, 6, :primary_key
|
12
|
+
t.string :subject, 7
|
13
|
+
t.string :subject_plus_room, 8, :read_only
|
14
|
+
end
|
14
15
|
end
|
data/spec/fakes/student_fake.rb
CHANGED
data/spec/fakes/teacher_fake.rb
CHANGED
@@ -3,12 +3,12 @@ require './lib/quickbase_record'
|
|
3
3
|
class TeacherFake
|
4
4
|
include QuickbaseRecord::Model
|
5
5
|
|
6
|
-
define_fields
|
7
|
-
|
8
|
-
:id
|
9
|
-
:name
|
10
|
-
:subject
|
11
|
-
:salary
|
12
|
-
:attachment
|
13
|
-
|
6
|
+
define_fields do |t|
|
7
|
+
t.dbid "bjzrx8cjn"
|
8
|
+
t.number :id, 3, :primary_key, :read_only
|
9
|
+
t.string :name, 6
|
10
|
+
t.string :subject, 7
|
11
|
+
t.number :salary, 8
|
12
|
+
t.file_attachment :attachment, 9
|
13
|
+
end
|
14
14
|
end
|
data/spec/field_spec.rb
CHANGED
@@ -1,14 +1,39 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
require 'quickbase_record/fields/field'
|
2
|
+
require 'quickbase_record/fields/string_field'
|
3
|
+
require 'quickbase_record/fields/number_field'
|
4
|
+
require 'quickbase_record/fields/date_field'
|
5
|
+
require 'quickbase_record/fields/file_attachment_field'
|
6
|
+
|
7
|
+
RSpec.describe StringField do
|
8
|
+
describe '#convert' do
|
9
|
+
it "returns a string" do
|
10
|
+
expect(StringField.new.convert(123)).to eq('123')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.describe NumberField do
|
16
|
+
describe '#convert' do
|
17
|
+
it "returns a number" do
|
18
|
+
expect(NumberField.new.convert('123')).to eq(123)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns a float" do
|
22
|
+
expect(NumberField.new.convert('123.45')).to eq(123.45)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
RSpec.describe DateField do
|
28
|
+
describe '#convert' do
|
29
|
+
it "converts ms to a formated date string" do
|
30
|
+
now_in_ms = Time.now.to_f * 1000
|
31
|
+
now_as_string = DateTime.now.strftime('%m/%d/%Y')
|
32
|
+
expect(DateField.new.convert(now_in_ms)).to eq(now_as_string)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns nil when passed an empty string" do
|
36
|
+
expect(DateField.new.convert("")).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/model_spec.rb
CHANGED
@@ -3,15 +3,16 @@ require './spec/fakes/student_fake'
|
|
3
3
|
RSpec.describe QuickbaseRecord::Model do
|
4
4
|
describe '.define_fields' do
|
5
5
|
it "sets the class field mappings for field names => FIDs" do
|
6
|
-
StudentFake.define_fields
|
7
|
-
|
8
|
-
:id
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
|
6
|
+
StudentFake.define_fields do |t|
|
7
|
+
t.dbid "abc123"
|
8
|
+
t.number :id, 3, :primary_key, :read_only
|
9
|
+
t.date :date_created, 4
|
10
|
+
t.string :name, 6
|
11
|
+
t.number :grade, 7, :read_only
|
12
|
+
t.string :email, 8
|
13
|
+
end
|
13
14
|
|
14
|
-
expect(StudentFake.fields[:id]).to eq(3)
|
15
|
+
expect(StudentFake.fields[:id].fid).to eq(3)
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
data/spec/queries_spec.rb
CHANGED
@@ -5,7 +5,7 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
5
5
|
describe '.find' do
|
6
6
|
it "finds a single Teacher given an ID" do
|
7
7
|
teacher = TeacherFake.find(1)
|
8
|
-
expect(teacher.id).to eq(
|
8
|
+
expect(teacher.id).to eq(1)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "returns an object of the Teacher class" do
|
@@ -37,12 +37,12 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
37
37
|
|
38
38
|
it "accepts a string in QuickBase query format" do
|
39
39
|
teachers = TeacherFake.where("{'3'.EX.'1'}")
|
40
|
-
expect(teachers.first.id).to eq(
|
40
|
+
expect(teachers.first.id).to eq(1)
|
41
41
|
end
|
42
42
|
|
43
43
|
it "accepts a string in QuickBase query format using field names" do
|
44
44
|
teachers = TeacherFake.where("{'id'.EX.'1'}")
|
45
|
-
expect(teachers.first.id).to eq(
|
45
|
+
expect(teachers.first.id).to eq(1)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "returns an empty array if no QuickBase records are found" do
|
@@ -51,7 +51,7 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it "accepts query options" do
|
54
|
-
teachers = TeacherFake.where(subject: ['
|
54
|
+
teachers = TeacherFake.where(subject: ['Biology', 'Gym'], query_options: {slist: 'subject', options: 'sortorder-D'})
|
55
55
|
expect(teachers.first.subject).to eq('Gym')
|
56
56
|
end
|
57
57
|
|
@@ -83,6 +83,13 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
83
83
|
end
|
84
84
|
|
85
85
|
describe '#save' do
|
86
|
+
it "doesn't save :read_only fields" do
|
87
|
+
classroom = ClassroomFake.find(101)
|
88
|
+
classroom.assign_attributes(subject_plus_room: "this shouldn't save")
|
89
|
+
classroom.save
|
90
|
+
expect(ClassroomFake.find(101).subject_plus_room).not_to eq("this shouldn't save")
|
91
|
+
end
|
92
|
+
|
86
93
|
context "when record ID is the primary key" do
|
87
94
|
it "creates a new record in QuickBase for an object without an ID and sets it's new ID" do
|
88
95
|
cullen = TeacherFake.new(name: 'Cullen Jett', salary: '1,000,000.00')
|
@@ -114,17 +121,17 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
114
121
|
|
115
122
|
context "when record ID is not the primary key" do
|
116
123
|
it "creates a new record if the object doesn't have a record ID" do
|
117
|
-
math = ClassroomFake.new(id:
|
124
|
+
math = ClassroomFake.new(id: 1, subject: 'Math')
|
118
125
|
math.save
|
119
|
-
expect(ClassroomFake.find(
|
126
|
+
expect(ClassroomFake.find(1)).not_to be_nil
|
120
127
|
math.delete
|
121
128
|
end
|
122
129
|
|
123
130
|
it "sets the object's record id for new records" do
|
124
|
-
english = ClassroomFake.new(id:
|
131
|
+
english = ClassroomFake.new(id: 2, subject: 'English', date_created: 'this should not save')
|
125
132
|
english.save
|
126
133
|
expect(english.record_id).to be_present
|
127
|
-
expect(english.record_id).not_to eq(
|
134
|
+
expect(english.record_id).not_to eq(2)
|
128
135
|
english.delete
|
129
136
|
end
|
130
137
|
|
@@ -153,7 +160,7 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
153
160
|
|
154
161
|
context "when record ID is not the primary key" do
|
155
162
|
it "deletes the record from QuickBase" do
|
156
|
-
gym = ClassroomFake.new(id:
|
163
|
+
gym = ClassroomFake.new(id: 3, subject: 'Gym')
|
157
164
|
gym.save
|
158
165
|
expect(gym.delete).to eq(gym)
|
159
166
|
end
|
@@ -196,6 +203,12 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
196
203
|
teacher.update_attributes()
|
197
204
|
expect(teacher.update_attributes()).to be false
|
198
205
|
end
|
206
|
+
|
207
|
+
it "doesn't save :read_only attributes" do
|
208
|
+
classroom = ClassroomFake.find(101)
|
209
|
+
classroom.update_attributes(subject_plus_room: "this shouldn't save")
|
210
|
+
expect(ClassroomFake.find(101).subject_plus_room).not_to eq("this shouldn't save")
|
211
|
+
end
|
199
212
|
end
|
200
213
|
|
201
214
|
# This is sort of a private method, but it seems pretty important so I'm keeping these tests.
|
@@ -254,7 +267,7 @@ RSpec.describe QuickbaseRecord::Queries do
|
|
254
267
|
|
255
268
|
describe '.build_query_options' do
|
256
269
|
it "returns a hash" do
|
257
|
-
options = {clist: '
|
270
|
+
options = {clist: 'id.salary'}
|
258
271
|
expect(TeacherFake.build_query_options(options)).to be_a Hash
|
259
272
|
end
|
260
273
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quickbase_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cullen Jett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: shoulda-matchers
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: advantage_quickbase
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,9 +125,15 @@ files:
|
|
111
125
|
- lib/quickbase_record.rb
|
112
126
|
- lib/quickbase_record/client.rb
|
113
127
|
- lib/quickbase_record/configuration.rb
|
114
|
-
- lib/quickbase_record/
|
128
|
+
- lib/quickbase_record/field.rb
|
129
|
+
- lib/quickbase_record/fields/date_field.rb
|
130
|
+
- lib/quickbase_record/fields/field.rb
|
131
|
+
- lib/quickbase_record/fields/file_attachment_field.rb
|
132
|
+
- lib/quickbase_record/fields/number_field.rb
|
133
|
+
- lib/quickbase_record/fields/string_field.rb
|
115
134
|
- lib/quickbase_record/model.rb
|
116
135
|
- lib/quickbase_record/queries.rb
|
136
|
+
- lib/quickbase_record/table_definition.rb
|
117
137
|
- lib/quickbase_record/version.rb
|
118
138
|
- quickbase_record.gemspec
|
119
139
|
- spec/fakes/classroom_fake.rb
|