printavo-ruby 0.2.0 → 0.3.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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c80d0cf1950d67050c32a5d20e9bc6d001587fb509c3f52831b6dfbec77e5b3
4
- data.tar.gz: 2d117bae60f460bd9ba9aaa2571bdeacb4915e361224e3f3d61183e2b52a33df
3
+ metadata.gz: a7786dadca364f38068636a9a6e30efac78ac79107c8dfb4ade22b39db5f0bc1
4
+ data.tar.gz: f0464978791f12c8e3f5d37d2de09ecfc4b97e57aca4999beda995b68957d2e1
5
5
  SHA512:
6
- metadata.gz: 1858601061541936154d9d8daad2b30950dd737501502681e266966f8de415eb84f15c0fa9ba3d8ac2725a27990d8cb000728a9be03c0d5c7e86c13362d53b06
7
- data.tar.gz: 3ff3869148ccbabb980d352b1a3270de1c63d18eaf6d512a96fb116cd9c346718f90b7121a13455d582b7e205a1736ee357437f8f1a34cd9e83b572cd7d63184
6
+ metadata.gz: a6aae8c15d5f5c348d8e717c09eaf85092a9421d473541ac1ef3c38042534ed1aa14c6e0c5283d6878325cdf32a7325fed52e980913e7b15e8c443ed64a695bb
7
+ data.tar.gz: bac95ec4243aa408c495f88d7c4841a308f7c49f509d8b7a0f3a4a161cb9db30418d2ba2c79be67f353c89b68d24cec6f70c1487b64496ea5ef74489fe44acc8
data/README.md CHANGED
@@ -116,6 +116,26 @@ job = client.jobs.find("77")
116
116
  puts job.taxable? # => true
117
117
  ```
118
118
 
119
+ ### Pagination
120
+
121
+ All list resources support `each_page` and `all_pages` in addition to `all`.
122
+
123
+ ```ruby
124
+ # Iterate page by page (cursor-based, memory-efficient)
125
+ client.customers.each_page(first: 50) do |records|
126
+ records.each { |c| puts c.full_name }
127
+ end
128
+
129
+ # Collect every record across all pages into one array
130
+ all_orders = client.orders.all_pages
131
+
132
+ # Jobs require order_id
133
+ client.jobs.each_page(order_id: "99") do |records|
134
+ records.each { |j| puts j.name }
135
+ end
136
+ all_jobs = client.jobs.all_pages(order_id: "99")
137
+ ```
138
+
119
139
  ### Statuses
120
140
 
121
141
  ```ruby
@@ -234,9 +254,9 @@ end
234
254
 
235
255
  | Version | Milestone |
236
256
  |---|---|
237
- | 0.1.0 | Auth + Customers + Orders + Jobs ✅ |
257
+ | 0.1.0 | Auth + Customers + Orders + Jobs + Webhooks (Rack-compatible) ✅ |
238
258
  | 0.2.0 | Status registry + Inquiries ✅ |
239
- | 0.3.0 | Webhooks (Rack-compatible) |
259
+ | 0.3.0 | Pagination helpers (`each_page`, `all_pages`) + `bin/lint` ✅ |
240
260
  | 0.4.0 | Expanded GraphQL DSL |
241
261
  | 0.5.0 | Mutations (create/update) |
242
262
  | 0.6.0 | Analytics / Reporting queries |
data/docs/CHANGELOG.md CHANGED
@@ -8,6 +8,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.3.0] - 2026-03-29
12
+
13
+ ### Added
14
+ - `Printavo::Page` — value object wrapping `records`, `has_next_page`, `end_cursor` with `to_a`, `size`, `empty?`
15
+ - `Printavo::Resources::Base#each_page` — yields each page of records as an Array, following cursors automatically
16
+ - `Printavo::Resources::Base#all_pages` — returns all records across all pages as a flat Array
17
+ - All resources (`Customers`, `Orders`, `Jobs`, `Statuses`, `Inquiries`) implement `fetch_page` and support `each_page`/`all_pages`
18
+ - `Jobs#each_page(order_id:)` and `Jobs#all_pages(order_id:)` — `order_id` forwarded via `**kwargs`
19
+ - `bin/lint` — multi-Ruby RuboCop runner mirroring `bin/spec` (reads versions from `.mise.toml`)
20
+ - Roadmap: moved Pagination from 0.8.0 to 0.3.0; Webhooks slot repurposed
21
+
22
+ ### Changed
23
+ - All resource `all` methods refactored to delegate to `fetch_page` (backward compatible — still returns `Array`)
24
+
11
25
  ## [0.2.0] - 2026-03-29
12
26
 
13
27
  ### Added
