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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzM2ODllMjE5Y2VjZTcxNGYxZTc0MGJlOTZlZmMxZWY5YWE0YzZiZA==
4
+ OWYxNzdkYjc3ZjQxY2QxM2JhNmE3ZWEzNWU5YTU0ZDhmYWQ4YTY3YQ==
5
5
  data.tar.gz: !binary |-
6
- ODZkYjE3YjVmNWFhZjY2ZjUzYWEzYWZlYTUxN2FlZWEyYWM0NDRhNw==
6
+ NTgwYzI4Njk3Y2IxZWZhMzFkMWYxNjY3YzNjNjUxZTY5M2UxYzg5NA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZWZmMjZlOWU0NjZmYjNlNDkxY2E2Yjk5YTgyNDQzOWZlZGQ5MDRmNTI5Nzc0
10
- MDc0OWFiNmVmM2Q3MTBiY2YyMmU0ZTJiODY1MTFiNTU0YTkxNDhhNDdjMDMx
11
- MTZhOWFmNTUzZjMzMGQ5Y2Y4ZjdhZjUzOWU2YThkNDVlNGI4Mjk=
9
+ MGYwNzM3N2JjM2ViZjUwZTI0MjZhYTkyMDBlMmM0MWU0MjhlMmYwNTU1MmFh
10
+ ZTU0N2EyYzc0YmYyMGZmYzZhOTkxYmJiYTQ5NzljNDkwYzYyNjFmYjJmZjlh
11
+ OWQwNjQ2ZjQwMjg3ZmMwZDI1N2U0ODVmMmYzM2VmYzM2MjAxNTc=
12
12
  data.tar.gz: !binary |-
13
- MDBlMjU4ZGIwN2MzYjkxMzkxMTE3NWVjMzY0ODhhZWY2ODI0ZDNlMTkzNWY1
14
- MTE2MGVmMjM2MDMwNzMxNmYxMTFkZWMxNTZjZGZlZDU0ZDIyN2Q4NGE1Yjdi
15
- YzBkODY4YTRmNDQ5OGNlY2U1NWY4NWRmMWZlMmNkMWU4ZmM2N2U=
13
+ NjQ4Nzc5Mjk2NTQwMTYxYjczOGQ3ZjcwMDEzYmQyNDI5ZmM3NjViZTYzMjZk
14
+ NzU0YmY3NzEwYzgxMDgxZWFlNDY4NTNlOGZhNTg4OTg2MThlYjZmZTdiZDQ3
15
+ MGNkNTVlZjVhY2Y1ZmUyZGU1NjlhYTFlOWVmNjgzNWU1Y2U2MGY=
data/.gitignore CHANGED
@@ -13,5 +13,5 @@
13
13
  *.a
14
14
  mkmf.log
15
15
  /spec/config.yml
16
- .DS_Store
16
+ *.DS_Store
17
17
  *.gem
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 password. This can be done in a single initializer file with a call to `QuickbaseRecords.configure`, making sure to keep your credentials safe from the world.
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 = "your_apps_realm_name"
31
- config.username = "valid_username" (or something like ENV["QB_USERNAME"])
32
- config.password = "valid_password" (or something like ENV["QB_PASSWORD"])
33
- config.token = "your_app_token_if_applicable"
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: 'abcde12345'
48
- id: 3,
49
- content: 7,
50
- author: 8
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
- **IMPORTANT:** You must supply a key/value pair for :dbid and :id (QuickbaseRecord uses :id instead of :record_id to look more like standard ActiveRecord models). If your table does not use [Record ID] as it's primary key then you must supply a key/value pair for :record_id and assign :id to the primary key.
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,9 @@
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
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'field'
2
+
3
+ class DateField < Field
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+
8
+ def convert(value)
9
+ return nil if value == ""
10
+ Time.at(value.to_i / 1000).strftime("%m/%d/%Y")
11
+ end
12
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ require_relative 'field'
2
+
3
+ class FileAttachmentField < Field
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+
8
+ def convert(value)
9
+ value
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'field'
2
+
3
+ class NumberField < Field
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+
8
+ def convert(value)
9
+ value.match(/\./) ? value.to_f : value.to_i
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'field'
2
+
3
+ class StringField < Field
4
+ def initialize(*args)
5
+ super(*args)
6
+ end
7
+
8
+ def convert(value)
9
+ value.to_s
10
+ end
11
+ 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 fields(fields_hash={})
18
- @fields ||= FieldMapping.new(fields_hash).fields
19
- end
20
-
21
- def define_fields(fields)
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, value|
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
- clist = query_options.delete(:clist) if query_options[:clist]
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
- clist = options.delete(:clist) if options[:clist]
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
- query = { qid: id, clist: clist }
55
- query_response = qb_client.do_query(dbid, query)
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
- build_collection(query_response)
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
- self.fields[field_name.to_sym].to_s
149
+ fields[field_name.to_sym].fid
140
150
  end
