filemaker 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +129 -17
  3. data/filemaker.gemspec +1 -0
  4. data/lib/filemaker.rb +47 -0
  5. data/lib/filemaker/api/query_commands/findquery.rb +20 -3
  6. data/lib/filemaker/configuration.rb +1 -1
  7. data/lib/filemaker/core_ext/hash.rb +19 -15
  8. data/lib/filemaker/error.rb +5 -0
  9. data/lib/filemaker/metadata/field.rb +21 -5
  10. data/lib/filemaker/model.rb +132 -0
  11. data/lib/filemaker/model/builder.rb +52 -0
  12. data/lib/filemaker/model/components.rb +25 -0
  13. data/lib/filemaker/model/criteria.rb +101 -0
  14. data/lib/filemaker/model/field.rb +38 -0
  15. data/lib/filemaker/model/fields.rb +80 -0
  16. data/lib/filemaker/model/findable.rb +35 -0
  17. data/lib/filemaker/model/optional.rb +69 -0
  18. data/lib/filemaker/model/pagination.rb +41 -0
  19. data/lib/filemaker/model/persistable.rb +96 -0
  20. data/lib/filemaker/model/relations.rb +72 -0
  21. data/lib/filemaker/model/relations/belongs_to.rb +30 -0
  22. data/lib/filemaker/model/relations/has_many.rb +79 -0
  23. data/lib/filemaker/model/relations/proxy.rb +35 -0
  24. data/lib/filemaker/model/selectable.rb +146 -0
  25. data/lib/filemaker/railtie.rb +17 -0
  26. data/lib/filemaker/record.rb +25 -0
  27. data/lib/filemaker/resultset.rb +12 -4
  28. data/lib/filemaker/server.rb +7 -5
  29. data/lib/filemaker/version.rb +1 -1
  30. data/spec/filemaker/api/query_commands/compound_find_spec.rb +13 -1
  31. data/spec/filemaker/configuration_spec.rb +23 -0
  32. data/spec/filemaker/layout_spec.rb +0 -1
  33. data/spec/filemaker/model/criteria_spec.rb +304 -0
  34. data/spec/filemaker/model/relations_spec.rb +85 -0
  35. data/spec/filemaker/model_spec.rb +73 -0
  36. data/spec/filemaker/record_spec.rb +12 -1
  37. data/spec/spec_helper.rb +1 -0
  38. data/spec/support/filemaker.yml +13 -0
  39. data/spec/support/models.rb +38 -0
  40. metadata +44 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da908ea60c24ec21422e5405e5c18e149825bb78
4
- data.tar.gz: cf777449498d727f9c15ab765f5e610b292d0f8d
3
+ metadata.gz: 2d84b6982396ee09d4e78ae0d12be8fbb4ca3b69
4
+ data.tar.gz: 8a758a58c2b0462e8b34ec246b6aae68b70ca750
5
5
  SHA512:
6
- metadata.gz: f6d6523f795649e9f2b09cc66ce21fff013586713a677b002734ffbc03eb3d5cdec949198764361d594c896851d1c7000f58e2adb28c76293091cd37b9acc029
7
- data.tar.gz: 2b44e3649cfce1a9fa65ce5d7264f717ede0c86f63eafd695b9370deebd14f4870d2d5eb626860317e9cd5013e7f579cfa4bf64bd81125bd3ca7c38c1a49eda0
6
+ metadata.gz: cd8c34c33807e773c6f3bff976e1b095e35dd18e89e877da8f905af484d3d78b3765f6ac32c8770048f24ed993a3f24428b86a6de342cd79e439d377e586516f
7
+ data.tar.gz: cf8aa8ec4943ff7497387d5aa5f61c0a29b598dfa15a1d85f3cdbbdfd935ef732a75b9ac9b2110467c5f2afff09c671dd80464efee01856d637335e3f8ffbe53
data/README.md CHANGED
@@ -21,28 +21,30 @@ Ensure you have Web Publishing Engine (XML Publishing) enabled. Please turn on S
21
21
  Configuration for initializing a server:
22
22
 
23
23
  * `host` - IP or hostname
24
- * `ssl` - `{ verify: false }` if you are using FileMaker's unsigned certificate. You can also pass a hash which will be forwarded to Faraday directly like `ssl: { client_cert: '', client_key: '', ca_file: '', ca_path: '/path/to/certs', cert_store: '' }`. See [Setting up SSL certificates](https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates)
25
24
  * `account` - Please use `ENV` variable like `ENV['FILEMAKER_ACCOUNT']`
