finch-api 0.1.0.pre.alpha.3 → 0.1.0.pre.alpha.4

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.
@@ -49,7 +49,7 @@ module FinchAPI
49
49
 
50
50
  case page_data
51
51
  in {paging: Hash | nil => paging}
52
- @paging = FinchAPI::Models::Paging.coerce(paging)
52
+ @paging = FinchAPI::Converter.coerce(FinchAPI::Models::Paging, paging)
53
53
  else
54
54
  end
55
55
  end
@@ -253,6 +253,16 @@ module FinchAPI
253
253
  end
254
254
 
255
255
  class ConnectionStatus < FinchAPI::BaseModel
256
+ # @!attribute [r] last_successful_sync
257
+ # The datetime when the connection was last successfully synced.
258
+ #
259
+ # @return [Time, nil]
260
+ optional :last_successful_sync, Time
261
+
262
+ # @!parse
263
+ # # @return [Time]
264
+ # attr_writer :last_successful_sync
265
+
256
266
  # @!attribute [r] message
257
267
  #
258
268
  # @return [String, nil]
@@ -272,10 +282,11 @@ module FinchAPI
272
282
  # attr_writer :status
273
283
 
274
284
  # @!parse
285
+ # # @param last_successful_sync [Time]
275
286
  # # @param message [String]
276
287
  # # @param status [Symbol, FinchAPI::Models::ConnectionStatusType]
277
288
  # #
278
- # def initialize(message: nil, status: nil, **) = super
289
+ # def initialize(last_successful_sync: nil, message: nil, status: nil, **) = super
279
290
 
280
291
  # def initialize: (Hash | FinchAPI::BaseModel) -> void
281
292
  end
@@ -49,7 +49,7 @@ module FinchAPI
49
49
 
50
50
  case page_data
51
51
  in {paging: Hash | nil => paging}
52
- @paging = FinchAPI::Models::Paging.coerce(paging)
52
+ @paging = FinchAPI::Converter.coerce(FinchAPI::Models::Paging, paging)
53
53
  else
54
54
  end
55
55
  end
@@ -37,7 +37,7 @@ module FinchAPI
37
37
 
38
38
  case page_data
39
39
  in Array
40
- replace(page_data.map { model.coerce(_1) })
40
+ replace(page_data.map { FinchAPI::Converter.coerce(model, _1) })
41
41
  else
42
42
  end
43
43
  end
@@ -75,7 +75,7 @@ module FinchAPI
75
75
  def coerce_boolean(input)
76
76
  case input.is_a?(String) ? input.downcase : input
77
77
  in Numeric
78
- !input.zero?
78
+ input.nonzero?
79
79
  in "true"
80
80
  true
81
81
  in "false"
@@ -165,14 +165,12 @@ module FinchAPI
165
165
  private def deep_merge_lr(lhs, rhs, concat: false)
166
166
  case [lhs, rhs, concat]
167
167
  in [Hash, Hash, _]
168
- # rubocop:disable Style/YodaCondition
169
- rhs_cleaned = rhs.reject { |_, val| OMIT == val }
168
+ rhs_cleaned = rhs.reject { _2 == FinchAPI::Util::OMIT }
170
169
  lhs
171
- .reject { |key, _| OMIT == rhs[key] }
170
+ .reject { |key, _| rhs[key] == FinchAPI::Util::OMIT }
172
171
  .merge(rhs_cleaned) do |_, old_val, new_val|
173
172
  deep_merge_lr(old_val, new_val, concat: concat)
174
173
  end
175
- # rubocop:enable Style/YodaCondition
176
174
  in [Array, Array, true]
177
175
  lhs.concat(rhs)
178
176
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FinchAPI
4
- VERSION = "0.1.0-alpha.3"
4
+ VERSION = "0.1.0-alpha.4"
5
5
  end
data/lib/finch-api.rb CHANGED
@@ -36,7 +36,6 @@ require "connection_pool"
36
36
  # Package files.
