fmrest 0.7.1 → 0.11.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.
@@ -5,17 +5,18 @@ require "fmrest/string_date"
5
5
  module FmRest
6
6
  module V1
7
7
  class TypeCoercer < Faraday::Response::Middleware
8
- # We use this date to represent a time for consistency with ginjo-rfm
8
+ # We use this date to represent a FileMaker time for consistency with
9
+ # ginjo-rfm
9
10
  JULIAN_ZERO_DAY = "-4712/1/1"
10
11
 
11
12
  COERCE_HYBRID = [:hybrid, "hybrid", true].freeze
12
13
  COERCE_FULL = [:full, "full"].freeze
13
14
 
14
15
  # @param app [#call]
15
- # @param options [Hash]
16
- def initialize(app, options = FmRest.default_connection_settings)
16
+ # @param settings [FmRest::ConnectionSettings]
17
+ def initialize(app, settings)
17
18
  super(app)
18
- @options = options
19
+ @settings = settings
19
20
  end
20
21
 
21
22
  def on_complete(env)
@@ -30,15 +31,13 @@ module FmRest
30
31
  field_data = record["fieldData"] || record[:fieldData]
31
32
  portal_data = record["portalData"] || record[:portalData]
32
33
 
33
- # Build an enumerator that iterates over hashes of fields
34
- enum = Enumerator.new { |y| y << field_data }
35
- if portal_data
36
- portal_data.each_value do |portal_records|
37
- enum += portal_records.to_enum
34
+ coerce_fields(field_data)
35
+
36
+ portal_data.try(:each_value) do |portal_records|
37
+ portal_records.each do |pr|
38
+ coerce_fields(pr)
38
39
  end
39
40
  end
40
-
41
- enum.each { |hash| coerce_fields(hash) }
42
41
  end
43
42
  end
44
43
 
@@ -49,29 +48,49 @@ module FmRest
49
48
  next unless v.is_a?(String)
50
49
  next if k == "recordId" || k == :recordId || k == "modId" || k == :modId
51
50
 
52
- begin
53
- str_timestamp = datetime_class.strptime(v, datetime_format)
54
- hash[k] = str_timestamp
55
- next
56
- rescue ArgumentError
51
+ if quick_check_timestamp(v)
52
+ begin
53
+ hash[k] = coerce_timestamp(v)
54
+ next
55
+ rescue ArgumentError
56
+ end
57
57
  end
58
58
 
59
- begin
60
- str_date = date_class.strptime(v, date_format)
61
- hash[k] = str_date
62
- next
63
- rescue ArgumentError
59
+ if quick_check_date(v)
60
+ begin
61
+ hash[k] = date_class.strptime(v, date_strptime_format)
62
+ next
63
+ rescue ArgumentError
64
+ end
64
65
  end
65
66
 
66
- begin
67
- str_time = datetime_class.strptime("#{JULIAN_ZERO_DAY} #{v}", time_format)
68
- hash[k] = str_time
69
- next
70
- rescue ArgumentError
67
+ if quick_check_time(v)
68
+ begin
69
+ hash[k] = datetime_class.strptime("#{JULIAN_ZERO_DAY} #{v}", time_strptime_format)
70
+ next
71
+ rescue ArgumentError
72
+ end
71
73
  end
72
74
  end
73
75
  end
74
76
 
77
+ def coerce_timestamp(str)
78
+ str_timestamp = DateTime.strptime(str, datetime_strptime_format)
79
+
80
+ if local_timezone?
81
+ # Change the DateTime to the local timezone, keeping the same
82
+ # time and just modifying the timezone
83
+ offset = FmRest::V1.local_offset_for_datetime(str_timestamp)
84
+ str_timestamp = str_timestamp.new_offset(offset) - offset
85
+ end
86
+
87
+ if datetime_class == StringDateTime
88
+ str_timestamp = StringDateTime.new(str, str_timestamp)
89
+ end
90
+
91
+ str_timestamp
92
+ end
93
+
75
94
  def date_class
76
95
  @date_class ||=
77
96
  case coerce_dates
@@ -92,23 +111,79 @@ module FmRest
92
111
  end
93
112
  end
94
113
 
