Class: SecApi::Collections::Filings
- Inherits:
-
Object
- Object
- SecApi::Collections::Filings
- Includes:
- Enumerable
- Defined in:
- lib/sec_api/collections/filings.rb
Overview
A collection of SEC filings with Enumerable support and pagination.
Pagination Design (Architecture ADR-6): Uses cursor-based pagination via “from” offset rather than page numbers. Why cursor-based? More efficient for large datasets - the server doesn’t need to calculate page boundaries, and the client can stop early without fetching unnecessary data. Supports both manual (fetch_next_page) and automatic (auto_paginate) iteration patterns.
Filings collections are returned from query operations and support iteration, pagination metadata, total count from API response, and fetching subsequent pages of results.
Instance Attribute Summary collapse
-
#next_cursor ⇒ Integer
readonly
Offset position for fetching next page of results.
-
#total_count ⇒ Object
readonly
Returns the value of attribute total_count.
Instance Method Summary collapse
-
#auto_paginate ⇒ Enumerator::Lazy
Returns a lazy enumerator that automatically paginates through all results.
-
#count(*args, &block) ⇒ Object
Returns total count of results from API metadata, or delegates to Enumerable#count when filtering.
-
#each {|filing| ... } ⇒ Enumerator
Yields each Filing to the block.
-
#fetch_next_page ⇒ Filings
Fetch the next page of results.
-
#filings ⇒ Array<Objects::Filing>
Returns the array of Filing objects.
-
#has_more? ⇒ Boolean
Returns true if more pages of results are available.
-
#initialize(data, client: nil, query_context: nil) ⇒ Filings
constructor
Initialize a new Filings collection.
Constructor Details
#initialize(data, client: nil, query_context: nil) ⇒ Filings
Initialize a new Filings collection.
53 54 55 56 57 58 59 60 |
# File 'lib/sec_api/collections/filings.rb', line 53 def initialize(data, client: nil, query_context: nil) @_data = data @_client = client @_query_context = query_context build_objects freeze_collection end |
Instance Attribute Details
#next_cursor ⇒ Integer (readonly)
Returns offset position for fetching next page of results.
46 47 48 |
# File 'lib/sec_api/collections/filings.rb', line 46 def next_cursor @next_cursor end |
#total_count ⇒ Object (readonly)
Returns the value of attribute total_count.
46 |
# File 'lib/sec_api/collections/filings.rb', line 46 attr_reader :next_cursor, :total_count |
Instance Method Details
#auto_paginate ⇒ Enumerator::Lazy
Memory Efficiency: Only the current page is held in memory. Previous pages become eligible for garbage collection as iteration proceeds.
Retry Behavior: Transient errors (503, timeouts) during page fetches are automatically retried by the middleware. Permanent errors (401, 404) will be raised to the caller.
Returns a lazy enumerator that automatically paginates through all results.
Memory Efficiency Design: Why Enumerator::Lazy? For backfill operations with 100k+ results, we can’t load all filings into memory. Lazy enumeration fetches pages on-demand:
-
Only current page in memory (~50 filings)
-
Previous pages become GC-eligible as we iterate
-
Early termination via .take(N) avoids fetching unnecessary pages
-
Enumerable chaining (.select, .map) works naturally
Each iteration yields a single Objects::Filing object. Pages are fetched on-demand as the enumerator is consumed, keeping memory usage constant regardless of total result count. Only the current page is held in memory; previous pages become eligible for garbage collection as iteration proceeds.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/sec_api/collections/filings.rb', line 181 def auto_paginate raise PaginationError, "Cannot paginate without client reference" if @_client.nil? Enumerator.new do |yielder| current_page = self loop do # Yield each filing from current page current_page.each { |filing| yielder << filing } # Stop if no more pages break unless current_page.has_more? # Fetch next page (becomes new current, old page eligible for GC) next_page = current_page.fetch_next_page # Guard against infinite loop if API returns empty page mid-pagination # (defensive coding against API misbehavior) break if next_page.to_a.empty? && current_page.next_cursor == next_page.next_cursor current_page = next_page end end.lazy end |
#count ⇒ Integer #count(item) ⇒ Integer #count {|filing| ... } ⇒ Integer
When filtering, only filings in the current page are counted. For total filtered count across all pages, use auto_paginate.
Returns total count of results from API metadata, or delegates to Enumerable#count when filtering.
When called without arguments, returns the total number of matching filings across all pages (from API metadata), not just the count of filings in the current page.
When called with a block or argument, delegates to Enumerable#count to count filings in the current page matching the condition.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/sec_api/collections/filings.rb', line 111 def count(*args, &block) if block || args.any? super else case @total_count when Hash @total_count[:value] || @total_count["value"] || @objects.size when Integer @total_count else @objects.size end end end |
#each {|filing| ... } ⇒ Enumerator
Yields each Filing to the block. Required for Enumerable support.
75 76 77 |
# File 'lib/sec_api/collections/filings.rb', line 75 def each(&block) @objects.each(&block) end |
#fetch_next_page ⇒ Filings
Fetch the next page of results.
Makes an API request using the stored query context with the next cursor offset. Returns a new immutable Filings collection containing the next page of results.
221 222 223 224 225 226 227 |
# File 'lib/sec_api/collections/filings.rb', line 221 def fetch_next_page raise PaginationError, "No more pages available" unless has_more? payload = @_query_context.merge(from: @next_cursor.to_s) response = @_client.connection.post("/", payload) Filings.new(response.body, client: @_client, query_context: @_query_context) end |
#filings ⇒ Array<Objects::Filing>
Returns the array of Filing objects.
65 66 67 |
# File 'lib/sec_api/collections/filings.rb', line 65 def filings @objects end |
#has_more? ⇒ Boolean
Returns true if more pages of results are available.
More pages are available when:
-
A client reference exists (pagination requires API access)
-
The next_cursor is less than the total count
133 134 135 136 |
# File 'lib/sec_api/collections/filings.rb', line 133 def has_more? return false if @_client.nil? @next_cursor < extract_total_value end |