37
37
  require_relative "finch-api/version"
38
38
  require_relative "finch-api/util"
39
- require_relative "finch-api/extern"
40
39
  require_relative "finch-api/base_model"
41
40
  require_relative "finch-api/base_page"
42
41
  require_relative "finch-api/request_options"
@@ -84,7 +84,7 @@ module FinchAPI
84
84
  end
85
85
 
86
86
  # @api private
87
- sig { returns(T.anything) }
87
+ sig { returns(FinchAPI::PooledNetRequester) }
88
88
  attr_accessor :requester
89
89
 
90
90
  # @api private
@@ -5,9 +5,18 @@ module FinchAPI
5
5
  module Converter
6
6
  Input = T.type_alias { T.any(FinchAPI::Converter, T::Class[T.anything]) }
7
7
 
8
+ State =
9
+ T.type_alias do
10
+ {
11
+ strictness: T.any(T::Boolean, Symbol),
12
+ exactness: {yes: Integer, no: Integer, maybe: Integer},
13
+ branched: Integer
14
+ }
15
+ end
16
+
8
17
  # @api private
9
- sig { overridable.params(value: T.anything).returns(T.anything) }
10
- def coerce(value)
18
+ sig { overridable.params(value: T.anything, state: FinchAPI::Converter::State).returns(T.anything) }
19
+ def coerce(value, state:)
11
20
  end
12
21
 
13
22
  # @api private
@@ -15,15 +24,6 @@ module FinchAPI
15
24
  def dump(value)
16
25
  end
17
26
 
18
- # @api private
19
- sig do
20
- overridable
21
- .params(value: T.anything)
22
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
23
- end
24
- def try_strict_coerce(value)
25
- end
26
-
27
27
  class << self
28
28
  # @api private
29
29
  sig do
@@ -38,7 +38,7 @@ module FinchAPI
38
38
  FinchAPI::Converter::Input
39
39
  )
40
40
  )
41
- .returns(T.proc.returns(T.anything).void)
41
+ .returns(T.proc.returns(T.anything))
42
42
  end
43
43
  def self.type_info(spec)
44
44
  end
@@ -51,28 +51,43 @@ module FinchAPI
51
51
  # 2. if it's possible and safe to convert the given `value` to `target`, then the
52
52
  # converted value
53
53
  # 3. otherwise, the given `value` unaltered
54
- sig { params(target: FinchAPI::Converter::Input, value: T.anything).returns(T.anything) }
55
- def self.coerce(target, value)
54
+ #
55
+ # The coercion process is subject to improvement between minor release versions.
56
+ # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode
57
+ sig do
58
+ params(target: FinchAPI::Converter::Input, value: T.anything, state: FinchAPI::Converter::State)
59
+ .returns(T.anything)
60
+ end
61
+ def self.coerce(
62
+ target,
63
+ value,
64
+ # The `strictness` is one of `true`, `false`, or `:strong`. This informs the
65
+ # coercion strategy when we have to decide between multiple possible conversion
66
+ # targets:
67
+ #
68
+ # - `true`: the conversion must be exact, with minimum coercion.
69
+ # - `false`: the conversion can be approximate, with some coercion.
70
+ # - `:strong`: the conversion must be exact, with no coercion, and raise an error
71
+ # if not possible.
72
+ #
73
+ # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For
74
+ # any given conversion attempt, the exactness will be updated based on how closely
75
+ # the value recursively matches the target type:
76
+ #
77
+ # - `yes`: the value can be converted to the target type with minimum coercion.
78
+ # - `maybe`: the value can be converted to the target type with some reasonable
79
+ # coercion.
80
+ # - `no`: the value cannot be converted to the target type.
81
+ #
82
+ # See implementation below for more details.
83
+ state: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
84
+ )
56
85
  end
57
86
 
58
87
  # @api private
59
88
  sig { params(target: FinchAPI::Converter::Input, value: T.anything).returns(T.anything) }