141
151
 
142
- def convert_fid_to_field_name(fid)
143
- self.fields.invert[fid.to_i]
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
- field_name = convert_fid_to_field_name(fid)
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, fid|
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}.where() - no matching field name found. \nMake sure the field is part of your class configuration."
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, fid|
184
- current_object[fid.to_s] = public_send(field_name)
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['3'] #object has a record_id, so we'll edit it
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, self.id, current_object)
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
- id_field_name = self.class.fields.select { |field_name, fid| fid == 3 }.keys.first
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
- id_field_name = self.class.fields.select { |field_name, fid| fid == 3 }.keys.first
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
- updated_attributes.delete_if { |key, value| value.nil? }
239
+ primary_key = public_send(primary_key_field_name)
240
+ record_id = public_send(record_id_field_name)
217
241
 
218
- if self.id
219
- qb_client.edit_record(self.class.dbid, self.id, updated_attributes)
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
- self.id = qb_client.add_record(self.class.dbid, updated_attributes)
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
- hash.delete_if do |key, value|
229
- value.nil? || key.to_i <= 5 || key == :dbid
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
@@ -1,3 +1,3 @@
1
1
  module QuickbaseRecord
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -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'
@@ -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: 'bj4yju38j',
9
- date_created: 1,
10
- record_id: 3,
11
- id: 6,
12
- subject: 7
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
@@ -2,12 +2,4 @@ require './lib/quickbase_record'
2
2
 
3
3
  class StudentFake
4
4
  include QuickbaseRecord::Model
5
-
6
- define_fields ({
7
- :dbid => 'bjzrx8ckw',
8
- :id => 3,
9
- :name => 6,
10
- :grade => 7,
11
- :email => 8
12
- })
13
5
  end
@@ -3,12 +3,12 @@ require './lib/quickbase_record'
3
3
  class TeacherFake
4
4
  include QuickbaseRecord::Model
5
5
 
6
- define_fields ({
7
- :dbid => "bjzrx8cjn",
8
- :id => 3,
9
- :name => 6,
10
- :subject => 7,
11
- :salary => 8,
12
- :attachment => 9
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
- # require 'quickbase_record/field_mapping'
2
-
3
- # RSpec.describe QuickbaseRecord::Field do
4
- # describe '#value' do
5
- # it "returns the value if an integer is passed" do
6
- # expect(QuickbaseRecord::Field.new(123).value).to eq(123)
7
- # end
8
-
9
- # it "returns a formatted date if a hash with the key :date is passed" do
10
- # value = {date: 123}
11
- # expect(QuickbaseRecord::Field.new(value).to)
12
- # end
13
- # end
14
- # end
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
- :dbid => 'bjzrx8ckw',
8
- :id => 3,
9
- :name => 6,
10
- :grade => 7,
11
- :email => 8
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("1")
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('1')
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('1')
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: ['Gym', 'Biology'], query_options: {slist: 'subject', options: 'sortorder-D'})
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: '1', subject: 'Math')
124
+ math = ClassroomFake.new(id: 1, subject: 'Math')
118
125
  math.save
119
- expect(ClassroomFake.find('1')).not_to be_nil
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: '2', subject: 'English', date_created: 'this should not save')
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('2')
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: '3', subject: 'Gym')
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: '1.2.3'}
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.3.3
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-27 00:00:00.000000000 Z
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/field_mapping.rb
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
@@ -1,9 +0,0 @@
1
- module QuickbaseRecord
2
- class FieldMapping
3
- attr_accessor :fields
4
-
5
- def initialize(fields={})
6
- @fields = fields
7
- end
8
- end
9
- end