Module: ActiveRecord::Materialized::ViewQueryAccessClassMethods::ClassMethods
- Defined in:
- lib/activerecord/materialized/view_query_access_class_methods.rb
Overview
The read and refresh methods available on a ActiveRecord::Materialized::View subclass.
Instance Method Summary collapse
- #all(*args) ⇒ Object
- #count(*args) ⇒ Object
-
#dirty? ⇒ Boolean
Whether dependency writes have marked the view dirty since its last refresh.
- #find(*args) ⇒ Object
- #find_by(*args) ⇒ Object
- #find_each(*args, **opts, &block) ⇒ Object
- #find_in_batches(*args, **opts, &block) ⇒ Object
-
#ids(*args) ⇒ Object
idsand batch iteration (+find_each+/+find_in_batches+/+in_batches+) are defined in terms of the primary key:idsplucks it, and batching cursors on it and requires the cursor to be a unique column. -
#implicit_order_column ⇒ Array, Object
Order-dependent finders (+first+,
last,second, …) fall back to an implicitORDER BY <primary key>when the relation carries no order. - #in_batches(*args, **opts, &block) ⇒ Object
-
#last_refreshed_at ⇒ Time?
When the view was last refreshed, or
nilif it never has been. - #mark_dependencies_changed! ⇒ Object
-
#materialized? ⇒ Boolean
Reads are served from the cache only once warmed and the table exists; otherwise they fall through to the cold-read path.
-
#rebuild!(confirm: false) ⇒ RefreshResult
The only path that scans all base data;
confirm:guards against firing a full materialization by accident. -
#reconcile!(mode: :checksum, sample: nil) ⇒ ReconcileResult
Verify this view's contents against its source and repair any drift with scoped maintenance (never a full rebuild).
-
#refresh! ⇒ RefreshResult
Incremental maintenance only — never scans all base data.
-
#refresh_if_stale! ⇒ RefreshResult?
Refreshes the view only when it is materialized and stale; otherwise a no-op.
-
#refreshing? ⇒ Boolean
Whether a refresh is currently in progress for the view.
-
#source_watermark ⇒ Integer?
The oldest applied CDC source watermark across the view's partitions — its most-behind partition — or
nilif no watermarked change has been ingested (see SourceWatermark). -
#stale? ⇒ Boolean
Whether the view needs refreshing — dirty, never refreshed, or past its
max_staleness. - #table_exists? ⇒ Boolean
- #view_class ⇒ Object
-
#warm? ⇒ Boolean
Whether the view has been fully materialized; cold views are served read-through.
- #where(*args) ⇒ Object
Instance Method Details
#all(*args) ⇒ Object
121 122 123 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 121 def all(*args) read_router.scope.all(*args) end |
#count(*args) ⇒ Object
137 138 139 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 137 def count(*args) read_router.scope.count(*args) end |
#dirty? ⇒ Boolean
Whether dependency writes have marked the view dirty since its last refresh.
31 32 33 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 31 def dirty? view_class..dirty? end |
#find(*args) ⇒ Object
129 130 131 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 129 def find(*args) read_router.scope.find(*args) end |
#find_by(*args) ⇒ Object
133 134 135 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 133 def find_by(*args) read_router.partition_scope(args).find_by(*args) end |
#find_each(*args, **opts, &block) ⇒ Object
170 171 172 173 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 170 def find_each(*args, **opts, &block) require_materialized!(:find_each) super end |
#find_in_batches(*args, **opts, &block) ⇒ Object
175 176 177 178 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 175 def find_in_batches(*args, **opts, &block) require_materialized!(:find_in_batches) super end |
#ids(*args) ⇒ Object
ids and batch iteration (+find_each+/+find_in_batches+/+in_batches+) are defined in terms
of the primary key: ids plucks it, and batching cursors on it and requires the cursor to be
a unique column. A cold view's read-through derived table has no id (and no index to make a
group-key cursor unique), so none of these can be served correctly — a warm, materialized
cache table is required. Refuse with a clear, actionable error rather than emitting the
cryptic "no such column: id" the underlying query would raise.
165 166 167 168 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 165 def ids(*args) require_materialized!(:ids) super end |
#implicit_order_column ⇒ Array, Object
Order-dependent finders (+first+, last, second, …) fall back to an implicit
ORDER BY <primary key> when the relation carries no order. A cold view reads through to
the source as a derived table with no id column, so that implicit order references a
column that does not exist and the query blows up. Order by the GROUP BY key(s) instead —
they exist on both the cold derived table and the warm cache — and the trailing nil tells
ActiveRecord's _order_columns to use only these columns and NOT append the primary key.
A non-grouped view has no such key, so it keeps the default primary-key behavior.
The keys are unqualified (a dotted GROUP BY like "items.category" maps to the projected
category on the cache/derived table), matching how ActiveRecord::Materialized::ViewDefinition and CacheTableSchema
resolve them — a qualified name would reference a column neither table has, on warm and cold.
154 155 156 157 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 154 def implicit_order_column keys = maintenance_key_columns.map { |key| key.rpartition(".").last } keys.any? ? [*keys, nil] : super end |
#in_batches(*args, **opts, &block) ⇒ Object
180 181 182 183 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 180 def in_batches(*args, **opts, &block) require_materialized!(:in_batches) super end |
#last_refreshed_at ⇒ Time?
When the view was last refreshed, or nil if it never has been.
53 54 55 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 53 def last_refreshed_at view_class..last_refreshed_at end |
#mark_dependencies_changed! ⇒ Object
74 75 76 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 74 def mark_dependencies_changed! view_class..mark_dirty! end |
#materialized? ⇒ Boolean
Reads are served from the cache only once warmed and the table exists; otherwise they fall through to the cold-read path.
46 47 48 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 46 def materialized? view_class.table_exists? && view_class..warm? end |
#rebuild!(confirm: false) ⇒ RefreshResult
The only path that scans all base data; confirm: guards against
firing a full materialization by accident.
112 113 114 115 116 117 118 119 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 112 def rebuild!(confirm: false) unless confirm Kernel.raise ArgumentError, "#{view_class.name}.rebuild! performs a full materialization; call rebuild!(confirm: true)" end Refresher.new(view_class).rebuild! end |
#reconcile!(mode: :checksum, sample: nil) ⇒ ReconcileResult
Verify this view's contents against its source and repair any drift with scoped maintenance (never a full rebuild). See Reconciler.
102 103 104 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 102 def reconcile!(mode: :checksum, sample: nil) Reconciler.new(view_class, mode: mode, sample: sample).reconcile! end |
#refresh! ⇒ RefreshResult
Incremental maintenance only — never scans all base data.
85 86 87 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 85 def refresh! Refresher.new(view_class).refresh! end |
#refresh_if_stale! ⇒ RefreshResult?
Refreshes the view only when it is materialized and stale; otherwise a no-op.
92 93 94 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 92 def refresh_if_stale! refresh! if materialized? && stale? end |
#refreshing? ⇒ Boolean
Whether a refresh is currently in progress for the view.
70 71 72 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 70 def refreshing? view_class..refreshing? end |
#source_watermark ⇒ Integer?
The oldest applied CDC source watermark across the view's partitions — its most-behind
partition — or nil if no watermarked change has been ingested (see SourceWatermark).
Subtract from your source clock (same unit as the source_ts you pass ActiveRecord::Materialized.ingest_change)
to get the view's freshness/lag.
63 64 65 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 63 def source_watermark SourceWatermark.new(view_class).oldest end |
#stale? ⇒ Boolean
Whether the view needs refreshing — dirty, never refreshed, or past its max_staleness.
24 25 26 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 24 def stale? view_class..stale? end |
#table_exists? ⇒ Boolean
78 79 80 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 78 def table_exists? view_class.connection.data_source_exists?(view_class.table_name) end |
#view_class ⇒ Object
17 18 19 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 17 def view_class self end |
#warm? ⇒ Boolean
Whether the view has been fully materialized; cold views are served read-through.
38 39 40 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 38 def warm? view_class..warm? end |
#where(*args) ⇒ Object
125 126 127 |
# File 'lib/activerecord/materialized/view_query_access_class_methods.rb', line 125 def where(*args) read_router.partition_scope(args).where(*args) end |