@@ -0,0 +1,20 @@
1
+ # lib/printavo/page.rb
2
+ module Printavo
3
+ # Wraps a single page of API results with cursor metadata.
4
+ #
5
+ # @example Iterating pages manually
6
+ # page = client.customers.fetch_page(first: 10)
7
+ # page.records.each { |c| puts c.full_name }
8
+ # puts page.has_next_page # => true
9
+ # puts page.end_cursor # => "cursor_abc123"
10
+ #
11
+ # @example Using each_page
12
+ # client.customers.each_page(first: 10) do |records|
13
+ # records.each { |c| puts c.full_name }
14
+ # end
15
+ Page = Struct.new(:records, :has_next_page, :end_cursor, keyword_init: true) do
16
+ def to_a = records
17
+ def size = records.size
18
+ def empty? = records.empty?
19
+ end
20
+ end
@@ -5,6 +5,47 @@ module Printavo
5
5
  def initialize(graphql)
6
6
  @graphql = graphql
7
7
  end
8
+
9
+ # Yields each page of records as an Array, following cursors automatically.
10
+ # Extra keyword arguments are forwarded to fetch_page (e.g. order_id: for Jobs).
11
+ #
12
+ # @param first [Integer] page size (default 25)
13
+ # @yieldparam records [Array] one page of domain model objects
14
+ #
15
+ # @example
16
+ # client.customers.each_page(first: 50) do |records|
17
+ # records.each { |c| puts c.full_name }
18
+ # end
19
+ def each_page(first: 25, **kwargs)
20
+ after = nil
21
+ loop do
22
+ page = fetch_page(first: first, after: after, **kwargs)
23
+ yield(page.records)
24
+ break unless page.has_next_page
25
+
26
+ after = page.end_cursor
27
+ end
28
+ end
29
+
30
+ # Returns all records across all pages as a flat Array.
31
+ # Extra keyword arguments are forwarded to fetch_page (e.g. order_id: for Jobs).
32
+ #
33
+ # @param first [Integer] page size per request (default 25)
34
+ # @return [Array]
35
+ #
36
+ # @example
37
+ # all_customers = client.customers.all_pages
38
+ # all_jobs = client.jobs.all_pages(order_id: "99")
39
+ def all_pages(first: 25, **kwargs)
40
+ [].tap { |all| each_page(first: first, **kwargs) { |records| all.concat(records) } }
41
+ end
42
+
43
+ private
44
+
45
+ # Subclasses must implement: returns a Printavo::Page.
46
+ def fetch_page(**)
47
+ raise NotImplementedError, "#{self.class}#fetch_page is not implemented"
48
+ end
8
49
  end
9
50
  end
10
51
  end
@@ -35,14 +35,26 @@ module Printavo
35
35
  GQL
36
36
 
37
37
  def all(first: 25, after: nil)
38
- data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
39
- data['customers']['nodes'].map { |attrs| Printavo::Customer.new(attrs) }
38
+ fetch_page(first: first, after: after).records
40
39
  end
41
40
 
42
41
  def find(id)
43
42
  data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
44
43
  Printavo::Customer.new(data['customer'])
45
44
  end
45
+
46
+ private
47
+
48
+ def fetch_page(first: 25, after: nil, **)
49
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
50
+ nodes = data['customers']['nodes'].map { |attrs| Printavo::Customer.new(attrs) }
51
+ page_info = data['customers']['pageInfo']
52
+ Printavo::Page.new(
53
+ records: nodes,
54
+ has_next_page: page_info['hasNextPage'],
55
+ end_cursor: page_info['endCursor']
56
+ )
57
+ end
46
58
  end
47
59
  end
48
60
  end
@@ -53,14 +53,26 @@ module Printavo
53
53
  GQL
54
54
 
55
55
  def all(first: 25, after: nil)
56
- data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
57
- data['inquiries']['nodes'].map { |attrs| Printavo::Inquiry.new(attrs) }
56
+ fetch_page(first: first, after: after).records
58
57
  end
59
58
 
60
59
  def find(id)
61
60
  data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
62
61
  Printavo::Inquiry.new(data['inquiry'])
63
62
  end
63
+
64
+ private
65
+
66
+ def fetch_page(first: 25, after: nil, **)
67
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
68
+ nodes = data['inquiries']['nodes'].map { |attrs| Printavo::Inquiry.new(attrs) }
69
+ page_info = data['inquiries']['pageInfo']
70
+ Printavo::Page.new(
71
+ records: nodes,
72
+ has_next_page: page_info['hasNextPage'],
73
+ end_cursor: page_info['endCursor']
74
+ )
75
+ end
64
76
  end
65
77
  end
66
78
  end