60
89
  def self.dump(target, value)
61
90
  end
62
-
63
- # @api private
64
- #
65
- # The underlying algorithm for computing maximal compatibility is subject to
66
- # future improvements.
67
- #
68
- # Similar to `#.coerce`, used to determine the best union variant to decode into.
69
- #
70
- # 1. determine if strict-ish coercion is possible
71
- # 2. return either result of successful coercion or if loose coercion is possible
72
- # 3. return a score for recursively tallied count for fields that can be coerced
73
- sig { params(target: FinchAPI::Converter::Input, value: T.anything).returns(T.anything) }
74
- def self.try_strict_coerce(target, value)
75
- end
76
91
  end
77
92
  end
78
93
 
@@ -95,23 +110,16 @@ module FinchAPI
95
110
 
96
111
  class << self
97
112
  # @api private
98
- sig(:final) { override.params(value: T.anything).returns(T.anything) }
99
- def coerce(value)
113
+ sig(:final) do
114
+ override.params(value: T.anything, state: FinchAPI::Converter::State).returns(T.anything)
115
+ end
116
+ def coerce(value, state:)
100
117
  end
101
118
 
102
119
  # @api private
103
120
  sig(:final) { override.params(value: T.anything).returns(T.anything) }
104
121
  def dump(value)
105
122
  end
106
-
107
- # @api private
108
- sig(:final) do
109
- override
110
- .params(value: T.anything)
111
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
112
- end
113
- def try_strict_coerce(value)
114
- end
115
123
  end
116
124
  end
117
125
 
@@ -135,9 +143,11 @@ module FinchAPI
135
143
  class << self
136
144
  # @api private
137
145
  sig(:final) do
138
- override.params(value: T.any(T::Boolean, T.anything)).returns(T.any(T::Boolean, T.anything))
146
+ override
147
+ .params(value: T.any(T::Boolean, T.anything), state: FinchAPI::Converter::State)
148
+ .returns(T.any(T::Boolean, T.anything))
139
149
  end
140
- def coerce(value)
150
+ def coerce(value, state:)
141
151
  end
142
152
 
143
153
  # @api private
@@ -146,15 +156,6 @@ module FinchAPI
146
156
  end
147
157
  def dump(value)
148
158
  end
149
-
150
- # @api private
151
- sig(:final) do
152
- override
153
- .params(value: T.anything)
154
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
155
- end
156
- def try_strict_coerce(value)
157
- end
158
159
  end
159
160
  end
160
161
 
@@ -194,23 +195,21 @@ module FinchAPI
194
195
  end
195
196
 
196
197
  # @api private
197
- sig { override.params(value: T.any(String, Symbol, T.anything)).returns(T.any(Symbol, T.anything)) }
198
- def coerce(value)
198
+ #
199
+ # Unlike with primitives, `Enum` additionally validates that the value is a member
200
+ # of the enum.
201
+ sig do
202
+ override
203
+ .params(value: T.any(String, Symbol, T.anything), state: FinchAPI::Converter::State)
204
+ .returns(T.any(Symbol, T.anything))
205
+ end
206
+ def coerce(value, state:)
199
207
  end
200
208
 
201
209
  # @api private
202
210
  sig { override.params(value: T.any(Symbol, T.anything)).returns(T.any(Symbol, T.anything)) }
203
211
  def dump(value)
204
212
  end
205
-
206
- # @api private
207
- sig do
208
- override
209
- .params(value: T.anything)
210
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
211
- end
212
- def try_strict_coerce(value)
213
- end
214
213
  end
215
214
 
216
215
  # @api private
@@ -264,23 +263,14 @@ module FinchAPI
264
263
  end
265
264
 
266
265
  # @api private
267
- sig { override.params(value: T.anything).returns(T.anything) }
268
- def coerce(value)
266
+ sig { override.params(value: T.anything, state: FinchAPI::Converter::State).returns(T.anything) }
267
+ def coerce(value, state:)
269
268
  end
