filemaker 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/README.md +6 -4
- data/filemaker.gemspec +3 -3
- data/lib/filemaker/model.rb +61 -19
- data/lib/filemaker/model/batches.rb +4 -2
- data/lib/filemaker/model/builder.rb +9 -0
- data/lib/filemaker/model/field.rb +26 -14
- data/lib/filemaker/model/fields.rb +25 -0
- data/lib/filemaker/model/findable.rb +1 -0
- data/lib/filemaker/model/persistable.rb +12 -4
- data/lib/filemaker/model/relations.rb +5 -4
- data/lib/filemaker/model/relations/belongs_to.rb +8 -6
- data/lib/filemaker/model/relations/has_many.rb +8 -5
- data/lib/filemaker/model/relations/proxy.rb +8 -1
- data/lib/filemaker/model/selectable.rb +7 -9
- data/lib/filemaker/model/type.rb +3 -1
- data/lib/filemaker/model/types/big_decimal.rb +6 -0
- data/lib/filemaker/model/types/date.rb +6 -0
- data/lib/filemaker/model/types/date_time.rb +28 -0
- data/lib/filemaker/model/types/integer.rb +6 -0
- data/lib/filemaker/model/types/text.rb +6 -0
- data/lib/filemaker/model/types/time.rb +12 -5
- data/lib/filemaker/record.rb +7 -6
- data/lib/filemaker/server.rb +2 -3
- data/lib/filemaker/version.rb +1 -1
- data/spec/filemaker/model/builder_spec.rb +7 -0
- data/spec/filemaker/model/criteria_spec.rb +7 -1
- data/spec/filemaker/model/relations_spec.rb +10 -8
- data/spec/filemaker/model/types_spec.rb +21 -2
- data/spec/filemaker/model_spec.rb +14 -9
- data/spec/support/models.rb +3 -0
- data/spec/support/responses/jobs.xml +27 -1
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 760eb94b95fc1aacf25f18cf284780211c18c9fda1beaf4a53a6be49e3fd0aae
|
4
|
+
data.tar.gz: f1525fe3dbfb0697b72fd5d031c64fc93d5d9b0ee50d5d755336ef909344703b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b56eaf97df56cbf2d1ff8b5359128a2251046a55834da211fc163c274b4e294cf713e44f0fd2470cf7306b1b9be05b15d5ceac5df77b201e9ac4c6068d925104
|
7
|
+
data.tar.gz: e0430af65e889355a80085cb8972e79daf665dd8735541e270936e563f27d9c51abd3022df191564305f32ed9b148b7e0d3ea665eeb082e91ed10f70329d5ad4
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Filemaker
|
2
2
|
|
3
3
|
[](https://travis-ci.org/mech/filemaker-ruby)
|
4
|
+
[](https://hakiri.io/github/mech/filemaker-ruby/master)
|
4
5
|
|
5
6
|
A Ruby wrapper to FileMaker XML API.
|
6
7
|
|
@@ -220,23 +221,24 @@ Model.not(name: 'Bob')
|
|
220
221
|
```ruby
|
221
222
|
# (q0);(q1)
|
222
223
|
# (Singapore) OR (Malaysia)
|
223
|
-
Model.in(nationality: %w
|
224
|
+
Model.in(nationality: %w[Singapore Malaysia])
|
224
225
|
|
225
226
|
# (q0,q1)
|
227
|
+
# (nationality AND age)
|
226
228
|
# Essentially the same as:
|
227
229
|
# Model.where(nationality: 'Singapore', age: 30)
|
228
230
|
Model.in(nationality: 'Singapore', age: 30)
|
229
231
|
|
230
232
|
# (q0);(q1);(q2);(q3)
|
231
|
-
Model.in({ nationality: %w
|
233
|
+
Model.in({ nationality: %w[Singapore Malaysia] }, { age: [20, 30] })
|
232
234
|
|
233
235
|
# (q0,q2);(q1,q2)
|
234
236
|
# (Singapore AND male) OR (Malaysia AND male)
|
235
|
-
Model.in(nationality: %w
|
237
|
+
Model.in(nationality: %w[Singapore Malaysia], gender: 'male')
|
236
238
|
|
237
239
|
# !(q0);!(q1)
|
238
240
|
# NOT(Singapore) OR NOT(Malaysia)
|
239
|
-
Model.not_in(nationality: %w
|
241
|
+
Model.not_in(nationality: %w[Singapore Malaysia])
|
240
242
|
|
241
243
|
# !(q0,q1)
|
242
244
|
Model.not_in(name: 'Lee', age: '< 40')
|
data/filemaker.gemspec
CHANGED
@@ -19,12 +19,12 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'typhoeus'
|
22
|
-
spec.add_runtime_dependency 'nokogiri', '~> 1.
|
22
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.10.4'
|
23
23
|
spec.add_runtime_dependency 'activemodel'
|
24
24
|
spec.add_runtime_dependency 'globalid'
|
25
25
|
|
26
|
-
spec.add_development_dependency 'bundler'
|
27
|
-
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'bundler'
|
27
|
+
spec.add_development_dependency 'rake'
|
28
28
|
spec.add_development_dependency 'rspec', '~> 3.7'
|
29
29
|
spec.add_development_dependency 'rubocop'
|
30
30
|
spec.add_development_dependency 'pry-byebug'
|
data/lib/filemaker/model.rb
CHANGED
@@ -41,8 +41,8 @@ module Filemaker
|
|
41
41
|
|
42
42
|
def cache_key
|
43
43
|
return "#{model_key}/new" if new_record?
|
44
|
-
return "#{model_key}/#{id}-#{updated_at.to_datetime.utc.to_s(:number)}"
|
45
|
-
|
44
|
+
return "#{model_key}/#{id}-#{updated_at.to_datetime.utc.to_s(:number)}" if respond_to?(:updated_at) && send(:updated_at)
|
45
|
+
|
46
46
|
"#{model_key}/#{id}"
|
47
47
|
end
|
48
48
|
|
@@ -59,7 +59,11 @@ module Filemaker
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def fm_attributes
|
62
|
-
self.class.
|
62
|
+
self.class.with_model_fields_for_query(attributes)
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_attributes
|
66
|
+
self.class.with_model_fields_for_creation(attributes)
|
63
67
|
end
|
64
68
|
|
65
69
|
def dirty_attributes
|
@@ -69,7 +73,7 @@ module Filemaker
|
|
69
73
|
end
|
70
74
|
|
71
75
|
# We need to use serialize_for_update instead
|
72
|
-
self.class.
|
76
|
+
self.class.with_model_fields_for_update(dirty)
|
73
77
|
end
|
74
78
|
|
75
79
|
private
|
@@ -129,7 +133,7 @@ module Filemaker
|
|
129
133
|
# is an array. Without the test and expectation setup, debugging the
|
130
134
|
# output will take far longer to realise. This reinforce the belief that
|
131
135
|
# TDD is in fact a valuable thing to do.
|
132
|
-
def
|
136
|
+
def with_model_fields_for_query(criterion)
|
133
137
|
accepted_fields = {}
|
134
138
|
|
135
139
|
criterion.each_pair do |key, value|
|
@@ -141,23 +145,61 @@ module Filemaker
|
|
141
145
|
|
142
146
|
# We do not serialize at this point, as we are still in Ruby-land.
|
143
147
|
# Filemaker::Server will help us serialize into FileMaker format.
|
144
|
-
if value.is_a?
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
if value.is_a?(Array)
|
149
|
+
accepted_fields[field.fm_name] = value.map { |v| field.serialize_for_query(v) }
|
150
|
+
else
|
151
|
+
accepted_fields[field.fm_name] = field.serialize_for_query(value)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
accepted_fields
|
156
|
+
end
|
157
|
+
|
158
|
+
def with_model_fields_for_creation(criterion)
|
159
|
+
accepted_fields = {}
|
160
|
+
|
161
|
+
criterion.each_pair do |key, value|
|
162
|
+
field = find_field_by_name(key)
|
163
|
+
|
164
|
+
# Do not process nil value
|
165
|
+
next unless field && value
|
166
|
+
|
167
|
+
# We do not serialize at this point, as we are still in Ruby-land.
|
168
|
+
# Filemaker::Server will help us serialize into FileMaker format.
|
169
|
+
if value.is_a?(Array)
|
170
|
+
field.max_repeat.times do |idx|
|
171
|
+
index = idx + 1
|
172
|
+
repeated_fm_name = "#{field.fm_name}(#{index})"
|
173
|
+
accepted_fields[repeated_fm_name] = field.serialize_for_update(value[idx])
|
152
174
|
end
|
175
|
+
else
|
176
|
+
accepted_fields[field.fm_name] = field.serialize_for_update(value)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
accepted_fields
|
181
|
+
end
|
182
|
+
|
183
|
+
def with_model_fields_for_update(criterion)
|
184
|
+
accepted_fields = {}
|
153
185
|
|
154
|
-
|
186
|
+
criterion.each_pair do |key, value|
|
187
|
+
field = find_field_by_name(key)
|
188
|
+
|
189
|
+
next unless field
|
190
|
+
|
191
|
+
# Able to process nil value only for update
|
192
|
+
|
193
|
+
# We do not serialize at this point, as we are still in Ruby-land.
|
194
|
+
# Filemaker::Server will help us serialize into FileMaker format.
|
195
|
+
if value.is_a?(Array)
|
196
|
+
field.max_repeat.times do |idx|
|
197
|
+
index = idx + 1
|
198
|
+
repeated_fm_name = "#{field.fm_name}(#{index})"
|
199
|
+
accepted_fields[repeated_fm_name] = field.serialize_for_update(value[idx])
|
200
|
+
end
|
155
201
|
else
|
156
|
-
accepted_fields[field.fm_name] =
|
157
|
-
field.serialize_for_query(value)
|
158
|
-
else
|
159
|
-
field.serialize_for_update(value)
|
160
|
-
end
|
202
|
+
accepted_fields[field.fm_name] = field.serialize_for_update(value)
|
161
203
|
end
|
162
204
|
end
|
163
205
|
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module Filemaker
|
2
2
|
module Model
|
3
3
|
module Batches
|
4
|
-
def in_batches(batch_size: 200, options: {})
|
4
|
+
def in_batches(batch_size: 200, options: {}, sleep: 0)
|
5
5
|
output = []
|
6
6
|
total = self.in(options).count
|
7
7
|
pages = (total / batch_size.to_f).ceil
|
8
8
|
1.upto(pages) do |page|
|
9
|
+
sleep(sleep)
|
9
10
|
output.concat self.in(options).per(batch_size).page(page)
|
10
11
|
end
|
11
12
|
|
12
13
|
output
|
13
14
|
end
|
14
15
|
|
15
|
-
def where_batches(batch_size: 200, options: {})
|
16
|
+
def where_batches(batch_size: 200, options: {}, sleep: 0)
|
16
17
|
output = []
|
17
18
|
total = where(options).count
|
18
19
|
pages = (total / batch_size.to_f).ceil
|
19
20
|
1.upto(pages) do |page|
|
21
|
+
sleep(sleep)
|
20
22
|
output.concat where(options).per(batch_size).page(page)
|
21
23
|
end
|
22
24
|
|
@@ -33,6 +33,15 @@ module Filemaker
|
|
33
33
|
value = field.cast(record[fm_field_name])
|
34
34
|
object.public_send(setter, value)
|
35
35
|
|
36
|
+
if record[fm_field_name].is_a?(Array) && field.max_repeat > 1
|
37
|
+
field.max_repeat.times do |idx|
|
38
|
+
index = idx + 1
|
39
|
+
repeated_setter = "#{field.name}__#{index}="
|
40
|
+
repeated_value = field.cast(record[fm_field_name][idx])
|
41
|
+
object.public_send(repeated_setter, repeated_value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
36
45
|
# So after hydrating, we do not say it was dirty
|
37
46
|
object.clear_changes_information
|
38
47
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Filemaker
|
2
2
|
module Model
|
3
3
|
class Field
|
4
|
-
attr_reader :name, :type, :default_value, :fm_name
|
4
|
+
attr_reader :name, :type, :default_value, :fm_name, :max_repeat
|
5
5
|
|
6
6
|
def initialize(name, type, options = {})
|
7
7
|
@name = name
|
8
8
|
@type = type
|
9
|
+
@max_repeat = options.fetch(:max_repeat) { 1 }
|
9
10
|
@default_value = serialize_for_update(options.fetch(:default) { nil })
|
10
11
|
|
11
12
|
# We need to downcase because Filemaker::Record is
|
@@ -16,7 +17,9 @@ module Filemaker
|
|
16
17
|
# Will delegate to the underlying @type for casting
|
17
18
|
# From raw input to Ruby type
|
18
19
|
def cast(value)
|
19
|
-
return value if
|
20
|
+
return value if value.nil?
|
21
|
+
return value if value.is_a?(Array) && @max_repeat > 1
|
22
|
+
|
20
23
|
@type.__filemaker_cast_to_ruby_object(value)
|
21
24
|
rescue StandardError => e
|
22
25
|
warn "[#{e.message}] Could not cast: #{name}=#{value}"
|
@@ -26,8 +29,22 @@ module Filemaker
|
|
26
29
|
# Convert to Ruby type situable for making FileMaker update
|
27
30
|
# For attr_writer
|
28
31
|
def serialize_for_update(value)
|
29
|
-
return value if
|
30
|
-
|
32
|
+
return value if value.nil?
|
33
|
+
|
34
|
+
if value.is_a?(Array) && @max_repeat > 1
|
35
|
+
value.map { |v| @type.__filemaker_serialize_for_update(v) }
|
36
|
+
|
37
|
+
# @max_repeat.times do |idx|
|
38
|
+
# index = idx + 1
|
39
|
+
# repeated_field_name = "@#{@name}__#{index}"
|
40
|
+
# repeated_field_value = @type.__filemaker_serialize_for_update(value[idx])
|
41
|
+
# instance_eval do
|
42
|
+
# instance_variable_set(repeated_field_name, repeated_field_value)
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
else
|
46
|
+
@type.__filemaker_serialize_for_update(value)
|
47
|
+
end
|
31
48
|
rescue StandardError => e
|
32
49
|
warn "[#{e.message}] Could not serialize for update: #{name}=#{value}"
|
33
50
|
value
|
@@ -35,21 +52,16 @@ module Filemaker
|
|
35
52
|
|
36
53
|
# Convert to Ruby type situable for making FileMaker query
|
37
54
|
def serialize_for_query(value)
|
38
|
-
return value if
|
55
|
+
return value if value.nil?
|
56
|
+
return value if value =~ /^==|=\*/
|
57
|
+
return value if value =~ /(\.\.\.)/
|
58
|
+
return value if value =~ /\A(<|<=|>|>=)/
|
59
|
+
|
39
60
|
@type.__filemaker_serialize_for_query(value)
|
40
61
|
rescue StandardError => e
|
41
62
|
warn "[#{e.message}] Could not serialize for query: #{name}=#{value}"
|
42
63
|
value
|
43
64
|
end
|
44
|
-
|
45
|
-
# Doc why we skip it!
|
46
|
-
# TODO - we may need to customize it for query and update. For example
|
47
|
-
# query will bypass `==`, but update do not need to care.
|
48
|
-
def skip_modifying_value(value)
|
49
|
-
return true if value.nil?
|
50
|
-
return true if value =~ /^==|=\*/
|
51
|
-
return true if value =~ /(\.\.\.)/
|
52
|
-
end
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
@@ -64,6 +64,24 @@ module Filemaker
|
|
64
64
|
field_names.each do |name|
|
65
65
|
add_field(name, Filemaker::Model::Type.registry[type], options)
|
66
66
|
create_accessors(name)
|
67
|
+
|
68
|
+
next unless options[:max_repeat] && options[:max_repeat] > 1
|
69
|
+
|
70
|
+
# We have repeating fields
|
71
|
+
# It will create [max_repeat] number of attribute with names like:
|
72
|
+
# xxx__1, xxx__2, xxx__3
|
73
|
+
# Their fm_name will be xxx(1), xxx(2), xxx(3)
|
74
|
+
options[:max_repeat].times do |idx|
|
75
|
+
index = idx + 1
|
76
|
+
repeated_field_name = "#{name}__#{index}"
|
77
|
+
fm_name = (options.fetch(:fm_name) { name }).to_s.downcase.freeze
|
78
|
+
add_field(
|
79
|
+
repeated_field_name,
|
80
|
+
Filemaker::Model::Type.registry[type],
|
81
|
+
options.merge(fm_name: "#{fm_name}(#{index})")
|
82
|
+
)
|
83
|
+
create_accessors(repeated_field_name)
|
84
|
+
end
|
67
85
|
end
|
68
86
|
end
|
69
87
|
end
|
@@ -105,10 +123,17 @@ module Filemaker
|
|
105
123
|
|
106
124
|
# Find FileMaker's real name given either the attribute name or the real
|
107
125
|
# FileMaker name.
|
126
|
+
# FIXME - This may have ordering problem. If fm_name is the same as the
|
127
|
+
# field name.
|
108
128
|
def find_field_by_name(name)
|
109
129
|
name = name.to_s
|
110
130
|
fields.values.find do |f|
|
111
131
|
f.name == name || f.fm_name == name
|
132
|
+
|
133
|
+
# Unfortunately can't use this as builder.rb need to find field based
|
134
|
+
# on fm_name
|
135
|
+
# Always find by attribute name for now
|
136
|
+
# f.name == name
|
112
137
|
end
|
113
138
|
end
|
114
139
|
end
|
@@ -10,9 +10,9 @@ module Filemaker
|
|
10
10
|
# Call save! but do not raise error.
|
11
11
|
def save
|
12
12
|
save!
|
13
|
-
rescue StandardError
|
14
|
-
errors.add(:base) <<
|
15
|
-
|
13
|
+
rescue StandardError => e
|
14
|
+
errors.add(:base) << e.message # Does this works?
|
15
|
+
false
|
16
16
|
end
|
17
17
|
|
18
18
|
def save!
|
@@ -27,7 +27,7 @@ module Filemaker
|
|
27
27
|
run_callbacks :create do
|
28
28
|
options = {}
|
29
29
|
yield options if block_given?
|
30
|
-
resultset = api.new(
|
30
|
+
resultset = api.new(create_attributes, options)
|
31
31
|
changes_applied
|
32
32
|
replace_new_data(resultset)
|
33
33
|
end
|
@@ -51,10 +51,18 @@ module Filemaker
|
|
51
51
|
|
52
52
|
def update_attributes(attrs = {})
|
53
53
|
return self if attrs.blank?
|
54
|
+
|
54
55
|
assign_attributes(attrs)
|
55
56
|
save
|
56
57
|
end
|
57
58
|
|
59
|
+
def update_attributes!(attrs = {})
|
60
|
+
return self if attrs.blank?
|
61
|
+
|
62
|
+
assign_attributes(attrs)
|
63
|
+
save!
|
64
|
+
end
|
65
|
+
|
58
66
|
# Use -delete to remove the record backed by the model.
|
59
67
|
# @return [Filemaker::Model] frozen instance
|
60
68
|
def destroy
|
@@ -45,9 +45,9 @@ module Filemaker
|
|
45
45
|
# job.company(true)
|
46
46
|
define_method(name) do |force_reload = false|
|
47
47
|
if force_reload
|
48
|
-
@relations[name] = type.
|
48
|
+
@relations[name] = type.init(self, name, options)
|
49
49
|
else
|
50
|
-
@relations[name] ||= type.
|
50
|
+
@relations[name] ||= type.init(self, name, options)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -58,8 +58,9 @@ module Filemaker
|
|
58
58
|
# save and return the identity ID, then we update the parent's
|
59
59
|
# reference_key.
|
60
60
|
define_method("#{name}=") do |object|
|
61
|
-
|
62
|
-
|
61
|
+
return nil if object.nil?
|
62
|
+
|
63
|
+
@relations[name] = object
|
63
64
|
end
|
64
65
|
|
65
66
|
# Creator
|
@@ -22,7 +22,7 @@ module Filemaker
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# Order: source_key first, reference_key next, then identity
|
25
|
-
# all must be findable using `
|
25
|
+
# all must be findable using `find_field_by_name`
|
26
26
|
def final_reference_key
|
27
27
|
target_class.find_field_by_name(source_key).try(:name) ||
|
28
28
|
target_class.find_field_by_name(reference_key).try(:name) ||
|
@@ -36,11 +36,13 @@ module Filemaker
|
|
36
36
|
# If the field value contains underscore or space like 'FM_notified'
|
37
37
|
# or 'FM notified', a single `=` may not match correctly.
|
38
38
|
def build_target
|
39
|
-
@target =
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
@target = if reference_value.blank? || final_reference_key.blank?
|
40
|
+
nil
|
41
|
+
else
|
42
|
+
target_class.where(
|
43
|
+
final_reference_key => "==#{reference_value}"
|
44
|
+
).first
|
45
|
+
end
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -42,6 +42,7 @@ module Filemaker
|
|
42
42
|
def <<(*args)
|
43
43
|
docs = args.flatten
|
44
44
|
return concat(docs) if docs.size > 1
|
45
|
+
|
45
46
|
if (doc = docs.first)
|
46
47
|
create(doc)
|
47
48
|
end
|
@@ -81,11 +82,13 @@ module Filemaker
|
|
81
82
|
protected
|
82
83
|
|
83
84
|
def build_target
|
84
|
-
@target =
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
@target = if reference_value.blank? || final_reference_key.blank?
|
86
|
+
[]
|
87
|
+
else
|
88
|
+
target_class.where(
|
89
|
+
final_reference_key => "==#{reference_value}"
|
90
|
+
)
|
91
|
+
end
|
89
92
|
end
|
90
93
|
end
|
91
94
|
end
|
@@ -6,7 +6,7 @@ module Filemaker
|
|
6
6
|
class Proxy
|
7
7
|
instance_methods.each do |method|
|
8
8
|
undef_method(method) unless
|
9
|
-
method =~
|
9
|
+
method =~ /^(__.*|send|object_id|equal\?|respond_to\?|tap|public_send)$/
|
10
10
|
end
|
11
11
|
|
12
12
|
attr_accessor :owner, :target, :options
|
@@ -21,8 +21,15 @@ module Filemaker
|
|
21
21
|
@class_name = options.fetch(:class_name) { name.to_s.classify }
|
22
22
|
end
|
23
23
|
|
24
|
+
# Create will not return the proxy if target was NilClass
|
25
|
+
def self.init(owner, name, options)
|
26
|
+
new_instance = new(owner, name, options)
|
27
|
+
new_instance.target.nil? ? nil : new_instance
|
28
|
+
end
|
29
|
+
|
24
30
|
def target_class
|
25
31
|
return @class_name if @class_name.is_a?(Class)
|
32
|
+
|
26
33
|
@class_name.constantize
|
27
34
|
end
|
28
35
|
|
@@ -16,7 +16,7 @@ module Filemaker
|
|
16
16
|
chains.delete(:in)
|
17
17
|
|
18
18
|
@selector ||= {}
|
19
|
-
selector.merge!(klass.
|
19
|
+
selector.merge!(klass.with_model_fields_for_query(criterion))
|
20
20
|
yield options if block_given?
|
21
21
|
self
|
22
22
|
end
|
@@ -39,7 +39,8 @@ module Filemaker
|
|
39
39
|
return where(criterion) if criterion.is_a? Hash
|
40
40
|
|
41
41
|
# Find using model ID (may not be the -recid)
|
42
|
-
|
42
|
+
# Always append double '=' for ID instead of just one '='
|
43
|
+
id = criterion.to_s.gsub(/\A=*/, '==')
|
43
44
|
|
44
45
|
# If we are finding with ID, we just limit to one and return
|
45
46
|
# immediately. Last resort is to use the recid to find.
|
@@ -68,11 +69,7 @@ module Filemaker
|
|
68
69
|
chains.delete(:in)
|
69
70
|
@selector ||= {}
|
70
71
|
|
71
|
-
criterion =
|
72
|
-
klass.with_model_fields(criterion, use_query: false)
|
73
|
-
else
|
74
|
-
klass.with_model_fields(criterion)
|
75
|
-
end
|
72
|
+
criterion = klass.with_model_fields_for_query(criterion)
|
76
73
|
|
77
74
|
criterion.each_key do |key|
|
78
75
|
selector["#{key}.op"] = operator
|
@@ -87,6 +84,7 @@ module Filemaker
|
|
87
84
|
end
|
88
85
|
end
|
89
86
|
|
87
|
+
alias id find
|
90
88
|
alias equals eq
|
91
89
|
alias contains cn
|
92
90
|
alias begins_with bw
|
@@ -115,7 +113,7 @@ module Filemaker
|
|
115
113
|
@selector ||= []
|
116
114
|
|
117
115
|
become_array(criterion).each do |hash|
|
118
|
-
accepted_hash = klass.
|
116
|
+
accepted_hash = klass.with_model_fields_for_query(hash)
|
119
117
|
accepted_hash['-omit'] = true if negating
|
120
118
|
@selector << accepted_hash
|
121
119
|
end
|
@@ -153,7 +151,7 @@ module Filemaker
|
|
153
151
|
end
|
154
152
|
|
155
153
|
@selector ||= {}
|
156
|
-
selector.merge!(klass.
|
154
|
+
selector.merge!(klass.with_model_fields_for_query(criterion))
|
157
155
|
options[:lop] = 'or'
|
158
156
|
yield options if block_given?
|
159
157
|
self
|
data/lib/filemaker/model/type.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'filemaker/model/types/text'
|
2
2
|
require 'filemaker/model/types/date'
|
3
|
+
require 'filemaker/model/types/date_time'
|
3
4
|
require 'filemaker/model/types/time'
|
4
5
|
require 'filemaker/model/types/big_decimal'
|
5
6
|
require 'filemaker/model/types/integer'
|
@@ -21,7 +22,8 @@ module Filemaker
|
|
21
22
|
register(:string, Filemaker::Model::Types::Text)
|
22
23
|
register(:text, Filemaker::Model::Types::Text)
|
23
24
|
register(:date, Filemaker::Model::Types::Date)
|
24
|
-
register(:datetime, Filemaker::Model::Types::
|
25
|
+
register(:datetime, Filemaker::Model::Types::DateTime)
|
26
|
+
register(:time, Filemaker::Model::Types::Time)
|
25
27
|
register(:money, Filemaker::Model::Types::BigDecimal)
|
26
28
|
register(:number, Filemaker::Model::Types::BigDecimal)
|
27
29
|
register(:integer, Filemaker::Model::Types::Integer)
|
@@ -3,17 +3,23 @@ module Filemaker
|
|
3
3
|
module Types
|
4
4
|
class BigDecimal
|
5
5
|
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
+
return nil if value.nil?
|
6
7
|
return value if value.is_a?(::BigDecimal)
|
8
|
+
|
7
9
|
BigDecimal(value.to_s)
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.__filemaker_serialize_for_update(value)
|
13
|
+
return nil if value.nil?
|
11
14
|
return value if value.is_a?(::BigDecimal)
|
15
|
+
|
12
16
|
BigDecimal(value.to_s)
|
13
17
|
end
|
14
18
|
|
15
19
|
def self.__filemaker_serialize_for_query(value)
|
20
|
+
return nil if value.nil?
|
16
21
|
return value if value.is_a?(::BigDecimal)
|
22
|
+
|
17
23
|
BigDecimal(value.to_s)
|
18
24
|
end
|
19
25
|
end
|
@@ -3,19 +3,25 @@ module Filemaker
|
|
3
3
|
module Types
|
4
4
|
class Date
|
5
5
|
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
+
return nil if value.nil?
|
6
7
|
return value if value.is_a?(::Date)
|
8
|
+
|
7
9
|
::Date.parse(value.to_s)
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.__filemaker_serialize_for_update(value)
|
13
|
+
return nil if value.nil?
|
11
14
|
return value if value.is_a?(::Date)
|
15
|
+
|
12
16
|
::Date.parse(value.to_s)
|
13
17
|
end
|
14
18
|
|
15
19
|
def self.__filemaker_serialize_for_query(value)
|
16
20
|
# If we are doing date range query like
|
17
21
|
# Model.where(date: '12/2018')
|
22
|
+
return nil if value.nil?
|
18
23
|
return value if value.is_a?(::Date) || value.is_a?(String)
|
24
|
+
|
19
25
|
::Date.parse(value.to_s)
|
20
26
|
end
|
21
27
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Filemaker
|
2
|
+
module Model
|
3
|
+
module Types
|
4
|
+
class DateTime
|
5
|
+
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
+
return nil if value.nil?
|
7
|
+
return value if value.is_a?(::Time)
|
8
|
+
|
9
|
+
::Time.parse(value.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.__filemaker_serialize_for_update(value)
|
13
|
+
return nil if value.nil?
|
14
|
+
return value if value.is_a?(::Time)
|
15
|
+
|
16
|
+
::Time.parse(value.to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.__filemaker_serialize_for_query(value)
|
20
|
+
return nil if value.nil?
|
21
|
+
return value if value.is_a?(::Time) || value.is_a?(String)
|
22
|
+
|
23
|
+
::Time.parse(value.to_s)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -3,17 +3,23 @@ module Filemaker
|
|
3
3
|
module Types
|
4
4
|
class Integer
|
5
5
|
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
+
return nil if value.nil?
|
6
7
|
return value if value.is_a?(::Integer)
|
8
|
+
|
7
9
|
value.to_i
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.__filemaker_serialize_for_update(value)
|
13
|
+
return nil if value.nil?
|
11
14
|
return value if value.is_a?(::Integer)
|
15
|
+
|
12
16
|
value.to_i
|
13
17
|
end
|
14
18
|
|
15
19
|
def self.__filemaker_serialize_for_query(value)
|
20
|
+
return nil if value.nil?
|
16
21
|
return value if value.is_a?(::Integer)
|
22
|
+
|
17
23
|
value.to_i
|
18
24
|
end
|
19
25
|
end
|
@@ -3,14 +3,20 @@ module Filemaker
|
|
3
3
|
module Types
|
4
4
|
class Text
|
5
5
|
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
+
return nil if value.nil?
|
7
|
+
|
6
8
|
value.to_s
|
7
9
|
end
|
8
10
|
|
9
11
|
def self.__filemaker_serialize_for_update(value)
|
12
|
+
return nil if value.nil?
|
13
|
+
|
10
14
|
value.to_s
|
11
15
|
end
|
12
16
|
|
13
17
|
def self.__filemaker_serialize_for_query(value)
|
18
|
+
return nil if value.nil?
|
19
|
+
|
14
20
|
value.to_s
|
15
21
|
end
|
16
22
|
end
|
@@ -3,18 +3,25 @@ module Filemaker
|
|
3
3
|
module Types
|
4
4
|
class Time
|
5
5
|
def self.__filemaker_cast_to_ruby_object(value)
|
6
|
-
return
|
6
|
+
return nil if value.nil?
|
7
|
+
return value.strftime("%H:%M") if value.is_a?(::Time)
|
8
|
+
|
7
9
|
::Time.parse(value.to_s)
|
8
10
|
end
|
9
11
|
|
10
12
|
def self.__filemaker_serialize_for_update(value)
|
11
|
-
return
|
12
|
-
|
13
|
+
return nil if value.nil?
|
14
|
+
return value.strftime("%H:%M") if value.is_a?(::Time) || value.is_a?(::DateTime)
|
15
|
+
|
16
|
+
# Could be a string like "09:00" already
|
17
|
+
value
|
13
18
|
end
|
14
19
|
|
15
20
|
def self.__filemaker_serialize_for_query(value)
|
16
|
-
return
|
17
|
-
|
21
|
+
return nil if value.nil?
|
22
|
+
return value.strftime("%H:%M") if value.is_a?(::Time)
|
23
|
+
|
24
|
+
value
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
data/lib/filemaker/record.rb
CHANGED
@@ -22,8 +22,7 @@ module Filemaker
|
|
22
22
|
# `field` is Nokogiri::XML::Element
|
23
23
|
field_name = field['name']
|
24
24
|
# Right now, I do not want to mess with the field name
|
25
|
-
# field_name.gsub!(Regexp.new(portal_table_name + '::'), '')
|
26
|
-
# \if portal_table_name
|
25
|
+
# field_name.gsub!(Regexp.new(portal_table_name + '::'), '') if portal_table_name
|
27
26
|
datum = []
|
28
27
|
|
29
28
|
metadata_fields = if portal_table_name
|
@@ -45,15 +44,15 @@ module Filemaker
|
|
45
44
|
end
|
46
45
|
|
47
46
|
def [](key)
|
48
|
-
raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}")
|
49
|
-
|
47
|
+
raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}") unless key?(key)
|
48
|
+
|
50
49
|
super
|
51
50
|
end
|
52
51
|
|
53
52
|
def []=(key, value)
|
54
53
|
if @ready
|
55
|
-
raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}")
|
56
|
-
|
54
|
+
raise(Filemaker::Errors::InvalidFieldError, "Invalid field: #{key}") unless key?(key)
|
55
|
+
|
57
56
|
@dirty[key] = value
|
58
57
|
else
|
59
58
|
super
|
@@ -80,6 +79,7 @@ module Filemaker
|
|
80
79
|
|
81
80
|
def normalize_data(datum)
|
82
81
|
return nil if datum.empty?
|
82
|
+
|
83
83
|
datum.size == 1 ? datum.first : datum
|
84
84
|
end
|
85
85
|
|
@@ -87,6 +87,7 @@ module Filemaker
|
|
87
87
|
method = symbol.to_s
|
88
88
|
return self[method] if key?(method)
|
89
89
|
return @dirty[$`] = args.first if method =~ /(=)$/ && key?($`)
|
90
|
+
|
90
91
|
super
|
91
92
|
end
|
92
93
|
|
data/lib/filemaker/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require 'typhoeus'
|
2
3
|
require 'filemaker/configuration'
|
3
4
|
|
@@ -102,12 +103,10 @@ module Filemaker
|
|
102
103
|
|
103
104
|
args.each do |key, value|
|
104
105
|
case value
|
105
|
-
when DateTime
|
106
|
+
when DateTime, Time
|
106
107
|
args[key] = value.strftime('%m/%d/%Y %H:%M:%S')
|
107
108
|
when Date
|
108
109
|
args[key] = value.strftime('%m/%d/%Y')
|
109
|
-
when Time
|
110
|
-
args[key] = value.strftime('%H:%M')
|
111
110
|
else
|
112
111
|
# Especially for range operator (...), we want to output as String
|
113
112
|
args[key] = value.to_s
|
data/lib/filemaker/version.rb
CHANGED
@@ -25,6 +25,13 @@ describe Filemaker::Model::Builder do
|
|
25
25
|
expect(subject.modify_date).to eq(Date.parse('2014-08-12'))
|
26
26
|
end
|
27
27
|
|
28
|
+
it 'has repeated fields' do
|
29
|
+
expect(subject.bonus).to eq [BigDecimal(1000), BigDecimal(2000), BigDecimal(3000)]
|
30
|
+
expect(subject.bonus__1).to eq BigDecimal(1000)
|
31
|
+
expect(subject.bonus__2).to eq BigDecimal(2000)
|
32
|
+
expect(subject.bonus__3).to eq BigDecimal(3000)
|
33
|
+
end
|
34
|
+
|
28
35
|
it 'is not dirty' do
|
29
36
|
expect(subject.changed?).to eq false
|
30
37
|
expect(subject.changes).to be_empty
|
@@ -60,7 +60,13 @@ describe Filemaker::Model::Criteria do
|
|
60
60
|
it 'will use the identity to find' do
|
61
61
|
allow(criteria).to receive(:first).and_return([])
|
62
62
|
criteria.find(22)
|
63
|
-
expect(criteria.selector).to eq({ 'ca id' => '
|
63
|
+
expect(criteria.selector).to eq({ 'ca id' => '==22' })
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'alias id to find' do
|
67
|
+
allow(criteria).to receive(:first).and_return([])
|
68
|
+
criteria.id(22)
|
69
|
+
expect(criteria.selector).to eq({ 'ca id' => '==22' })
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
@@ -34,10 +34,11 @@ describe Filemaker::Model::Relations do
|
|
34
34
|
@model.candidate.target
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
# Comment this test - because we return nil instead of Proxy object
|
38
|
+
# it 'uses identity for missing reference_key' do
|
39
|
+
# expect(@model.member.reference_key).to eq 'member_id'
|
40
|
+
# expect(@model.member.final_reference_key).to eq 'id'
|
41
|
+
# end
|
41
42
|
|
42
43
|
it 'proxy blank?' do
|
43
44
|
expect(@model.candidate.blank?).to eq false
|
@@ -79,9 +80,10 @@ describe Filemaker::Model::Relations do
|
|
79
80
|
expect(@model.manager.reference_key).to eq 'manager_id'
|
80
81
|
end
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
# Comment this test - because we return nil instead of Proxy object
|
84
|
+
# it 'another_manager has different reference_key' do
|
85
|
+
# expect(@model.another_manager.reference_key).to eq :candidate_id
|
86
|
+
# end
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
@@ -105,7 +107,7 @@ describe Filemaker::Model::Relations do
|
|
105
107
|
end
|
106
108
|
|
107
109
|
it 'returns criteria instead of an array of model objects' do
|
108
|
-
expect(@model.posts).to
|
110
|
+
expect(@model.posts.class).to eq Filemaker::Model::Criteria
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
@@ -35,26 +35,45 @@ describe Filemaker::Model::Types do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
context 'Types::
|
38
|
+
context 'Types::DateTime' do
|
39
39
|
it 'assign as a time' do
|
40
40
|
model.updated_at = Time.new(2018, 1, 1, 12, 12, 12)
|
41
41
|
expect(model.updated_at).to be_a Time
|
42
42
|
expect(model.updated_at).to eq Time.new(2018, 1, 1, 12, 12, 12)
|
43
43
|
end
|
44
44
|
|
45
|
+
it 'assign as a datetime but return as time' do
|
46
|
+
model.updated_at = DateTime.new(2018, 1, 1, 12, 12, 12)
|
47
|
+
expect(model.updated_at).to be_a Time
|
48
|
+
expect(model.updated_at).to eq Time.parse(model.updated_at.to_s)
|
49
|
+
end
|
50
|
+
|
45
51
|
it 'can query as a string' do
|
46
52
|
c = MyModel.where(updated_at: '2018')
|
47
53
|
expect(c.selector['modifieddate']).to be_a String
|
48
54
|
expect(c.selector['modifieddate']).to eq '2018'
|
49
55
|
end
|
50
56
|
|
51
|
-
it 'can query as a
|
57
|
+
it 'can query as a datetime' do
|
52
58
|
c = MyModel.where(updated_at: Time.new(2018, 1, 1, 12, 12, 12))
|
53
59
|
expect(c.selector['modifieddate']).to be_a Time
|
54
60
|
expect(c.selector['modifieddate']).to eq Time.new(2018, 1, 1, 12, 12, 12)
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
64
|
+
context 'Types::DateTime' do
|
65
|
+
it 'assign as time' do
|
66
|
+
model.time_in = DateTime.new(2019, 1, 1, 9, 0, 0)
|
67
|
+
expect(model.time_in).to be_a String
|
68
|
+
expect(model.time_in).to eq '09:00'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'query with HH:MM format' do
|
72
|
+
c = MyModel.where(time_in: Time.new(2019, 1, 1, 15, 45, 0))
|
73
|
+
expect(c.selector['time_in']).to eq '15:45'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
58
77
|
context 'Types::BigDecimal' do
|
59
78
|
it 'assign as a big decimal' do
|
60
79
|
model.salary = '25'
|
@@ -88,7 +88,12 @@ describe Filemaker::Model do
|
|
88
88
|
'created_at',
|
89
89
|
'modifieddate',
|
90
90
|
'salary',
|
91
|
-
'
|
91
|
+
'bonus',
|
92
|
+
'bonus(1)',
|
93
|
+
'bonus(2)',
|
94
|
+
'bonus(3)',
|
95
|
+
'passage of time',
|
96
|
+
'time_in'
|
92
97
|
]
|
93
98
|
end
|
94
99
|
|
@@ -103,23 +108,23 @@ describe Filemaker::Model do
|
|
103
108
|
# end
|
104
109
|
|
105
110
|
it 'accepts date range as string' do
|
106
|
-
|
107
|
-
expect(
|
111
|
+
c = MyModel.where(created_at: '1/1/2016...1/31/2016')
|
112
|
+
expect(c.selector['created_at']).to be_a String
|
108
113
|
end
|
109
114
|
|
110
115
|
it 'accepts number range as string' do
|
111
|
-
|
112
|
-
expect(
|
116
|
+
c = MyModel.where(salary: '1000...2000')
|
117
|
+
expect(c.selector['salary']).to be_a String
|
113
118
|
end
|
114
119
|
|
115
120
|
it 'accepts == for any type' do
|
116
|
-
|
117
|
-
expect(
|
121
|
+
c = MyModel.where(salary: '==')
|
122
|
+
expect(c.selector['salary']).to eq '=='
|
118
123
|
end
|
119
124
|
|
120
125
|
it 'accepts =* for any type' do
|
121
|
-
|
122
|
-
expect(
|
126
|
+
c = MyModel.where(age: '=*')
|
127
|
+
expect(c.selector['passage of time']).to eq '=*'
|
123
128
|
end
|
124
129
|
|
125
130
|
it 'check for presence of name and salary' do
|
data/spec/support/models.rb
CHANGED
@@ -32,6 +32,7 @@ class Job
|
|
32
32
|
string :status
|
33
33
|
string :jdid, fm_name: 'JDID'
|
34
34
|
date :modify_date, fm_name: 'modify date'
|
35
|
+
money :bonus, max_repeat: 3
|
35
36
|
end
|
36
37
|
|
37
38
|
class Member
|
@@ -72,7 +73,9 @@ class MyModel
|
|
72
73
|
date :created_at
|
73
74
|
datetime :updated_at, fm_name: 'ModifiedDate'
|
74
75
|
money :salary
|
76
|
+
money :bonus, max_repeat: 3
|
75
77
|
integer :age, fm_name: 'passage of time'
|
78
|
+
time :time_in
|
76
79
|
end
|
77
80
|
|
78
81
|
class Project
|
@@ -13,6 +13,7 @@
|
|
13
13
|
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="1" name="experience & qualification" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
14
14
|
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="1" name="location" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
15
15
|
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="1" name="Salary" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
16
|
+
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="3" name="Bonus" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
16
17
|
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="1" name="JD Cat" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
17
18
|
<field-definition auto-enter="no" four-digit-year="no" global="no" max-repeat="1" name="JobType" not-empty="no" numeric-only="no" result="text" time-of-day="no" type="normal"/>
|
18
19
|
<field-definition auto-enter="yes" four-digit-year="no" global="no" max-repeat="1" name="modify date" not-empty="no" numeric-only="no" result="date" time-of-day="no" type="normal"/>
|
@@ -39,6 +40,11 @@
|
|
39
40
|
<field name="Salary">
|
40
41
|
<data>Negotiable</data>
|
41
42
|
</field>
|
43
|
+
<field name="Bonus">
|
44
|
+
<data>1000</data>
|
45
|
+
<data>2000</data>
|
46
|
+
<data>3000</data>
|
47
|
+
</field>
|
42
48
|
<field name="JD Cat">
|
43
49
|
<data>IT & Telecommunications</data>
|
44
50
|
</field>
|
@@ -74,6 +80,11 @@
|
|
74
80
|
<field name="Salary">
|
75
81
|
<data>Negotiable</data>
|
76
82
|
</field>
|
83
|
+
<field name="Bonus">
|
84
|
+
<data>4000</data>
|
85
|
+
<data>5000</data>
|
86
|
+
<data>6000</data>
|
87
|
+
</field>
|
77
88
|
<field name="JD Cat">
|
78
89
|
<data>Administrative & Related</data>
|
79
90
|
</field>
|
@@ -109,6 +120,11 @@
|
|
109
120
|
<field name="Salary">
|
110
121
|
<data>6000 - 7000</data>
|
111
122
|
</field>
|
123
|
+
<field name="Bonus">
|
124
|
+
<data>7000</data>
|
125
|
+
<data>8000</data>
|
126
|
+
<data>9000</data>
|
127
|
+
</field>
|
112
128
|
<field name="JD Cat">
|
113
129
|
<data>IT & Telecommunications</data>
|
114
130
|
</field>
|
@@ -144,6 +160,11 @@
|
|
144
160
|
<field name="Salary">
|
145
161
|
<data>Negotiable</data>
|
146
162
|
</field>
|
163
|
+
<field name="Bonus">
|
164
|
+
<data>1000</data>
|
165
|
+
<data></data>
|
166
|
+
<data></data>
|
167
|
+
</field>
|
147
168
|
<field name="JD Cat">
|
148
169
|
<data>IT & Telecommunications</data>
|
149
170
|
</field>
|
@@ -179,6 +200,11 @@
|
|
179
200
|
<field name="Salary">
|
180
201
|
<data>3000 - 5500</data>
|
181
202
|
</field>
|
203
|
+
<field name="Bonus">
|
204
|
+
<data></data>
|
205
|
+
<data></data>
|
206
|
+
<data></data>
|
207
|
+
</field>
|
182
208
|
<field name="JD Cat">
|
183
209
|
<data>IT & Telecommunications</data>
|
184
210
|
</field>
|
@@ -196,4 +222,4 @@
|
|
196
222
|
</field>
|
197
223
|
</record>
|
198
224
|
</resultset>
|
199
|
-
</fmresultset>
|
225
|
+
</fmresultset>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filemaker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mech
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.10.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.10.4
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activemodel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,30 +70,30 @@ dependencies:
|
|
70
70
|
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -193,6 +193,7 @@ files:
|
|
193
193
|
- lib/filemaker/model/type.rb
|
194
194
|
- lib/filemaker/model/types/big_decimal.rb
|
195
195
|
- lib/filemaker/model/types/date.rb
|
196
|
+
- lib/filemaker/model/types/date_time.rb
|
196
197
|
- lib/filemaker/model/types/email.rb
|
197
198
|
- lib/filemaker/model/types/integer.rb
|
198
199
|
- lib/filemaker/model/types/text.rb
|
@@ -253,8 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
254
|
- !ruby/object:Gem::Version
|
254
255
|
version: '0'
|
255
256
|
requirements: []
|
256
|
-
|
257
|
-
rubygems_version: 2.7.7
|
257
|
+
rubygems_version: 3.0.6
|
258
258
|
signing_key:
|
259
259
|
specification_version: 4
|
260
260
|
summary: A Ruby wrapper to FileMaker XML API.
|