Class: ChronoModel::Adapter
- Inherits:
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
- Object
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
- ChronoModel::Adapter
- Includes:
- DDL, Indexes, Migrations, Upgrade
- Defined in:
- lib/chrono_model/adapter.rb,
lib/chrono_model/adapter/ddl.rb,
lib/chrono_model/adapter/indexes.rb,
lib/chrono_model/adapter/upgrade.rb,
lib/chrono_model/adapter/migrations.rb,
lib/chrono_model/adapter/migrations_modules/stable.rb
Overview
This class implements all ActiveRecord::ConnectionAdapters::SchemaStatements methods adding support for temporal extensions. It inherits from the Postgres adapter for a clean override of its methods using super.
Defined Under Namespace
Modules: DDL, Indexes, Migrations, MigrationsModules, Upgrade
Constant Summary collapse
- TEMPORAL_SCHEMA =
The schema holding current data
'temporal'- HISTORY_SCHEMA =
The schema holding historical data
'history'
Instance Method Summary collapse
-
#chrono_metadata_for(view_name) ⇒ Object
Reads the Gem metadata from the COMMENT set on the given PostgreSQL view name.
-
#chrono_metadata_set(view_name, metadata) ⇒ Object
Writes Gem metadata on the COMMENT field in the given VIEW name.
- #chrono_setup! ⇒ Object
-
#chrono_supported? ⇒ Boolean
Returns true whether the connection adapter supports our implementation of temporal tables.
-
#column_definitions(table_name) ⇒ Object
Runs column_definitions in the temporal schema, as the table there defined is the source for this information.
-
#initialize ⇒ Adapter
constructor
A new instance of Adapter.
-
#is_chrono?(table) ⇒ Boolean
Returns true if the given name references a temporal table.
-
#on_history_schema(&block) ⇒ Object
Evaluates the given block in the history schema.
-
#on_schema(schema, recurse: :follow) ⇒ Object
Evaluates the given block in the given
schemasearch path. -
#on_temporal_schema(&block) ⇒ Object
Evaluates the given block in the temporal schema.
-
#primary_key(table_name) ⇒ Object
Runs primary_key, indexes and default_sequence_name in the temporal schema, as the table there defined is the source for this information.
- #valid_table_definition_options ⇒ Object
Methods included from Upgrade
Methods included from Indexes
#add_temporal_indexes, #add_timeline_consistency_constraint, #remove_temporal_indexes, #remove_timeline_consistency_constraint, #timeline_consistency_constraint_name
Methods included from Migrations
#add_column, #change_column, #change_column_default, #change_column_null, #change_table, #create_table, #drop_table, #remove_column, #rename_column, #rename_table
Methods included from MigrationsModules::Stable
Constructor Details
#initialize ⇒ Adapter
Returns a new instance of Adapter.
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/chrono_model/adapter.rb', line 30 def initialize(*) super connect! unless chrono_supported? raise ChronoModel::Error, 'Your database server is not supported by ChronoModel. ' \ 'Currently, only PostgreSQL >= 9.3 is supported.' end chrono_setup! end |
Instance Method Details
#chrono_metadata_for(view_name) ⇒ Object
Reads the Gem metadata from the COMMENT set on the given PostgreSQL view name.
154 155 156 157 158 159 160 161 |
# File 'lib/chrono_model/adapter.rb', line 154 def (view_name) comment = select_value( "SELECT obj_description(#{quote(view_name)}::regclass)", "ChronoModel metadata for #{view_name}" ) if data_source_exists?(view_name) MultiJson.load(comment || '{}').with_indifferent_access end |
#chrono_metadata_set(view_name, metadata) ⇒ Object
Writes Gem metadata on the COMMENT field in the given VIEW name.
165 166 167 168 169 |
# File 'lib/chrono_model/adapter.rb', line 165 def (view_name, ) comment = MultiJson.dump() execute "COMMENT ON VIEW #{view_name} IS #{quote(comment)}" end |
#chrono_setup! ⇒ Object
53 54 55 56 57 |
# File 'lib/chrono_model/adapter.rb', line 53 def chrono_setup! chrono_ensure_schemas chrono_upgrade_warning end |
#chrono_supported? ⇒ Boolean
Returns true whether the connection adapter supports our
implementation of temporal tables. Currently, Chronomodel
is supported starting with PostgreSQL 9.3 (90300 in PostgreSQL's
PG_VERSION_NUM numeric format).
49 50 51 |
# File 'lib/chrono_model/adapter.rb', line 49 def chrono_supported? postgresql_version >= 90300 # rubocop:disable Style/NumericLiterals end |
#column_definitions(table_name) ⇒ Object
Runs column_definitions in the temporal schema, as the table there defined is the source for this information.
The default search path is included however, since the table may reference types defined in other schemas, which result in their names becoming schema qualified, which will cause type resolutions to fail.
90 91 92 93 94 |
# File 'lib/chrono_model/adapter.rb', line 90 def column_definitions(table_name) return super unless is_chrono?(table_name) on_schema("#{TEMPORAL_SCHEMA},#{schema_search_path}", recurse: :ignore) { super } end |
#is_chrono?(table) ⇒ Boolean
Returns true if the given name references a temporal table.
146 147 148 149 |
# File 'lib/chrono_model/adapter.rb', line 146 def is_chrono?(table) on_temporal_schema { data_source_exists?(table) } && on_history_schema { data_source_exists?(table) } end |
#on_history_schema(&block) ⇒ Object
Evaluates the given block in the history schema.
104 105 106 |
# File 'lib/chrono_model/adapter.rb', line 104 def on_history_schema(&block) on_schema(HISTORY_SCHEMA, &block) end |
#on_schema(schema, recurse: :follow) ⇒ Object
Evaluates the given block in the given schema search path.
Recursion works by saving the old_path the function closure at each recursive call.
See specs for examples and behaviour.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/chrono_model/adapter.rb', line 115 def on_schema(schema, recurse: :follow) old_path = schema_search_path count_recursions do if (recurse == :follow) || (Thread.current['recursions'] == 1) self.schema_search_path = schema end yield end ensure # If the transaction is aborted, any execute() call will raise # "transaction is aborted errors" - thus calling the Adapter's # setter won't update the memoized variable. # # Here we reset it to +nil+ to refresh it on the next call, as # there is no way to know which path will be restored when the # transaction ends. # transaction_aborted = chrono_connection.transaction_status == PG::Connection::PQTRANS_INERROR if transaction_aborted && Thread.current['recursions'] == 1 @schema_search_path = nil else self.schema_search_path = old_path end end |
#on_temporal_schema(&block) ⇒ Object
Evaluates the given block in the temporal schema.
98 99 100 |
# File 'lib/chrono_model/adapter.rb', line 98 def on_temporal_schema(&block) on_schema(TEMPORAL_SCHEMA, &block) end |
#primary_key(table_name) ⇒ Object
Runs primary_key, indexes and default_sequence_name in the temporal schema, as the table there defined is the source for this information.
Moreover, the PostgreSQLAdapter indexes method uses
current_schema(), thus this is the only (and cleanest) way to
make injection work.
Schema nesting is disabled on these calls, make sure to fetch metadata from the first caller's selected schema and not from the current one.
NOTE: These methods are dynamically defined, see the source.
73 |
# File 'lib/chrono_model/adapter.rb', line 73 def primary_key(table_name); end |
#valid_table_definition_options ⇒ Object
171 172 173 |
# File 'lib/chrono_model/adapter.rb', line 171 def super + %i[temporal journal no_journal full_journal] end |