270
269
 
271
270
  # @api private
272
271
  sig { override.params(value: T.anything).returns(T.anything) }
273
272
  def dump(value)
274
273
  end
275
-
276
- # @api private
277
- sig do
278
- override
279
- .params(value: T.anything)
280
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
281
- end
282
- def try_strict_coerce(value)
283
- end
284
274
  end
285
275
 
286
276
  # @api private
@@ -317,10 +307,10 @@ module FinchAPI
317
307
  # @api private
318
308
  sig(:final) do
319
309
  override
320
- .params(value: T.any(T::Enumerable[T.anything], T.anything))
310
+ .params(value: T.any(T::Enumerable[T.anything], T.anything), state: FinchAPI::Converter::State)
321
311
  .returns(T.any(T::Array[T.anything], T.anything))
322
312
  end
323
- def coerce(value)
313
+ def coerce(value, state:)
324
314
  end
325
315
 
326
316
  # @api private
@@ -333,17 +323,13 @@ module FinchAPI
333
323
  end
334
324
 
335
325
  # @api private
336
- sig(:final) do
337
- override
338
- .params(value: T.anything)
339
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
340
- end
341
- def try_strict_coerce(value)
326
+ sig(:final) { returns(T.anything) }
327
+ protected def item_type
342
328
  end
343
329
 
344
330
  # @api private
345
- sig(:final) { returns(T.anything) }
346
- protected def item_type
331
+ sig(:final) { returns(T::Boolean) }
332
+ protected def nilable?
347
333
  end
348
334
 
349
335
  # @api private
@@ -396,10 +382,10 @@ module FinchAPI
396
382
  # @api private
397
383
  sig(:final) do
398
384
  override
399
- .params(value: T.any(T::Hash[T.anything, T.anything], T.anything))
385
+ .params(value: T.any(T::Hash[T.anything, T.anything], T.anything), state: FinchAPI::Converter::State)
400
386
  .returns(T.any(FinchAPI::Util::AnyHash, T.anything))
401
387
  end
402
- def coerce(value)
388
+ def coerce(value, state:)
403
389
  end
404
390
 
405
391
  # @api private
@@ -412,17 +398,13 @@ module FinchAPI
412
398
  end
413
399
 
414
400
  # @api private
415
- sig(:final) do
416
- override
417
- .params(value: T.anything)
418
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
419
- end
420
- def try_strict_coerce(value)
401
+ sig(:final) { returns(T.anything) }
402
+ protected def item_type
421
403
  end
422
404
 
423
405
  # @api private
424
- sig(:final) { returns(T.anything) }
425
- protected def item_type
406
+ sig(:final) { returns(T::Boolean) }
407
+ protected def nilable?
426
408
  end
427
409
 
428
410
  # @api private
@@ -446,7 +428,7 @@ module FinchAPI
446
428
 
447
429
  abstract!
448
430
 
449
- KnownFieldShape = T.type_alias { {mode: T.nilable(Symbol), required: T::Boolean} }
431
+ KnownFieldShape = T.type_alias { {mode: T.nilable(Symbol), required: T::Boolean, nilable: T::Boolean} }
450
432
 
451
433
  class << self
452
434
  # @api private
@@ -465,11 +447,6 @@ module FinchAPI
465
447
  def known_fields
466
448
  end
467
449
 
468
- # @api private
469
- sig { returns(T::Hash[Symbol, Symbol]) }
470
- def reverse_map
471
- end
472
-
473
450
  # @api private
474
451
  sig do