26
25
  * `password` - Please use `ENV` variable like `ENV['FILEMAKER_PASSWORD']`
26
+ * `ssl` - Use `{ verify: false }` if you are using FileMaker's unsigned certificate. You can also pass a hash which will be forwarded to Faraday directly like `ssl: { client_cert: '', client_key: '', ca_file: '', ca_path: '/path/to/certs', cert_store: '' }`. See [Setting up SSL certificates on the Faraday wiki](https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates)
27
+ * `log` - A choice of `:simple`, `:curl` and `:curl_auth`.
27
28
 
28
29
  ```ruby
29
30
  server = Filemaker::Server.new do |config|
30
- config.host = 'localhost'
31
- config.account = ENV['FILEMAKER_ACCOUNT']
32
- config.password = ENV['FILEMAKER_PASSWORD']
33
- config.ssl = { verify: false }
34
- config.log = :curl
31
+ config.host = ENV['FILEMAKER_HOST']
32
+ config.account_name = ENV['FILEMAKER_ACCOUNT_NAME']
33
+ config.password = ENV['FILEMAKER_PASSWORD']
34
+ config.ssl = { verify: false }
35
+ config.log = :curl
35
36
  end
36
37
 
37
- server.databases.all # Using -dbnames
38
- server.database['candidates'].layouts # Using -layoutnames and -db=candidates
38
+ server.databases.all # Using -dbnames
39
+ server.database['candidates'].layouts.all # Using -layoutnames and -db=candidates
40
+ server.database['candidates'].scripts.all # Using -scriptnames and -db=candidates
39
41
 
40
42
  api = server.db['candidates'].lay['profile']
41
43
  api = server.db['candidates']['profile']
42
44
  api = server.database['candidates'].layout['profile']
43
45
  ```
44
46
 
45
- Once you are able to grab the `api`, you are golden and can make request to read/write to FileMaker API.
47
+ Once you are able to grab the `api`, you are golden and can make requests to read/write to FileMaker API.
46
48
 
47
49
  ## Using the API
48
50
 
@@ -61,25 +63,31 @@ Most API will be smart enough to reject invalid query parameters if passed in in
61
63
 
62
64
  ## Using Filemaker::Model
63
65
 
64
- If you want ActiveModel-like access with a decent query DSL like `where`, `find`, `all`, you can include `Filemaker::Model` to your model. Your Rails form will work as well as JSON serialization.
66
+ If you want ActiveModel-like access with a decent query DSL like `where`, `find`, `in`, you can include `Filemaker::Model` to your model. Your Rails form will work as well as JSON serialization.
65
67
 
66
68
  ```ruby
67
69
  class Job
68
70
  include Filemaker::Model
69
71
 
70
- server :default # Taken from filemaker.yml config file
71
72
  database :jobs
72
73
  layout :job
74
+
75
+ paginates_per 50
73
76
 
74
- string :title, :requirements
75
- datetime :created_at, :published_at
77
+ # Taken from filemaker.yml config file, default to :default
78
+ # Only use registry if you have multiple FileMaker servers you want to connect
79
+ registry :read_slave
80
+
81
+ string :job_id, fm_name: 'JobOrderID', id: true
82
+ string :title, :requirements
83
+ datetime :created_at
84
+ datetime :published_at, fm_name: 'ModifiedDate'
85
+ money :salary
76
86
 
77
87
  validates :title, presence: true
78
88
 
79
- def as_json(options = {})
80
- options[:except] ||= [:created_at]
81
- super(options)
82
- end
89
+ belongs_to :company
90
+ has_many :applicants, class_name: 'JobApplication', reference_key: 'job_id'
83
91
  end
84
92
  ```
85
93
 
@@ -89,11 +97,114 @@ end
89
97
  development:
90
98
  default:
91
99
  host: localhost
100
+ account_name: ENV['FILEMAKER_ACCOUNT_NAME']
101
+ password: ENV['FILEMAKER_PASSWORD']
92
102
  ssl: true
