Class: ActiveShopifyGraphQL::Query::Scope

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/active_shopify_graphql/query/scope.rb

Overview

A chainable query builder that accumulates query configuration and executes the query when records are accessed.

Examples:

Basic usage

ProductVariant.where(sku: "*").limit(100).to_a

Pagination with block

ProductVariant.where(sku: "*").in_pages(of: 50) do |page|
  process_batch(page)
end

Manual pagination

page = ProductVariant.where(sku: "*").in_pages(of: 50)
page.each { |record| process(record) }
page = page.next_page while page.has_next_page?

Constant Summary collapse

DEFAULT_PER_PAGE =
250

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_class, conditions: {}, loader: nil, total_limit: nil, per_page: DEFAULT_PER_PAGE) ⇒ Scope

Returns a new instance of Scope.



27
28
29
30
31
32
33
34
35
# File 'lib/active_shopify_graphql/query/scope.rb', line 27

def initialize(model_class, conditions: {}, loader: nil, total_limit: nil, per_page: DEFAULT_PER_PAGE)
  @model_class = model_class
  @conditions = conditions
  @loader = loader
  @total_limit = total_limit
  @per_page = [per_page, ActiveShopifyGraphQL.configuration.max_objects_per_paginated_query].min
  @loaded = false
  @records = nil
end

Instance Attribute Details

#conditionsObject (readonly)

Returns the value of attribute conditions.



25
26
27
# File 'lib/active_shopify_graphql/query/scope.rb', line 25

def conditions
  @conditions
end

#model_classObject (readonly)

Returns the value of attribute model_class.



25
26
27
# File 'lib/active_shopify_graphql/query/scope.rb', line 25

def model_class
  @model_class
end

#per_pageObject (readonly)

Returns the value of attribute per_page.



25
26
27
# File 'lib/active_shopify_graphql/query/scope.rb', line 25

def per_page
  @per_page
end

#total_limitObject (readonly)

Returns the value of attribute total_limit.



25
26
27
# File 'lib/active_shopify_graphql/query/scope.rb', line 25

def total_limit
  @total_limit
end

Instance Method Details

#[](index) ⇒ Object

Array-like access



159
160
161
# File 'lib/active_shopify_graphql/query/scope.rb', line 159

def [](index)
  to_a[index]
end

#countInteger

Count records (loads all pages, use with caution)

Returns:

  • (Integer)


154
155
156
# File 'lib/active_shopify_graphql/query/scope.rb', line 154

def count
  to_a.count
end

#each {|Object| ... } ⇒ Object

Iterate through all records across all pages

Yields:

  • (Object)

    Each record



97
98
99
100
101
102
103
# File 'lib/active_shopify_graphql/query/scope.rb', line 97

def each(&block)
  return to_enum(:each) unless block_given?

  each_page do |page|
    page.each(&block)
  end
end

#each_page {|PaginatedResult| ... } ⇒ Object

Iterate through all pages, yielding each page

Yields:

  • (PaginatedResult)

    Each page of results



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/active_shopify_graphql/query/scope.rb', line 62

def each_page
  current_page = fetch_first_page
  records_yielded = 0

  loop do
    break if current_page.empty?

    # Apply total limit if set
    if @total_limit
      remaining = @total_limit - records_yielded
      break if remaining <= 0

      if current_page.size > remaining
        # Trim the page to fit the limit
        trimmed_records = current_page.records.first(remaining)
        current_page = Response::PaginatedResult.new(
          records: trimmed_records,
          page_info: Response::PageInfo.new, # Empty page info to stop pagination
          query_scope: self
        )
      end
    end

    yield current_page
    records_yielded += current_page.size

    break unless current_page.has_next_page?
    break if @total_limit && records_yielded >= @total_limit

    current_page = current_page.next_page
  end
end

#empty?Boolean

Check if no records exist (Array compatibility)

Returns:

  • (Boolean)


141
142
143
# File 'lib/active_shopify_graphql/query/scope.rb', line 141