95
- def date_format
96
- @date_format ||=
97
- FmRest::V1.convert_date_time_format(@options[:date_format] || DEFAULT_DATE_FORMAT)
114
+ def date_fm_format
115
+ @settings.date_format
116
+ end
117
+
118
+ def timestamp_fm_format
119
+ @settings.timestamp_format
120
+ end
121
+
122
+ def time_fm_format
123
+ @settings.time_format
98
124
  end
99
125
 
100
- def datetime_format
101
- @datetime_format ||=
102
- FmRest::V1.convert_date_time_format(@options[:timestamp_format] || DEFAULT_TIMESTAMP_FORMAT)
126
+ def date_strptime_format
127
+ FmRest::V1.fm_date_to_strptime_format(date_fm_format)
128
+ end
129
+
130
+ def datetime_strptime_format
131
+ FmRest::V1.fm_date_to_strptime_format(timestamp_fm_format)
132
+ end
133
+
134
+ def time_strptime_format
135
+ @time_strptime_format ||=
136
+ "%Y/%m/%d " + FmRest::V1.fm_date_to_strptime_format(time_fm_format)
137
+ end
138
+
139
+ # We use a string length test, followed by regexp match test to try to
140
+ # identify date fields. Benchmarking shows this should be between 1 and 3
141
+ # orders of magnitude faster for fails (i.e. non-dates) than just using
142
+ # Date.strptime.
143
+ #
144
+ # user system total real
145
+ # strptime: 0.268496 0.000962 0.269458 ( 0.270865)
146
+ # re=~: 0.024872 0.000070 0.024942 ( 0.025057)
147
+ # re.match?: 0.019745 0.000095 0.019840 ( 0.020058)
148
+ # strptime fail: 0.141309 0.000354 0.141663 ( 0.142266)
149
+ # re=~ fail: 0.031637 0.000095 0.031732 ( 0.031872)
150
+ # re.match? fail: 0.011249 0.000056 0.011305 ( 0.011375)
151
+ # length fail: 0.007177 0.000024 0.007201 ( 0.007222)
152
+ #
153
+ # NOTE: The faster Regexp#match? was introduced in Ruby 2.4.0, so we
154
+ # can't really rely on it being available
155
+ if //.respond_to?(:match?)
156
+ def quick_check_timestamp(v)
157
+ v.length == timestamp_fm_format.length && FmRest::V1::fm_date_to_regexp(timestamp_fm_format).match?(v)
158
+ end
159
+
160
+ def quick_check_date(v)
161
+ v.length == date_fm_format.length && FmRest::V1::fm_date_to_regexp(date_fm_format).match?(v)
162
+ end
163
+
164
+ def quick_check_time(v)
165
+ v.length == time_fm_format.length && FmRest::V1::fm_date_to_regexp(time_fm_format).match?(v)
166
+ end
167
+ else
168
+ def quick_check_timestamp(v)
169
+ v.length == timestamp_fm_format.length && FmRest::V1::fm_date_to_regexp(timestamp_fm_format) =~ v
170
+ end
171
+
172
+ def quick_check_date(v)
173
+ v.length == date_fm_format.length && FmRest::V1::fm_date_to_regexp(date_fm_format) =~ v
174
+ end
175
+
176
+ def quick_check_time(v)
177
+ v.length == time_fm_format.length && FmRest::V1::fm_date_to_regexp(time_fm_format) =~ v
178
+ end
103
179
  end
104
180
 
105
- def time_format
106
- @time_format ||=
107
- "%Y/%m/%d " + FmRest::V1.convert_date_time_format(@options[:time_format] || DEFAULT_TIME_FORMAT)
181
+ def local_timezone?
182
+ @local_timezone ||= @settings.timezone.try(:to_sym) == :local
108
183
  end
109
184
 
110
185
  def coerce_dates
111
- @options.fetch(:coerce_dates, false)
186
+ @settings.coerce_dates
112
187
  end
113
188
 
114
189
  alias_method :enabled?, :coerce_dates
@@ -5,17 +5,6 @@ module FmRest
5
5
  module Utils
6
6
  VALID_SCRIPT_KEYS = [:prerequest, :presort, :after].freeze
7
7
 