475
452
  returns(
@@ -480,11 +457,6 @@ module FinchAPI
480
457
  def fields
481
458
  end
482
459
 
483
- # @api private
484
- sig { returns(T::Hash[Symbol, T.proc.returns(T::Class[T.anything])]) }
485
- def defaults
486
- end
487
-
488
460
  # @api private
489
461
  sig do
490
462
  params(
@@ -554,6 +526,10 @@ module FinchAPI
554
526
  sig { params(blk: T.proc.void).void }
555
527
  private def response_only(&blk)
556
528
  end
529
+
530
+ sig { params(other: T.anything).returns(T::Boolean) }
531
+ def ==(other)
532
+ end
557
533
  end
558
534
 
559
535
  sig { params(other: T.anything).returns(T::Boolean) }
@@ -564,10 +540,13 @@ module FinchAPI
564
540
  # @api private
565
541
  sig do
566
542
  override
567
- .params(value: T.any(FinchAPI::BaseModel, T::Hash[T.anything, T.anything], T.anything))
543
+ .params(
544
+ value: T.any(FinchAPI::BaseModel, T::Hash[T.anything, T.anything], T.anything),
545
+ state: FinchAPI::Converter::State
546
+ )
568
547
  .returns(T.any(T.attached_class, T.anything))
569
548
  end
570
- def coerce(value)
549
+ def coerce(value, state:)
571
550
  end
572
551
 
573
552
  # @api private
@@ -578,15 +557,6 @@ module FinchAPI
578
557
  end
579
558
  def dump(value)
580
559
  end
581
-
582
- # @api private
583
- sig do
584
- override
585
- .params(value: T.anything)
586
- .returns(T.any([T::Boolean, T.anything, NilClass], [T::Boolean, T::Boolean, Integer]))
587
- end
588
- def try_strict_coerce(value)
589
- end
590
560
  end
591
561
 
592
562
  # Returns the raw value associated with the given key, if found. Otherwise, nil is
@@ -632,10 +602,6 @@ module FinchAPI
632
602
  def self.new(data = {})
633
603
  end
634
604
 
635
- sig { returns(String) }
636
- def to_s
637
- end
638
-
639
605
  sig { returns(String) }
640
606
  def inspect
641
607
  end
@@ -265,6 +265,13 @@ module FinchAPI
265
265
  end
266
266
 
267
267
  class ConnectionStatus < FinchAPI::BaseModel
268
+ # The datetime when the connection was last successfully synced.
269
+ sig { returns(T.nilable(Time)) }
270
+ attr_reader :last_successful_sync
271
+
272
+ sig { params(last_successful_sync: Time).void }
273
+ attr_writer :last_successful_sync
274
+
268
275
  sig { returns(T.nilable(String)) }
269
276
  attr_reader :message
270
277
 
@@ -278,12 +285,22 @@ module FinchAPI
278
285
  attr_writer :status
279
286
 
280
287
  sig do
281
- params(message: String, status: FinchAPI::Models::ConnectionStatusType::OrSymbol).returns(T.attached_class)
288
+ params(
289
+ last_successful_sync: Time,
290
+ message: String,
291
+ status: FinchAPI::Models::ConnectionStatusType::OrSymbol
292
+ )
293
+ .returns(T.attached_class)
282
294
  end
283
- def self.new(message: nil, status: nil)
295
+ def self.new(last_successful_sync: nil, message: nil, status: nil)
284
296
  end
285
297
 
286
- sig { override.returns({message: String, status: FinchAPI::Models::ConnectionStatusType::TaggedSymbol}) }
298
+ sig do
299
+ override
300
+ .returns(
301
+ {last_successful_sync: Time, message: String, status: FinchAPI::Models::ConnectionStatusType::TaggedSymbol}
302
+ )
303
+ end
287
304
  def to_hash
288
305
  end
289
306
  end
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
 
3
3
  module FinchAPI
4
- VERSION = "0.1.0-alpha.3"
4
+ VERSION = "0.1.0-alpha.4"
5
5
  end
@@ -49,7 +49,7 @@ module FinchAPI
49
49
  ) -> void
50
50
 
51
51
  # @api private
52
- attr_accessor requester: top
52
+ attr_accessor requester: FinchAPI::PooledNetRequester
53
53
 
54
54
  def initialize: (
55
55
  base_url: String,