103
+ log: :curl
104
+
105
+ read_slave:
106
+ host: ...
107
+ ssl: { verify: false }
108
+
109
+ production:
110
+ default:
111
+ host: example.com
112
+ ssl: { ca_path: '/secret/path' }
93
113
  ```
94
114
 
95
115
  ## Query DSL
96
116
 
117
+ ### Using -find
118
+
119
+ ```ruby
120
+ Model.where(gender: 'male', age: '< 50') # Default -lop=and
121
+ Model.where(gender: 'male').or(age: '< 50') # -lop=or
122
+ Model.where(gender: 'male').not(age: 40) # age.op=neq
123
+
124
+ # Supply a block to configure additional options like
125
+ # -script, -script.prefind, -lay.response, etc
126
+ Model.where(gender: 'male').or(age: '< 50') do |option|
127
+ option[:script] = ['RemoveDuplicates', 20]
128
+ end
129
+
130
+ Model.where(gender: 'male').or(name: 'Lee').not(age: '=40')
131
+
132
+ # Comparison operator
133
+
134
+ Model.equals(candidate_id: '123') # { candidate_id: '=123' }
135
+ Model.contains(name: 'Chong') # { name: '*Chong*' }
136
+ Model.begins_with(salary: '2000...4000') # ??
137
+ Model.ends_with(name: 'Yong') # { name: '*Yong' }
138
+ Model.gt(age: 20)
139
+ Model.gte(age: 20)
140
+ Model.lt(age: 20)
141
+ Model.lte(age: 20)
142
+ Model.not(name: 'Bob')
143
+ ```
144
+
145
+ ### Using -findquery
146
+
147
+ OR broadens the found set and AND narrows it
148
+
149
+ ```ruby
150
+ # (q0);(q1)
151
+ # (Singapore) OR (Malaysia)
152
+ Model.in(nationality: %w(Singapore Malaysia))
153
+
154
+ # (q0,q1)
155
+ # Essentially the same as:
156
+ # Model.where(nationality: 'Singapore', age: 30)
157
+ Model.in(nationality: 'Singapore', age: 30)
158
+
159
+ # (q0);(q1);(q2);(q3)
160
+ Model.in({ nationality: %w(Singapore Malaysia) }, { age: [20, 30] })
161
+
162
+ # (q0,q2);(q1,q2)
163
+ # (Singapore AND male) OR (Malaysia AND male)
164
+ Model.in(nationality: %w(Singapore Malaysia), gender: 'male')
165
+
166
+ # !(q0);!(q1)
167
+ # NOT(Singapore) OR NOT(Malaysia)
168
+ Model.not_in(nationality: %w(Singapore Malaysia))
169
+
170
+ # !(q0,q1)
171
+ Model.not_in(name: 'Lee', age: '< 40')
172
+
173
+ # !(q0);!(q1)
174
+ # Must be within an array of hashes
175
+ Model.not_in([{ name: 'Lee' }, { age: '< 40' }])
176
+
177
+ # (q0);(q1);!(q2,q3)
178
+ Model.in(nationality: %w(Singapore Malaysia)).not_in(name: 'Lee', age: '< 40')
179
+ ```
180
+
181
+ - [x] Please test the above query with real data to ensure correctness!
182
+ - [x] Please test the comparison operators with keyword as well as applied to value.
183
+ - [x] Test serialization of BigDecimal and other types.
184
+
185
+ ## Pagination
186
+
187
+ If you have [kaminari](https://github.com/amatsuda/kaminari) in your project's `Gemfile`, `Filemaker::Model` will use it to page through the returned collection.
188
+
189
+ ```ruby
190
+ Job.where(title: 'admin').per(50) # default to page(1)
191
+ Job.where(title: 'admin').page(5) # default to per(25)
192
+ Job.where(title: 'admin').page(2).per(35)
193
+
194
+ # In your model, you can customize the per_page
195
+ class Job
196
+ include Filemaker::Model
197
+
198
+ database :jobs
199
+ layout :job
200
+
201
+ paginates_per 50
202
+
203
+ end
204
+
205
+ Job.per_page # => 50
206
+ ```
207
+
97
208
  ## Credits
98
209
 
99
210
  This project is heavily inspired by the following Filemaker Ruby effort and several other ORM gems.
@@ -101,6 +212,7 @@ This project is heavily inspired by the following Filemaker Ruby effort and seve
101
212
  * [Rfm](https://github.com/lardawge/rfm)
102
213
  * [ginjo/rfm](https://github.com/ginjo/rfm)
103
214
  * [mongoid](https://github.com/mongoid/mongoid)
215
+ * [origin](https://github.com/mongoid/origin)
104
216
  * [elasticsearch-ruby](https://github.com/elasticsearch/elasticsearch-ruby)
105
217
 
106
218
  ## Contributing
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_runtime_dependency 'faraday'
22
22
  spec.add_runtime_dependency 'typhoeus'
23
23
  spec.add_runtime_dependency 'nokogiri'
24
+ spec.add_runtime_dependency 'activemodel'
24
25
 
25
26
  spec.add_development_dependency 'bundler', '~> 1.6'
26
27
  spec.add_development_dependency 'rake', '~> 10.0'
@@ -11,3 +11,50 @@ require 'filemaker/record'
11
11
  require 'filemaker/layout'
12
12
  require 'filemaker/script'
13
13
  require 'filemaker/error'
14
+
15
+ require 'active_support'
16
+ require 'active_support/core_ext'
17
+ require 'active_model'
18
+
19
+ require 'filemaker/model/criteria'
20
+ require 'filemaker/model'
21
+
22
+ require 'yaml'
23
+
24
+ module Filemaker
25
+ module_function
26
+
27
+ # Based on the environment, register the server so we only ever have one
28
+ # instance of Filemaker::Server per named session. The named session will be
29
+ # defined at the `filemaker.yml` config file.
30
+ def load!(path, environment = nil)
31
+ sessions = YAML.load(ERB.new(File.new(path).read).result)[environment.to_s]
32
+ fail Error::ConfigurationError, 'Environment wrong?' if sessions.nil?
33
+
34
+ sessions.each_pair do |key, value|
35
+ registry[key] = Filemaker::Server.new do |config|
36
+ config.host = value.fetch('host') do
37
+ fail Error::ConfigurationError, 'Missing config.host'
38
+ end
39
+
40
+ config.account_name = value.fetch('account_name') do
41
+ fail Error::ConfigurationError, 'Missing config.account_name'
42
+ end
43
+
44
+ config.password = value.fetch('password') do
45
+ fail Error::ConfigurationError, 'Missing config.password'
46
+ end
47
+
48
+ config.ssl = value['ssl'] if value['ssl']
49
+ config.log = value['log'] if value['log']
50
+ config.endpoint = value['endpoint'] if value['endpoint']
51
+ end
52
+ end
53
+ end
54
+
55
+ def registry
56
+ @registry ||= {}
57
+ end
58
+ end
59
+
60
+ require 'filemaker/railtie' if defined?(Rails)
@@ -6,18 +6,30 @@ module Filemaker
6
6
  # query(status: 'open', title: 'web') => (q0,q1)
7
7
  # query(status: %w(open closed)) => (q0);(q1)
8
8
  #
9
- def query(array_hash)
9
+ def query(array_hash, options = {})
10
10
  compound_find = CompoundFind.new(array_hash)
11
11
 
12
12
  query_hash = compound_find.key_values.merge(
13
13
  '-query' => compound_find.key_maps_string
14
14
  )
15
15
 
16
- findquery(query_hash)
16
+ findquery(query_hash, options)
17
17
  end
18
18
 
19
19
  # Raw -findquery if you want to construct your own.
20
20
  def findquery(query_hash, options = {})
21
+ valid_options(options,
22
+ :max,
23
+ :skip,
24
+ :sortfield,
25
+ :sortorder,
26
+ :lay_response,
27
+ :script,
28
+ :script_prefind,
29
+ :script_presort,
30
+ :relatedsets_filter,
31
+ :relatedsets_max)
32
+
21
33
  perform_request('-findquery', query_hash, options)
22
34
  end
23
35
 
@@ -39,6 +51,10 @@ module Filemaker
39
51
  translate_key_maps
40
52
  end
41
53
 
54
+ def to_s
55
+ "#{key_values}, #{key_maps_string}"
56
+ end
57
+
42
58
  private
43
59
 
44
60
  def build_key_values(hash)
@@ -65,7 +81,8 @@ module Filemaker
65
81
  len = q_tag_array.length
66
82
  result = q_tag_array.flatten.combination(len).select do |c|
67
83
  q_tag_array.all? { |a| (a & c).size > 0 }
68
- end.each { |c| c.unshift('-omit') if omit }
84
+ end
85
+ result = result.each { |c| c.unshift('-omit') if omit }
69
86
  @key_maps.concat result
70
87
  end
71
88
 
@@ -13,7 +13,7 @@ module Filemaker
13
13
 
14
14
  %w(host account_name password).each do |name|
15
15
  define_method "#{name}_missing?" do
16
- (send(name.to_sym) || '').empty?
16
+ (public_send(name.to_sym) || '').empty?
17
17
  end
18
18
  end
19
19
 
@@ -1,18 +1,3 @@
1
- class Hash
2
- def transform_keys
3
- return enum_for(:transform_keys) unless block_given?
4
- result = self.class.new
5
- each_key do |key|
6
- result[yield(key)] = self[key]
7
- end
8
- result
9
- end
10
-
11
- def stringify_keys
12
- transform_keys { |key| key.to_s }
13
- end
14
- end
15
-
16
1
  module Filemaker
17
2
  class HashWithIndifferentAndCaseInsensitiveAccess < Hash
18
3
  def []=(key, value)
@@ -23,6 +8,25 @@ module Filemaker
23
8
  super(convert_key(key))
24
9
  end
25
10
 
11
+ def key?(key)
12
+ super(convert_key(key))
13
+ end
14
+
15
+ alias_method :include?, :key?
16
+ alias_method :member?, :key?
17
+
18
+ def fetch(key, *extras)
19
+ super(convert_key(key), *extras)
20
+ end
21
+
22
+ def values_at(*indices)
23
+ indices.map { |key| self[convert_key(key)] }
24
+ end
25
+
26
+ def delete(key)
27
+ super(convert_key(key))
28
+ end
29
+
26
30
  protected
27
31
 
28
32
  def convert_key(key)
@@ -4,6 +4,7 @@ module Filemaker
4
4
  class AuthenticationError < StandardError; end
5
5
  class ParameterError < StandardError; end
6
6
  class CoerceError < StandardError; end
7
+ class ConfigurationError < StandardError; end
7
8
 
8
9
  class FilemakerError < StandardError
9
10
  attr_reader :code
@@ -35,6 +36,7 @@ module Filemaker
35
36
  class ScriptMissingError < MissingError; end
36
37
  class LayoutMissingError < MissingError; end
37
38
  class TableMissingError < MissingError; end
39
+ class InvalidFieldError < StandardError; end
38
40
 
39
41
  class SecurityError < FilemakerError; end
40
42
  class RecordAccessDeniedError < SecurityError; end
@@ -68,6 +70,9 @@ module Filemaker
68
70
  class UnableToCreateTempFileError < FileError; end
69
71
  class UnableToOpenFileError < FileError; end
70
72
 
73
+ class QueryError < StandardError; end
74
+ class MixedClauseError < QueryError; end
75
+
71
76
  def self.raise_error_by_code(code)
72
77
  msg = error_message_by_code(code)
73
78
  error_class = find_error_class_by_code(code)
@@ -43,8 +43,23 @@ module Filemaker
43
43
  when 'date'
44
44
  # date_format likely will be '%m/%d/%Y', but if we got '19/8/2014',
45
45
  # then `strptime` will raise invalid date error
46
- Date.strptime(value, @resultset.date_format)
47
- # Date.strptime(Date.parse(value).strftime(@resultset.date_format), @resultset.date_format)
46
+ # Sometimes we can get '27/11 /1981' also :(
47
+ begin
48
+ Date.strptime(value, @resultset.date_format)
49
+ rescue
50
+ # We could be getting back these date:
51
+ # '17.12.95', '19/05/99', '27/11 /1981'
52
+ # '1959-07-03' will be beyong us, so consider returning nil
53
+ value = value.gsub(/-|\./, '/')
54
+ split = value.split('/').map(&:strip)
55
+ split[2] = "19#{split[2]}" if split[2].size == 2
56
+ value = split.join('/')
57
+
58
+ Date.strptime(
59
+ Date.parse(value)
60
+ .strftime(@resultset.date_format), @resultset.date_format
61
+ )
62
+ end
48
63
  when 'time'
49
64
  DateTime.strptime("1/1/-4712 #{value}", @resultset.timestamp_format)
50
65
  when 'timestamp'
@@ -54,9 +69,10 @@ module Filemaker
54
69
  else
55
70
  value
56
71
  end
57
- rescue Exception => e
58
- msg = "Could not coerce #{value} due to #{e.message}"
59
- raise Filemaker::Error::CoerceError, msg
72
+ rescue
73
+ warn "Could not coerce #{value}. Return nil instead."
74
+ nil
75
+ # raise Filemaker::Error::CoerceError, msg
60
76
  end
61
77
 
62
78
  private
@@ -0,0 +1,132 @@
1
+ require 'filemaker/model/components'
2
+
3
+ module Filemaker
4
+ module Model
5
+ extend ActiveSupport::Concern
6
+ include Components
7
+
8
+ # @return [Boolean] indicates if this is a new fresh record
9
+ attr_reader :attributes, :new_record, :record_id, :mod_id
10
+
11
+ included do
12
+ class_attribute :db, :lay, :registry_name, :server, :api, :per_page
13
+ self.per_page = Kaminari.config.default_per_page if defined?(Kaminari)
14
+ end
15
+
16
+ def initialize(attrs = nil)
17
+ @new_record = true
18
+ @attributes = {}
19
+ @relations = {}
20
+ apply_defaults
21
+ process_attributes(attrs)
22
+ end
23
+
24
+ def new_record?
25
+ new_record
26
+ end
27
+
28
+ def persisted?
29
+ !new_record?
30
+ end
31
+
32
+ def to_a
33
+ [self]
34
+ end
35
+
36
+ def id
37
+ self.class.identity ? identity_id : record_id
38
+ end
39
+
40
+ def identity_id
41
+ public_send(identity.name) if identity
42
+ end
43
+
44
+ def to_param
45
+ id.to_s if id
46
+ end
47
+
48
+ def fm_attributes
49
+ self.class.with_model_fields(attributes)
50
+ end
51
+
52
+ private
53
+
54
+ def process_attributes(attrs)
55
+ attrs ||= {}
56
+ return if attrs.empty?
57
+
58
+ attrs.each_pair do |key, value|
59
+ public_send("#{key}=", value) if respond_to?("#{key}=")
60
+ end
61
+ end
62
+
63
+ module ClassMethods
64
+ def database(db)
65
+ self.db = db
66
+ self.registry_name ||= 'default' unless lay.blank?
67
+ register
68
+ end
69
+
70
+ def layout(lay)
71
+ self.lay = lay
72
+ self.registry_name ||= 'default' unless db.blank?
73
+ register
74
+ end
75
+
76
+ def registry(name)
77
+ self.registry_name = (name || 'default').to_s
78
+ register
79
+ end
80
+
81
+ def register
82
+ self.server = Filemaker.registry[registry_name]
83
+ self.api = server.db[db][lay] if server && db && lay
84
+ end
85
+
86
+ # A chance for the model to set it's per_page.
87
+ def paginates_per(value)
88
+ self.per_page = value.to_i
89
+ end
90
+
91
+ # Make use of -view to return an array of [name, data_type] for this
92
+ # model from FileMaker.
93
+ #
94
+ # @return [Array] array of [name, data_type]
95
+ def fm_fields
96
+ api.view.fields.values.map { |field| [field.name, field.data_type] }
97
+ end
98
+
99
+ # Filter out any fields that do not match model's fields.
100
+ #
101
+ # A testing story to tell: when working on `in` query, we have value that
102
+ # is an array. Without the test and expectation setup, debugging the
103
+ # output will take far longer to realise. This reinforce the belief that
104
+ # TDD is in fact a valuable thing to do.
105
+ def with_model_fields(criterion, coerce = true)
106
+ accepted_fields = {}
107
+
108
+ criterion.each_pair do |key, value|
109
+ field = find_field_by_name(key)
110
+
111
+ next unless field
112
+
113
+ # We do not serialize at this point, as we are still in Ruby-land.
114
+ # Filemaker::Server will help us serialize into FileMaker format.
115
+ if value.is_a? Array
116
+ temp = []
117
+ value.each do |v|
118
+ temp << (coerce ? field.coerce(v) : v)
119
+ end
120
+
121
+ accepted_fields[field.fm_name] = temp
122
+ else
123
+ accepted_fields[field.fm_name] = \
124
+ coerce ? field.coerce(value) : value
125
+ end
126
+ end
127
+
128
+ accepted_fields
129
+ end
130
+ end
131
+ end
132
+ end