def empty?
  first(1).empty?
end

#exists?Boolean

Check if any records exist

Returns:

  • (Boolean)


135
136
137
# File 'lib/active_shopify_graphql/query/scope.rb', line 135

def exists?
  first(1).any?
end

#fetch_first_pagePaginatedResult

Fetch the first page of results

Returns:

  • (PaginatedResult)


189
190
191
# File 'lib/active_shopify_graphql/query/scope.rb', line 189

def fetch_first_page
  fetch_page
end

#fetch_page(after: nil, before: nil) ⇒ PaginatedResult

Fetch a specific page by cursor

Parameters:

  • after (String, nil) (defaults to: nil)

    Cursor to fetch records after

  • before (String, nil) (defaults to: nil)

    Cursor to fetch records before

Returns:

  • (PaginatedResult)


177
178
179
180
181
182
183
184
185
# File 'lib/active_shopify_graphql/query/scope.rb', line 177

def fetch_page(after: nil, before: nil)
  loader.load_paginated_collection(
    conditions: @conditions,
    per_page: effective_per_page,
    after: after,
    before: before,
    query_scope: self
  )
end

#first(count = nil) ⇒ Object, ...

Get first record

Parameters:

  • count (Integer, nil) (defaults to: nil)

    Number of records to return

Returns:

  • (Object, Array, nil)

    First record(s) or nil



123
124
125
126
127
128
129
130
131
# File 'lib/active_shopify_graphql/query/scope.rb', line 123

def first(count = nil)
  if count
    scoped = dup_with(total_limit: count, per_page: [count, max_objects_per_paginated_query].min)
    scoped.to_a
  else
    scoped = dup_with(total_limit: 1, per_page: 1)
    scoped.to_a.first
  end
end

#in_pages(of: DEFAULT_PER_PAGE) {|PaginatedResult| ... } ⇒ PaginatedResult, self

Configure pagination and optionally iterate through pages

Parameters:

  • of (Integer) (defaults to: DEFAULT_PER_PAGE)

    Number of records per page (default: 250, max: 250)

Yields:

  • (PaginatedResult)

    Each page of results

Returns:

  • (PaginatedResult, self)

    Returns PaginatedResult if no block given



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/active_shopify_graphql/query/scope.rb', line 48

def in_pages(of: DEFAULT_PER_PAGE, &block)
  page_size = [of, ActiveShopifyGraphQL.configuration.max_objects_per_paginated_query].min
  scoped = dup_with(per_page: page_size)

  if block_given?
    scoped.each_page(&block)
    self
  else
    scoped.fetch_first_page
  end
end

#limit(count) ⇒ Scope

Set a limit on total records to return

Parameters:

  • count (Integer)

    Maximum number of records to fetch across all pages

Returns:

  • (Scope)

    A new scope with the limit applied



40
41
42
# File 'lib/active_shopify_graphql/query/scope.rb', line 40

def limit(count)
  dup_with(total_limit: count)
end

#map(&block) ⇒ Object

Map over records (Array compatibility)



164
165
166
# File 'lib/active_shopify_graphql/query/scope.rb', line 164

def map(&block)
  to_a.map(&block)
end

#select_records(&block) ⇒ Object

Select/filter records (Array compatibility)



169
170
171
# File 'lib/active_shopify_graphql/query/scope.rb', line 169

def select_records(&block)
  to_a.select(&block)
end

#sizeInteger Also known as: length

Size/length of records (loads all pages, use with caution)

Returns:

  • (Integer)


147
148
149
# File 'lib/active_shopify_graphql/query/scope.rb', line 147

def size
  to_a.size
end

#to_aArray Also known as: load

Load all records respecting total_limit

Returns:

  • (Array)

    All records



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/active_shopify_graphql/query/scope.rb', line 107

def to_a
  return @records if @loaded

  all_records = []
  each_page do |page|
    all_records.concat(page.to_a)
  end
  @records = all_records
  @loaded = true
  @records
end