8
- FM_DATETIME_FORMAT_MATCHER = /MM|mm|dd|HH|ss|yyyy/.freeze
9
-
10
- FM_DATETIME_FORMAT_SUBSTITUTIONS = {
11
- "MM" => "%m",
12
- "dd" => "%d",
13
- "yyyy" => "%Y",
14
- "HH" => "%H",
15
- "mm" => "%M",
16
- "ss" => "%S"
17
- }.freeze
18
-
19
8
  # Converts custom script options to a hash with the Data API's expected
20
9
  # JSON script format.
21
10
  #
@@ -83,12 +72,6 @@ module FmRest
83
72
  params
84
73
  end
85
74
 
86
- # Converts a FM date-time format to `Date.strptime` format
87
- #
88
- def convert_date_time_format(fm_format)
89
- fm_format.gsub(FM_DATETIME_FORMAT_MATCHER, FM_DATETIME_FORMAT_SUBSTITUTIONS)
90
- end
91
-
92
75
  private
93
76
 
94
77
  def convert_script_arguments(script_arguments, suffix = nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FmRest
4
- VERSION = "0.7.1"
4
+ VERSION = "0.11.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fmrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Carbajal
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-13 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -54,30 +54,30 @@ dependencies:
54
54
  name: bundler
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - "~>"
57
+ - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: '1.16'
59
+ version: '0'
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - "~>"
64
+ - - ">="
65
65
  - !ruby/object:Gem::Version
66
- version: '1.16'
66
+ version: '0'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: rake
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - "~>"
71
+ - - ">="
72
72
  - !ruby/object:Gem::Version
73
- version: '10.0'
73
+ version: '0'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - "~>"
78
+ - - ">="
79
79
  - !ruby/object:Gem::Version
80
- version: '10.0'
80
+ version: '0'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: rspec
83
83
  requirement: !ruby/object:Gem::Requirement
@@ -226,6 +226,7 @@ executables: []
226
226
  extensions: []
227
227
  extra_rdoc_files: []
228
228
  files:
229
+ - ".github/workflows/ci.yml"
229
230
  - ".gitignore"
230
231
  - ".rspec"
231
232
  - ".travis.yml"
@@ -237,6 +238,7 @@ files:
237
238
  - Rakefile
238
239
  - fmrest.gemspec
239
240
  - lib/fmrest.rb
241
+ - lib/fmrest/connection_settings.rb
240
242
  - lib/fmrest/errors.rb
241
243
  - lib/fmrest/spyke.rb
242
244
  - lib/fmrest/spyke/base.rb
@@ -247,6 +249,7 @@ files:
247
249
  - lib/fmrest/spyke/model/auth.rb
248
250
  - lib/fmrest/spyke/model/connection.rb
249
251
  - lib/fmrest/spyke/model/container_fields.rb
252
+ - lib/fmrest/spyke/model/global_fields.rb
250
253
  - lib/fmrest/spyke/model/http.rb
251
254
  - lib/fmrest/spyke/model/orm.rb
252
255
  - lib/fmrest/spyke/model/serialization.rb
@@ -263,8 +266,10 @@ files:
263
266
  - lib/fmrest/token_store/moneta.rb
264
267
  - lib/fmrest/token_store/redis.rb
265
268
  - lib/fmrest/v1.rb
269
+ - lib/fmrest/v1/auth.rb
266
270
  - lib/fmrest/v1/connection.rb
267
271
  - lib/fmrest/v1/container_fields.rb
272
+ - lib/fmrest/v1/dates.rb
268
273
  - lib/fmrest/v1/paths.rb
269
274
  - lib/fmrest/v1/raise_errors.rb
270
275
  - lib/fmrest/v1/token_session.rb
@@ -277,7 +282,7 @@ homepage: https://github.com/beezwax/fmrest-ruby
277
282
  licenses:
278
283
  - MIT
279
284
  metadata: {}
280
- post_install_message:
285
+ post_install_message:
281
286
  rdoc_options: []
282
287
  require_paths:
283
288
  - lib
@@ -293,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
293
298
  version: '0'
294
299
  requirements: []
295
300
  rubygems_version: 3.0.6
296
- signing_key:
301
+ signing_key:
297
302
  specification_version: 4
298
303
  summary: FileMaker Data API client using Faraday
299
304
  test_files: []