@@ -35,14 +35,29 @@ module Printavo
35
35
  GQL
36
36
 
37
37
  def all(order_id:, first: 25, after: nil)
38
- data = @graphql.query(ALL_QUERY, variables: { orderId: order_id.to_s, first: first, after: after })
39
- data['order']['lineItems']['nodes'].map { |attrs| Printavo::Job.new(attrs) }
38
+ fetch_page(order_id: order_id, first: first, after: after).records
40
39
  end
41
40
 
42
41
  def find(id)
43
42
  data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
44
43
  Printavo::Job.new(data['lineItem'])
45
44
  end
45
+
46
+ private
47
+
48
+ def fetch_page(order_id:, first: 25, after: nil, **)
49
+ data = @graphql.query(
50
+ ALL_QUERY,
51
+ variables: { orderId: order_id.to_s, first: first, after: after }
52
+ )
53
+ nodes = data['order']['lineItems']['nodes'].map { |attrs| Printavo::Job.new(attrs) }
54
+ page_info = data['order']['lineItems']['pageInfo']
55
+ Printavo::Page.new(
56
+ records: nodes,
57
+ has_next_page: page_info['hasNextPage'],
58
+ end_cursor: page_info['endCursor']
59
+ )
60
+ end
46
61
  end
47
62
  end
48
63
  end
@@ -39,6 +39,7 @@ module Printavo
39
39
  status {
40
40
  id
41
41
  name
42
+ color
42
43
  }
43
44
  customer {
44
45
  id
@@ -52,14 +53,26 @@ module Printavo
52
53
  GQL
53
54
 
54
55
  def all(first: 25, after: nil)
55
- data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
56
- data['orders']['nodes'].map { |attrs| Printavo::Order.new(attrs) }
56
+ fetch_page(first: first, after: after).records
57
57
  end
58
58
 
59
59
  def find(id)
60
60
  data = @graphql.query(FIND_QUERY, variables: { id: id.to_s })
61
61
  Printavo::Order.new(data['order'])
62
62
  end
63
+
64
+ private
65
+
66
+ def fetch_page(first: 25, after: nil, **)
67
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
68
+ nodes = data['orders']['nodes'].map { |attrs| Printavo::Order.new(attrs) }
69
+ page_info = data['orders']['pageInfo']
70
+ Printavo::Page.new(
71
+ records: nodes,
72
+ has_next_page: page_info['hasNextPage'],
73
+ end_cursor: page_info['endCursor']
74
+ )
75
+ end
63
76
  end
64
77
  end
65
78
  end
@@ -29,8 +29,7 @@ module Printavo
29
29
  GQL
30
30
 
31
31
  def all(first: 100, after: nil)
32
- data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
33
- data['statuses']['nodes'].map { |attrs| Printavo::Status.new(attrs) }
32
+ fetch_page(first: first, after: after).records
34
33
  end
35
34
 
36
35
  def find(id)
@@ -45,6 +44,19 @@ module Printavo
45
44
  def registry
46
45
  all.to_h { |status| [status.key, status] }
47
46
  end
47
+
48
+ private
49
+
50
+ def fetch_page(first: 100, after: nil, **)
51
+ data = @graphql.query(ALL_QUERY, variables: { first: first, after: after })
52
+ nodes = data['statuses']['nodes'].map { |attrs| Printavo::Status.new(attrs) }
53
+ page_info = data['statuses']['pageInfo']
54
+ Printavo::Page.new(
55
+ records: nodes,
56
+ has_next_page: page_info['hasNextPage'],
57
+ end_cursor: page_info['endCursor']
58
+ )
59
+ end
48
60
  end
49
61
  end
50
62
  end
@@ -1,4 +1,4 @@
1
1
  # lib/printavo/version.rb
2
2
  module Printavo
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
  end
data/lib/printavo.rb CHANGED
@@ -8,6 +8,7 @@ require_relative 'printavo/errors'
8
8
  require_relative 'printavo/config'
9
9
  require_relative 'printavo/connection'
10
10
  require_relative 'printavo/graphql_client'
11
+ require_relative 'printavo/page'
11
12
  require_relative 'printavo/models/base'
12
13
  require_relative 'printavo/models/customer'
13
14
  require_relative 'printavo/models/status'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: printavo-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stan Carver II
@@ -277,6 +277,7 @@ files:
277
277
  - lib/printavo/models/job.rb
278
278
  - lib/printavo/models/order.rb
279
279
  - lib/printavo/models/status.rb
280
+ - lib/printavo/page.rb
280
281
  - lib/printavo/resources/base.rb
281
282
  - lib/printavo/resources/customers.rb
282
283
  - lib/printavo/resources/inquiries.rb