Showing preview only (567K chars total). Download the full file or copy to clipboard to get everything.
Repository: crashtech/torque-postgresql
Branch: master
Commit: c654b22bf46b
Files: 173
Total size: 520.9 KB
Directory structure:
gitextract_u1kant5h/
├── .circleci/
│ └── config.yml
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .rspec
├── Gemfile
├── MIT-LICENSE
├── README.md
├── README.rdoc
├── Rakefile
├── gemfiles/
│ └── Gemfile.rails-8.0
├── lib/
│ ├── generators/
│ │ └── torque/
│ │ ├── function_generator.rb
│ │ ├── templates/
│ │ │ ├── function.sql.erb
│ │ │ ├── type.sql.erb
│ │ │ └── view.sql.erb
│ │ ├── type_generator.rb
│ │ └── view_generator.rb
│ ├── torque/
│ │ ├── postgresql/
│ │ │ ├── adapter/
│ │ │ │ ├── database_statements.rb
│ │ │ │ ├── oid/
│ │ │ │ │ ├── array.rb
│ │ │ │ │ ├── box.rb
│ │ │ │ │ ├── circle.rb
│ │ │ │ │ ├── enum.rb
│ │ │ │ │ ├── enum_set.rb
│ │ │ │ │ ├── interval.rb
│ │ │ │ │ ├── line.rb
│ │ │ │ │ ├── range.rb
│ │ │ │ │ └── segment.rb
│ │ │ │ ├── oid.rb
│ │ │ │ ├── quoting.rb
│ │ │ │ ├── schema_creation.rb
│ │ │ │ ├── schema_definitions.rb
│ │ │ │ ├── schema_dumper.rb
│ │ │ │ ├── schema_overrides.rb
│ │ │ │ └── schema_statements.rb
│ │ │ ├── adapter.rb
│ │ │ ├── arel/
│ │ │ │ ├── infix_operation.rb
│ │ │ │ ├── join_source.rb
│ │ │ │ ├── nodes.rb
│ │ │ │ ├── operations.rb
│ │ │ │ ├── select_manager.rb
│ │ │ │ └── visitors.rb
│ │ │ ├── arel.rb
│ │ │ ├── associations/
│ │ │ │ ├── association_scope.rb
│ │ │ │ ├── belongs_to_many_association.rb
│ │ │ │ ├── builder/
│ │ │ │ │ ├── belongs_to_many.rb
│ │ │ │ │ └── has_many.rb
│ │ │ │ ├── builder.rb
│ │ │ │ ├── foreign_association.rb
│ │ │ │ ├── preloader/
│ │ │ │ │ ├── association.rb
│ │ │ │ │ └── loader_query.rb
│ │ │ │ └── preloader.rb
│ │ │ ├── associations.rb
│ │ │ ├── attributes/
│ │ │ │ ├── builder/
│ │ │ │ │ ├── enum.rb
│ │ │ │ │ ├── full_text_search.rb
│ │ │ │ │ └── period.rb
│ │ │ │ ├── builder.rb
│ │ │ │ ├── enum.rb
│ │ │ │ ├── enum_set.rb
│ │ │ │ ├── full_text_search.rb
│ │ │ │ ├── lazy.rb
│ │ │ │ └── period.rb
│ │ │ ├── attributes.rb
│ │ │ ├── autosave_association.rb
│ │ │ ├── auxiliary_statement/
│ │ │ │ ├── recursive.rb
│ │ │ │ └── settings.rb
│ │ │ ├── auxiliary_statement.rb
│ │ │ ├── base.rb
│ │ │ ├── collector.rb
│ │ │ ├── config.rb
│ │ │ ├── function.rb
│ │ │ ├── geometry_builder.rb
│ │ │ ├── i18n.rb
│ │ │ ├── inheritance.rb
│ │ │ ├── insert_all.rb
│ │ │ ├── migration/
│ │ │ │ └── command_recorder.rb
│ │ │ ├── migration.rb
│ │ │ ├── predicate_builder/
│ │ │ │ ├── arel_attribute_handler.rb
│ │ │ │ ├── array_handler.rb
│ │ │ │ ├── enumerator_lazy_handler.rb
│ │ │ │ └── regexp_handler.rb
│ │ │ ├── predicate_builder.rb
│ │ │ ├── railtie.rb
│ │ │ ├── reflection/
│ │ │ │ ├── abstract_reflection.rb
│ │ │ │ ├── association_reflection.rb
│ │ │ │ ├── belongs_to_many_reflection.rb
│ │ │ │ ├── has_many_reflection.rb
│ │ │ │ ├── runtime_reflection.rb
│ │ │ │ └── through_reflection.rb
│ │ │ ├── reflection.rb
│ │ │ ├── relation/
│ │ │ │ ├── auxiliary_statement.rb
│ │ │ │ ├── buckets.rb
│ │ │ │ ├── distinct_on.rb
│ │ │ │ ├── inheritance.rb
│ │ │ │ ├── join_series.rb
│ │ │ │ └── merger.rb
│ │ │ ├── relation.rb
│ │ │ ├── schema_cache/
│ │ │ │ ├── bound_schema_reflection.rb
│ │ │ │ ├── inheritance.rb
│ │ │ │ └── schema_reflection.rb
│ │ │ ├── schema_cache.rb
│ │ │ ├── table_name.rb
│ │ │ ├── version.rb
│ │ │ ├── versioned_commands/
│ │ │ │ ├── command_migration.rb
│ │ │ │ ├── generator.rb
│ │ │ │ ├── migration_context.rb
│ │ │ │ ├── migrator.rb
│ │ │ │ └── schema_table.rb
│ │ │ └── versioned_commands.rb
│ │ └── postgresql.rb
│ └── torque-postgresql.rb
├── spec/
│ ├── en.yml
│ ├── factories/
│ │ ├── authors.rb
│ │ ├── comments.rb
│ │ ├── item.rb
│ │ ├── posts.rb
│ │ ├── tags.rb
│ │ ├── texts.rb
│ │ ├── users.rb
│ │ └── videos.rb
│ ├── fixtures/
│ │ └── migrations/
│ │ ├── 20250101000001_create_users.rb
│ │ ├── 20250101000002_create_function_count_users_v1.sql
│ │ ├── 20250101000003_create_internal_users.rb
│ │ ├── 20250101000004_update_function_count_users_v2.sql
│ │ ├── 20250101000005_create_view_all_users_v1.sql
│ │ ├── 20250101000006_create_type_user_id_v1.sql
│ │ └── 20250101000007_remove_function_count_users_v2.sql
│ ├── initialize.rb
│ ├── mocks/
│ │ ├── cache_query.rb
│ │ └── create_table.rb
│ ├── models/
│ │ ├── activity.rb
│ │ ├── activity_book.rb
│ │ ├── activity_post/
│ │ │ └── sample.rb
│ │ ├── activity_post.rb
│ │ ├── author.rb
│ │ ├── author_journalist.rb
│ │ ├── category.rb
│ │ ├── comment.rb
│ │ ├── course.rb
│ │ ├── geometry.rb
│ │ ├── guest_comment.rb
│ │ ├── internal/
│ │ │ └── user.rb
│ │ ├── item.rb
│ │ ├── post.rb
│ │ ├── question.rb
│ │ ├── question_select.rb
│ │ ├── tag.rb
│ │ ├── text.rb
│ │ ├── time_keeper.rb
│ │ ├── user.rb
│ │ └── video.rb
│ ├── schema.rb
│ ├── spec_helper.rb
│ └── tests/
│ ├── arel_spec.rb
│ ├── auxiliary_statement_spec.rb
│ ├── belongs_to_many_spec.rb
│ ├── collector_spec.rb
│ ├── distinct_on_spec.rb
│ ├── enum_set_spec.rb
│ ├── enum_spec.rb
│ ├── full_text_seach_test.rb
│ ├── function_spec.rb
│ ├── geometric_builder_spec.rb
│ ├── has_many_spec.rb
│ ├── insert_all_spec.rb
│ ├── interval_spec.rb
│ ├── lazy_spec.rb
│ ├── period_spec.rb
│ ├── predicate_builder_spec.rb
│ ├── quoting_spec.rb
│ ├── relation_spec.rb
│ ├── schema_spec.rb
│ ├── table_inheritance_spec.rb
│ └── versioned_commands_spec.rb
└── torque_postgresql.gemspec
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
version: 2.1
orbs:
ruby: circleci/ruby@1.4.0
jobs:
test:
parallelism: 3
parameters:
ruby-version:
type: string
bundle-version:
type: string
docker:
- image: cimg/ruby:<< parameters.ruby-version >>
- image: cimg/postgres:14.6
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: torque
POSTGRES_DB: torque_postgresql
steps:
- checkout
- run: ruby --version
- run:
command: 'bundle install --gemfile gemfiles/<< parameters.bundle-version >>'
name: Install Bundle
- run:
command: dockerize -wait tcp://localhost:5432 -timeout 1m
name: Wait for DB
- run:
command: 'bundle exec --gemfile gemfiles/<< parameters.bundle-version >> rspec'
name: Run Tests
environment:
DATABASE_URL: 'postgresql://postgres:torque@localhost/torque_postgresql'
references:
matrix_build: &matrix_build
test:
matrix:
parameters:
ruby-version: ['3.2', '3.3', '3.4']
bundle-version: ['Gemfile.rails-8.0']
workflows:
commit:
jobs:
- <<: *matrix_build
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: ['crashtech']
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# polar: # Replace with a single Polar username
# buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
# thanks_dev: # Replace with a single thanks.dev username
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .gitignore
================================================
.env
*.gem
*.rbc
.bundle
.config
.yardoc
.byebug_history
.versions.conf
Gemfile.lock
coverage
doc/
.config
coverage/
InstalledFiles
pkg/
rdoc/
spec/reports/
spec/examples.txt
test/tmp/
test/version_tmp/
tmp/
bin/
.ruby-version
.ruby-gemset
gemfiles/*.lock
================================================
FILE: .rspec
================================================
--color
--require spec_helper
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
# Declare your gem's dependencies in torque_postgresql.gemspec.
# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.
gemspec
# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
# your gem to rubygems.org.
# To use a debugger
gem 'debug'
# Optional dependencies
gem 'annotate'
================================================
FILE: MIT-LICENSE
================================================
Copyright 2016 Carlos Silva
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
<a href="https://github.com/crashtech/torque-postgresql">
<img src="./docs/assets/images/github.png" alt="Torque PostgreSQL - Advanced PG features in a seamlessly RoR interface" />
</a>
[](https://circleci.com/gh/crashtech/torque-postgresql/tree/master)
[](https://codeclimate.com/github/crashtech/torque-postgresql)
[](https://badge.fury.io/rb/torque-postgresql)
<!--([](https://codeclimate.com/github/crashtech/torque-postgresql/coverage))-->
<!--([](https://gemnasium.com/github.com/crashtech/torque-postgresql))-->
* [Wiki](https://github.com/crashtech/torque-postgresql/wiki)
* [Bugs](https://github.com/crashtech/torque-postgresql/issues)
* [TODO](https://github.com/crashtech/torque-postgresql/wiki/TODO)
# Description
`torque-postgresql` is a plugin that enhances Ruby on Rails enabling easy access to existing PostgreSQL advanced resources, such as data types and query statements. Its features are designed to be similar to Rails architecture and work as smoothly as possible.
Fully compatible with `schema.rb` and 100% plug-and-play, with optional configurations, so that it can be adapted to your project's design pattern.
# Installation
To install torque-postgresql you need to add the following to your Gemfile:
```ruby
gem 'torque-postgresql', '~> 2.0' # For Rails >= 6.0 < 6.1
gem 'torque-postgresql', '~> 2.0.4' # For Rails >= 6.1
gem 'torque-postgresql', '~> 3.0' # For Rails >= 7.0 < 7.1
gem 'torque-postgresql', '~> 3.3' # For Rails >= 7.1 < 7.2
gem 'torque-postgresql', '~> 3.4' # For Rails >= 7.2 < 8.0
gem 'torque-postgresql', '~> 4.0' # For Rails >= 8.0
```
Also, run:
```
$ bundle
```
Or, for non-Gemfile related usage, simply:
```
gem install torque-postgresql
```
# Usage
These are the currently available features:
* [Configuring](https://github.com/crashtech/torque-postgresql/wiki/Configuring)
## Data types
* [Box](https://github.com/crashtech/torque-postgresql/wiki/Box)
* [Circle](https://github.com/crashtech/torque-postgresql/wiki/Circle)
* [Date/Time Range](https://github.com/crashtech/torque-postgresql/wiki/Date-Time-Range)
* [Enum](https://github.com/crashtech/torque-postgresql/wiki/Enum)
* [EnumSet](https://github.com/crashtech/torque-postgresql/wiki/Enum-Set)
* [Interval](https://github.com/crashtech/torque-postgresql/wiki/Interval)
* [Line](https://github.com/crashtech/torque-postgresql/wiki/Line)
* [Segment](https://github.com/crashtech/torque-postgresql/wiki/Segment)
## Querying
* [Arel](https://github.com/crashtech/torque-postgresql/wiki/Arel)
* [Auxiliary Statements](https://github.com/crashtech/torque-postgresql/wiki/Auxiliary-Statements)
* [Belongs to Many](https://github.com/crashtech/torque-postgresql/wiki/Belongs-to-Many)
* [Distinct On](https://github.com/crashtech/torque-postgresql/wiki/Distinct-On)
* [Dynamic Attributes](https://github.com/crashtech/torque-postgresql/wiki/Dynamic-Attributes)
* [Has Many](https://github.com/crashtech/torque-postgresql/wiki/Has-Many)
* [Inherited Tables](https://github.com/crashtech/torque-postgresql/wiki/Inherited-Tables)
* [Insert All](https://github.com/crashtech/torque-postgresql/wiki/Insert-All)
* [Multiple Schemas](https://github.com/crashtech/torque-postgresql/wiki/Multiple-Schemas)
* [Predicate Builder](https://github.com/crashtech/torque-postgresql/wiki/Predicate-Builder)
* [Full‐Text Search](https://github.com/crashtech/torque-postgresql/wiki/Full‐Text-Search)
* [Join Series](https://github.com/crashtech/torque-postgresql/wiki/Join-Series)
* [Buckets](https://github.com/crashtech/torque-postgresql/wiki/Buckets)
* [Versioned Commands (Views, Functions, Types)](https://github.com/crashtech/torque-postgresql/wiki/Versioned-Commands)
# How to Contribute
To start, simply fork the project, create a `.env` file following this example:
```
DATABASE_URL="postgres://USER:PASSWORD@localhost/DATABASE"
```
Run local tests using:
```
$ bundle install
$ bundle exec rake spec
```
Finally, fix and send a pull request.
## License
Copyright © 2017- Carlos Silva. See [The MIT License](MIT-LICENSE) for further details.
================================================
FILE: README.rdoc
================================================
= Torque PostgreSQL -- Add support to complex resources of PostgreSQL, like data
types, user-defined types and auxiliary statements (CTE)
This is a plugin that enhance Ruby on Rails enabling easy access to existing
PostgreSQL advanced resources, such as data types and queries statements. Its
features are design to be as similar as Rails architecture and they work as
smooth as possible.
100% plug-and-play, with optional configurations so that can be adapted to
your's project design pattern.
A short rundown of some of the major features:
* Enum type manager
It creates a separated class to hold each enum set that can be used by multiple
models, it also keeps the database consistent. The enum type is known to have
better performance against string- and integer-like enums.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/static/datatype-enum.html]
create_enum :roles, %i(visitor manager admin)
add_column :users, :role, :roles
Enum::Roles.admin
Users.roles
{Learn more}[link:classes/Torque/PostgreSQL/Attributes/Enum.html]
* Enum set type manager
The enum type is known to have a better performance against string- and integer-
like enums. Now with the array option, which behaves like binary assignment,
each record can have multiple enum values.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/static/datatype-enum.html]
create_enum :permissions, %i(read write exec)
add_column :posts, :creator_permissions, :permissions, array: true
Enum::PermissionsSet.new(3) # [:read, :write]
post.creator_permissions.write?
{Learn more}[link:classes/Torque/PostgreSQL/Attributes/EnumSet.html]
* Period complex queries
This provides extended and complex calculations over date and time ranges. In a
few words, you can now store `start_time` and `finish_time` in the same column
and relies on the methods provided here to fo your magic.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/functions-range.html]
add_column :events, :period, :tsrange
add_column :events, :interval, :interval
Event.create(title: 'Test', period: ['2019-01-01 12:00:00', '2019-01-01 14:00:00'], interval: 15.minutes)
Event.overlapping('2019-01-01 13:00:00', '2019-01-01 15:00:00').count
Event.not_real_overlapping('2019-01-01 11:00:00', '2019-01-01 13:00:00').empty?
{Learn more}[link:classes/Torque/PostgreSQL/Attributes/Builder/Period.html]
* Has many array association
The idea is simple, one table stores all the ids and the other one says that
`has many` records on that table because its records ids exist in the column of
the array. Like: `Tag has many Videos connected through an array`.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/arrays.html]
add_column :videos, :tag_ids, :bigint, array: true
Tag.has_many :videos, array: true
Tag.videos.size
Tag.videos << another_video
{Learn more}[link:classes/Torque/PostgreSQL/Reflection/AbstractReflection.html]
* Belongs to many association
The original `belongs_to` associations define a `SingularAssociation`, which
means that it could be extended with `array: true`. In this case, I decided to
create my own `CollectionAssociation` called `belongs_to_many`, which behaves
similar to the single one, but storing and returning a list of records.
With this, now you can say things like `Project belongs to many employees`,
which is more syntactically correct than `Project has many employees`
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/arrays.html]
add_column :videos, :tag_ids, :bigint, array: true
Video.belongs_to_many :tags
Video.tags.size
Video.tags << Tag.new(title: 'rails')
{Learn more}[link:classes/Torque/PostgreSQL/Reflection/BelongsToManyReflection.html]
* Distinct On
MySQL-like group by statement on queries. It keeps only the first row of each
set of rows where the given expressions evaluate to equal.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/static/sql-select.html#SQL-DISTINCT]
User.distinct_on(:name).all
{Learn more}[link:classes/Torque/PostgreSQL/Relation/DistinctOn.html]
* Auxiliary Statements
Provides a way to write auxiliary statements for use in a larger query. It's
reconfigured on the model, and then can be used during querying process.
{PostgreSQL Docs}[https://www.postgresql.org/docs/9.6/static/queries-with.html]
class User < ActiveRecord::Base
auxiliary_statement :last_comment do |cte|
cte.query Comment.distinct_on(:user_id).order(:user_id, id: :desc)
cte.attributes content: :last_comment_content
end
end
user = User.with(:last_comment).first
{Learn more}[link:classes/Torque/PostgreSQL/AuxiliaryStatement.html]
* Multiple Schemas
Allows models and modules to have a schema associated with them, so that
developers can better organize their tables into schemas and build features in
a way that the database can better represent how they are separated.
create_schema "internal", force: :cascade
module Internal
class User < ActiveRecord::Base
self.schema = 'internal'
end
end
Internal::User.all
{Learn more}[link:classes/Torque/PostgreSQL/Adapter/DatabaseStatements.html]
== Download and installation
The latest version of Torque PostgreSQL can be installed with RubyGems:
$ gem install torque-postgresql
Source code can be downloaded direct from the GitHub repository:
* https://github.com/crashtech/torque-postgresql
== License
Torque PostgreSQL is released under the MIT license:
* http://www.opensource.org/licenses/MIT
================================================
FILE: Rakefile
================================================
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'rdoc/task'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Torque::Postgresql'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc 'Initialize the local environment'
task :environment do |t|
lib = File.expand_path('../lib', __FILE__)
spec = File.expand_path('../spec', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
$LOAD_PATH.unshift(spec) unless $LOAD_PATH.include?(spec)
end
desc 'Prints a schema dump of the test database'
task dump: :environment do |t|
require 'byebug'
require 'spec_helper'
ActiveRecord::SchemaDumper.dump
end
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task default: :spec
================================================
FILE: gemfiles/Gemfile.rails-8.0
================================================
source 'https://rubygems.org'
gem 'rails', '~> 8.0', '< 8.1'
gem 'pg', '~> 1.4.0'
gemspec path: "../"
================================================
FILE: lib/generators/torque/function_generator.rb
================================================
# frozen_string_literal: true
require 'torque/postgresql/versioned_commands/generator'
module Torque
module Generators
class FunctionGenerator < Rails::Generators::Base
include Torque::PostgreSQL::VersionedCommands::Generator
alias create_function_file create_migration_file
end
end
end
================================================
FILE: lib/generators/torque/templates/function.sql.erb
================================================
CREATE OR REPLACE FUNCTION <%= name %>()
RETURNS void AS $$
-- Function body goes here
$$ LANGUAGE sql;
================================================
FILE: lib/generators/torque/templates/type.sql.erb
================================================
DROP TYPE IF EXISTS <%= name %>;
CREATE TYPE <%= name %>;
================================================
FILE: lib/generators/torque/templates/view.sql.erb
================================================
<%= "DROP MATERIALIZED VIEW IF EXISTS #{name};\n" if options[:materialized] %>CREATE <%= options[:materialized] ? 'MATERIALIZED' : 'OR REPLACE' %> VIEW <%= name %> AS (
-- View body goes here
);
================================================
FILE: lib/generators/torque/type_generator.rb
================================================
# frozen_string_literal: true
require 'torque/postgresql/versioned_commands/generator'
module Torque
module Generators
class TypeGenerator < Rails::Generators::Base
include Torque::PostgreSQL::VersionedCommands::Generator
alias create_type_file create_migration_file
end
end
end
================================================
FILE: lib/generators/torque/view_generator.rb
================================================
# frozen_string_literal: true
require 'torque/postgresql/versioned_commands/generator'
module Torque
module Generators
class ViewGenerator < Rails::Generators::Base
include Torque::PostgreSQL::VersionedCommands::Generator
class_option :materialized, type: :boolean, aliases: %i(--m), default: false,
desc: 'Use materialized view instead of regular view'
alias create_view_file create_migration_file
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/database_statements.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module DatabaseStatements
EXTENDED_DATABASE_TYPES = %i[enum enum_set interval]
# Switch between dump mode or not
def dump_mode!
@_dump_mode = !!!@_dump_mode
end
# List of schemas blocked by the application in the current connection
def schemas_blacklist
@schemas_blacklist ||= Torque::PostgreSQL.config.schemas.blacklist +
(@config.dig(:schemas, 'blacklist') || [])
end
# List of schemas used by the application in the current connection
def schemas_whitelist
@schemas_whitelist ||= Torque::PostgreSQL.config.schemas.whitelist +
(@config.dig(:schemas, 'whitelist') || [])
end
# A list of schemas on the search path sanitized
def schemas_search_path_sanitized
@schemas_search_path_sanitized ||= begin
db_user = @config[:username] || ENV['USER'] || ENV['USERNAME']
schema_search_path.split(',').map { |item| item.strip.sub('"$user"', db_user) }
end
end
# Check if a given type is valid.
def valid_type?(type)
super || extended_types.include?(type)
end
# Get the list of extended types
def extended_types
EXTENDED_DATABASE_TYPES
end
# Checks if a given schema exists in the database. If +filtered+ is
# given as false, then it will check regardless of whitelist and
# blacklist
def schema_exists?(name, filtered: true)
return user_defined_schemas.include?(name.to_s) if filtered
query_value(<<-SQL, "SCHEMA") == 1
SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = #{quote(name)}
SQL
end
# Returns true if type exists.
def type_exists?(name)
user_defined_types.key? name.to_s
end
alias data_type_exists? type_exists?
# Change some of the types being mapped
def initialize_type_map(m = type_map)
super
if PostgreSQL.config.geometry.enabled
m.register_type 'box', OID::Box.new
m.register_type 'circle', OID::Circle.new
m.register_type 'line', OID::Line.new
m.register_type 'segment', OID::Segment.new
end
if PostgreSQL.config.interval.enabled
m.register_type 'interval', OID::Interval.new
end
end
# :nodoc:
def load_additional_types(oids = nil)
type_map.alias_type 'regclass', 'varchar'
type_map.alias_type 'regconfig', 'varchar'
super
torque_load_additional_types(oids)
end
# Add the composite types to be loaded too.
def torque_load_additional_types(oids = nil)
return unless torque_load_additional_types?
# Types: (b)ase, (c)omposite, (d)omain, (e)num, (p)seudotype, (r)ange
# (m)ultirange
query = <<~SQL
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput,
r.rngsubtype, t.typtype, t.typbasetype, t.typarray
FROM pg_type as t
LEFT JOIN pg_range as r ON oid = rngtypid
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
SQL
if oids
query += " AND t.oid IN (%s)" % oids.join(", ")
else
query += " AND t.typtype IN ('e')"
end
options = { allow_retry: true, materialize_transactions: false }
internal_execute(query, 'SCHEMA', **options).each do |row|
if row['typtype'] == 'e' && PostgreSQL.config.enum.enabled
OID::Enum.create(row, type_map)
end
end
end
def torque_load_additional_types?
PostgreSQL.config.enum.enabled
end
# Gets a list of user defined types.
# You can even choose the +category+ filter
def user_defined_types(*categories)
categories = categories.compact.presence || %w[c e p r m]
query(<<-SQL, 'SCHEMA').to_h
SELECT t.typname, t.typtype
FROM pg_type as t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
AND t.typtype IN ('#{categories.join("', '")}')
SQL
end
# Get the list of inherited tables associated with their parent tables
def inherited_tables
tables = query(<<-SQL, 'SCHEMA')
SELECT inhrelid::regclass AS table_name,
inhparent::regclass AS inheritances
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
ORDER BY inhrelid
SQL
tables.each_with_object({}) do |(child, parent), result|
(result[child] ||= []) << parent
end
end
# Get the list of schemas that were created by the user
def user_defined_schemas
query_values(user_defined_schemas_sql, 'SCHEMA')
end
# Build the query for allowed schemas
def user_defined_schemas_sql
<<-SQL.squish
SELECT nspname
FROM pg_catalog.pg_namespace
WHERE 1=1 AND #{filter_by_schema.join(' AND ')}
ORDER BY oid
SQL
end
# Get the list of columns, and their definition, but only from the
# actual table, does not include columns that comes from inherited table
def column_definitions(table_name)
query(<<~SQL, "SCHEMA")
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
c.collname, col_description(a.attrelid, a.attnum) AS comment,
#{supports_identity_columns? ? 'attidentity' : quote('')} AS identity,
#{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
FROM pg_attribute a
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
LEFT JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
AND a.attnum > 0 AND NOT a.attisdropped
#{'AND a.attislocal' if @_dump_mode}
ORDER BY a.attnum
SQL
end
# Get all possible schema entries that can be created via versioned
# commands of the provided type. Mostly for covering removals and not
# dump them
def list_versioned_commands(type)
query =
case type
when :function
<<-SQL.squish
SELECT n.nspname AS schema, p.proname AS name
FROM pg_catalog.pg_proc p
INNER JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE 1=1 AND #{filter_by_schema.join(' AND ')};
SQL
when :type
<<-SQL.squish
SELECT n.nspname AS schema, t.typname AS name
FROM pg_type t
INNER JOIN pg_namespace n ON n.oid = t.typnamespace
WHERE 1=1 AND t.typtype NOT IN ('e')
AND #{filter_by_schema.join(' AND ')};
SQL
when :view
<<-SQL.squish
SELECT n.nspname AS schema, c.relname AS name
FROM pg_class c
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE 1=1 AND c.relkind IN ('v', 'm')
AND #{filter_by_schema.join(' AND ')};
SQL
end
select_rows(query, 'SCHEMA')
end
# Build the condition for filtering by schema
def filter_by_schema
conditions = []
conditions << <<-SQL.squish if schemas_blacklist.any?
nspname NOT LIKE ALL (ARRAY['#{schemas_blacklist.join("', '")}'])
SQL
conditions << <<-SQL.squish if schemas_whitelist.any?
nspname LIKE ANY (ARRAY['#{schemas_whitelist.join("', '")}'])
SQL
conditions
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/array.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module OID
module Array
def force_equality?(value)
PostgreSQL.config.predicate_builder.handle_array_attributes ? false : super
end
end
::ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.prepend(Array)
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/box.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class Box < Struct.new(:x1, :y1, :x2, :y2)
def points
klass = Torque::PostgreSQL.config.geometry.point_class
[
klass.new(x1, y1),
klass.new(x1, y2),
klass.new(x2, y1),
klass.new(x2, y2),
]
end
end
config.geometry.box_class ||= ::ActiveRecord.const_set('Box', Class.new(Box))
module Adapter
module OID
class Box < Torque::PostgreSQL::GeometryBuilder
PIECES = %i[x1 y1 x2 y2].freeze
FORMATION = '((%s,%s),(%s,%s))'.freeze
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/circle.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class Circle < Struct.new(:x, :y, :r)
alias radius r
alias radius= r=
def center
point_class.new(x, y)
end
def center=(value)
parts = value.is_a?(point_class) ? [value.x, value.y] : value[0..1]
self.x = parts.first
self.y = parts.last
end
private
def point_class
Torque::PostgreSQL.config.geometry.point_class
end
end
config.geometry.circle_class ||= ::ActiveRecord.const_set('Circle', Class.new(Circle))
module Adapter
module OID
class Circle < Torque::PostgreSQL::GeometryBuilder
PIECES = %i[x y r].freeze
FORMATION = '<(%s,%s),%s>'.freeze
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/enum.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module OID
class Enum < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Enum
attr_reader :name, :klass, :set_klass, :enum_klass
def self.create(row, type_map)
name = row['typname']
oid = row['oid'].to_i
arr_oid = row['typarray'].to_i
oid_klass = Enum.new(name)
oid_set_klass = EnumSet.new(name, oid_klass.klass)
oid_klass.instance_variable_set(:@set_klass, oid_set_klass)
type_map.register_type(oid, oid_klass)
type_map.register_type(arr_oid, oid_set_klass)
end
def initialize(name)
@name = name
@klass = Attributes::Enum.lookup(name)
@enum_klass = self
end
def hash
[self.class, name].hash
end
def serialize(value)
return if value.blank?
value = cast_value(value)
value.to_s unless value.nil?
end
def assert_valid_value(value)
cast_value(value)
end
# Always use symbol value for schema dumper
def type_cast_for_schema(value)
cast_value(value).to_sym.inspect
end
def ==(other)
self.class == other.class &&
other.klass == klass &&
other.type == type
end
private
def cast_value(value)
return if value.blank?
return value if value.is_a?(@klass)
@klass.new(value)
rescue Attributes::Enum::EnumError
nil
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/enum_set.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module OID
class EnumSet < Enum
def initialize(name, enum_klass)
@name = name + '[]'
@klass = Attributes::EnumSet.lookup(name, enum_klass)
@set_klass = self
@enum_klass = enum_klass
end
def type
:enum
end
def deserialize(value)
return unless value.present?
value = value[1..-2].split(',') if value.is_a?(String)
cast_value(value)
end
def serialize(value)
return if value.blank?
value = cast_value(value)
return if value.blank?
"{#{value.map(&:to_s).join(',')}}"
end
# Always use symbol values for schema dumper
def type_cast_for_schema(value)
cast_value(value).map(&:to_sym).inspect
end
private
def cast_value(value)
return if value.blank?
return value if value.is_a?(@klass)
@klass.new(value)
rescue Attributes::EnumSet::EnumSetError
nil
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/interval.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module OID
class Interval < ActiveModel::Type::Value
CAST_PARTS = [:years, :months, :days, :hours, :minutes, :seconds]
def type
:interval
end
# Accepts database-style string, numeric as seconds, array of parts
# padded to left, or a hash
#
# Examples:
# [12, 0, 0]
# produces: 12 hours, 0 minutes, and 0 seconds
#
# [nil, nil, 3, 0, 0, 0]
# produces: 3 days, 0 hours, 0 minutes, and 0 seconds
#
# {minutes: 12, seconds: 0}
# produces: 12 minutes, and 0 seconds
def cast(value)
return if value.blank?
case value
when ::String then deserialize(value)
when ::ActiveSupport::Duration then value
when ::Numeric
parts = CAST_PARTS.map do |part|
rest, value = value.divmod(1.send(part))
rest == 0 ? nil : [part, rest]
end
parts_to_duration(parts.compact)
when ::Array
value.compact!
parts = CAST_PARTS.drop(6 - value.size).zip(value).to_h
parts_to_duration(parts)
when ::Hash
parts_to_duration(value)
else
value
end
end
# Uses the ActiveSupport::Duration::ISO8601Parser
# See ActiveSupport::Duration#parse
# The value must be Integer when no precision is given
def deserialize(value)
return if value.blank?
ActiveSupport::Duration.parse(value)
end
# Uses the ActiveSupport::Duration::ISO8601Serializer
# See ActiveSupport::Duration#iso8601
def serialize(value)
return if value.blank?
value = cast(value) unless value.is_a?(ActiveSupport::Duration)
value = remove_weeks(value) if value.parts.to_h.key?(:weeks)
value.iso8601(precision: @scale)
end
# Always use the numeric value for schema dumper
def type_cast_for_schema(value)
cast(value).value.inspect
end
# Check if the user input has the correct format
def assert_valid_value(value)
# TODO: Implement!
end
# Transform a list of parts into a duration object
def parts_to_duration(parts)
parts = parts.to_h.slice(*CAST_PARTS)
return 0.seconds if parts.blank?
seconds = 0
parts = parts.map do |part, num|
num = num.to_i unless num.is_a?(Numeric)
next if num <= 0
seconds += num.send(part).value
[part.to_sym, num]
end
ActiveSupport::Duration.new(seconds, parts.compact)
end
# As PostgreSQL converts weeks in duration to days, intercept duration
# values with weeks and turn them into days before serializing so it
# won't break because the following issues
# https://github.com/crashtech/torque-postgresql/issues/26
# https://github.com/rails/rails/issues/34655
def remove_weeks(value)
parts = value.parts.dup
parts[:days] += parts.delete(:weeks) * 7
ActiveSupport::Duration.new(value.seconds.to_i, parts)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/line.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class Line < Struct.new(:slope, :intercept)
alias c intercept
alias c= intercept=
def a=(value)
self.slope = vertical? ? Float::INFINITY : Rational(value, b)
end
def a
slope.numerator
end
def b=(value)
self.slope = value.zero? ? Float::INFINITY : Rational(a, value)
end
def b
vertical? ? 0 : slope.denominator
end
def horizontal?
slope.zero?
end
def vertical?
!slope.try(:infinite?).eql?(nil)
end
end
config.geometry.line_class ||= ::ActiveRecord.const_set('Line', Class.new(Line))
module Adapter
module OID
class Line < Torque::PostgreSQL::GeometryBuilder
PIECES = %i[a b c].freeze
FORMATION = '{%s,%s,%s}'.freeze
protected
def build_klass(*args)
return nil if args.empty?
check_invalid_format!(args)
a, b, c = args.try(:first, pieces.size)&.map(&:to_f)
slope = b.zero? ? Float::INFINITY : Rational(a, b)
config_class.new(slope, c)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/range.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module OID
class Range < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range
HASH_PICK = %i[from start end to].freeze
module Comparison
def <=>(other)
return super unless other.acts_like?(:date) || other.acts_like?(:time)
other = other.to_time if other.acts_like?(:date)
super other.to_i
end
end
def cast_value(value)
case value
when ::Array
cast_custom(value[0], value[1])
when ::Hash
pieces = value.with_indifferent_access.values_at(*HASH_PICK)
cast_custom(pieces[0] || pieces[1], pieces[2] || pieces[3])
else
super
end
end
def map(value) # :nodoc:
return value unless value.respond_to?(:first)
from = yield(value.first)
to = yield(value.last)
cast_custom(from, to)
end
private
def cast_custom(from, to)
from = custom_cast_single(from, true)
to = custom_cast_single(to)
::Range.new(from, to)
end
def custom_cast_single(value, negative = false)
value.blank? ? custom_infinity(negative) : subtype.deserialize(value)
end
def custom_infinity(negative)
negative ? -::Float::INFINITY : ::Float::INFINITY
end
end
::ActiveRecord::ConnectionAdapters::PostgreSQL::OID.send(:remove_const, :Range)
::ActiveRecord::ConnectionAdapters::PostgreSQL::OID.const_set(:Range, Range)
::Float.prepend(Range::Comparison)
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid/segment.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class Segment < Struct.new(:point0, :point1)
def x1=(value)
self.point0 = new_point(value, y1)
end
def x1
point0.x
end
def y1=(value)
self.point0 = new_point(x1, value)
end
def y1
point0.y
end
def x2=(value)
self.point1 = new_point(value, y2)
end
def x2
point1.x
end
def y2=(value)
self.point1 = new_point(x2, value)
end
def y2
point1.y
end
private
def new_point(x, y)
Torque::PostgreSQL.config.geometry.point_class.new(x, y)
end
end
config.geometry.segment_class ||= ::ActiveRecord.const_set('Segment', Class.new(Segment))
module Adapter
module OID
class Segment < Torque::PostgreSQL::GeometryBuilder
PIECES = %i[x1 y1 x2 y2].freeze
FORMATION = '((%s,%s),(%s,%s))'.freeze
protected
def point_class
Torque::PostgreSQL.config.geometry.point_class
end
def build_klass(*args)
return nil if args.empty?
check_invalid_format!(args)
x1, y1, x2, y2 = args.try(:first, pieces.size)&.map(&:to_f)
config_class.new(
point_class.new(x1, y1),
point_class.new(x2, y2),
)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/oid.rb
================================================
require_relative 'oid/array'
require_relative 'oid/range'
================================================
FILE: lib/torque/postgresql/adapter/quoting.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module Quoting
QUOTED_TYPE_NAMES = Concurrent::Map.new
Name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name
Column = ActiveRecord::ConnectionAdapters::PostgreSQL::Column
ColumnDefinition = ActiveRecord::ConnectionAdapters::ColumnDefinition
Utils = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
# Quotes type names for use in SQL queries.
def quote_type_name(name, *args)
QUOTED_TYPE_NAMES[args] ||= begin
name = name.to_s
args << 'public' if args.empty? && !name.include?('.')
quote_identifier_name(name, *args)
end
end
# Make sure to support all sorts of different compositions of names
def quote_identifier_name(name, schema = nil)
name = Utils.extract_schema_qualified_name(name.to_s) unless name.is_a?(Name)
name.instance_variable_set(:@schema, Utils.unquote_identifier(schema.to_s)) if schema
name.quoted.freeze
end
def quote_default_expression(value, column)
return super unless value.class <= Array || value.class <= Set
type =
if column.is_a?(ColumnDefinition) && column.options.try(:[], :array)
# This is the general way
lookup_cast_type(column.sql_type)
elsif column.is_a?(Column) && column.array?
# When using +change_column_default+
lookup_cast_type_from_column(column)
end
type.nil? ? super : quote(type.serialize(value.to_a))
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/schema_creation.rb
================================================
module Torque
module PostgreSQL
module Adapter
module SchemaCreation
# Inherits are now setup via table options, but keep the implementation
# supported by this gem
def add_table_options!(create_sql, o)
if o.inherits.present?
# Make sure we always have parenthesis
create_sql << '()' unless create_sql[-1] == ')'
tables = o.inherits.map(&method(:quote_table_name))
create_sql << " INHERITS ( #{tables.join(' , ')} )"
end
super(create_sql, o)
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaCreation.prepend SchemaCreation
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/schema_definitions.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module ColumnMethods
# Adds a search language column to the table. See +add_search_language+
def search_language(*names, **options)
raise ArgumentError, "Missing column name(s) for search_language" if names.empty?
names.each { |name| column(name, :regconfig, **options) }
end
# Add a search vector column to the table. See +add_search_vector+
def search_vector(*names, columns:, **options)
raise ArgumentError, "Missing column name(s) for search_vector" if names.empty?
options = Attributes::Builder.search_vector_options(columns: columns, **options)
names.each { |name| column(name, :virtual, **options) }
end
end
module TableDefinition
include ColumnMethods
attr_reader :inherits
def initialize(*args, **options)
super
@inherits = Array.wrap(options.delete(:inherits)).flatten.compact \
if options.key?(:inherits)
end
def set_primary_key(tn, id, primary_key, *, **)
super unless @inherits.present? && primary_key.blank? && id == :primary_key
end
private
def create_column_definition(name, type, options)
if type == :enum_set
type = :enum
options ||= {}
options[:array] = true
end
super(name, type, options)
end
end
# Add exclusive support for versioned commands when importing from schema
# dump. This ensures that such methods are not available in regular
# migrations.
module Definition
def create_function(name, version:, dir: pool.migrations_paths)
return super unless VersionedCommands.valid_type?(:function)
execute VersionedCommands.fetch_command(dir, :function, name, version)
end
def create_type(name, version:, dir: pool.migrations_paths)
return super unless VersionedCommands.valid_type?(:type)
execute VersionedCommands.fetch_command(dir, :type, name, version)
end
def create_view(name, version:, dir: pool.migrations_paths)
return super unless VersionedCommands.valid_type?(:view)
execute VersionedCommands.fetch_command(dir, :view, name, version)
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::Table.include ColumnMethods
ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition.include TableDefinition
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/schema_dumper.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module SchemaDumper
SEARCH_VECTOR_SCANNER = /
to_tsvector\(
('[^']+'|[a-z][a-z0-9_]*)[^,]*,[^\(]*
\(?coalesce\(([a-z][a-z0-9_]*)[^\)]*\)\)?
(?:::[^\)]*\))?
(?:\s*,\s*'([A-D])')?
/ix
def initialize(*)
super
if with_versioned_commands?
@versioned_commands = VersionedCommands::SchemaTable.new(@connection.pool)
@ignore_tables << @versioned_commands.table_name
end
end
def dump(stream) # :nodoc:
@connection.dump_mode!
super
@connection.dump_mode!
stream
end
private
def types(stream) # :nodoc:
super
versioned_commands(stream, :type)
versioned_commands(stream, :function)
end
def tables(stream) # :nodoc:
around_tables(stream) { dump_tables(stream) }
end
def around_tables(stream)
functions(stream) if fx_functions_position == :beginning
yield
versioned_commands(stream, :view, true)
functions(stream) if fx_functions_position == :end
triggers(stream) if defined?(::Fx::SchemaDumper::Trigger)
end
def dump_tables(stream)
inherited_tables = @connection.inherited_tables
sorted_tables = (@connection.tables - @connection.views).filter_map do |table_name|
name_parts = table_name.split(/(?:public)?\./).reverse.compact_blank
next if ignored?(table_name) || ignored?(name_parts.join('.'))
[table_name, name_parts]
end.sort_by(&:last).to_h
postponed = []
stream.puts " # These are the common tables"
sorted_tables.each do |table, (table_name, _)|
next postponed << table if inherited_tables.key?(table_name)
table(table, stream)
stream.puts # Ideally we would not do this in the last one
end
if postponed.present?
stream.puts " # These are tables that have inheritance"
postponed.each do |table|
sub_stream = StringIO.new
table(table, sub_stream)
stream.puts sub_stream.string.sub(/do \|t\|\n end/, '')
stream.puts
end
end
# Fixes double new lines to single new lines
stream.pos -= 1
# dump foreign keys at the end to make sure all dependent tables exist.
if @connection.supports_foreign_keys?
foreign_keys_stream = StringIO.new
sorted_tables.each do |(tbl, *)|
foreign_keys(tbl, foreign_keys_stream)
end
foreign_keys_string = foreign_keys_stream.string
stream.puts if foreign_keys_string.length > 0
stream.print foreign_keys_string
end
end
# Make sure to remove the schema from the table name
def remove_prefix_and_suffix(table)
super(table.sub(/\A[a-z0-9_]*\./, ''))
end
# Dump user defined schemas
def schemas(stream)
return super if !PostgreSQL.config.schemas.enabled
return if (list = (@connection.user_defined_schemas - ['public'])).empty?
stream.puts " # Custom schemas defined in this database."
list.each { |name| stream.puts " create_schema \"#{name}\", force: :cascade" }
stream.puts
end
# Adjust the schema type for search vector
def schema_type_with_virtual(column)
column.virtual? && column.type == :tsvector ? :search_vector : super
end
# Adjust the schema type for search language
def schema_type(column)
column.sql_type == 'regconfig' ? :search_language : super
end
# Adjust table options to make the dump more readable
def prepare_column_options(column)
options = super
parse_search_vector_options(column, options) if column.type == :tsvector
options
end
# Parse the search vector operation into a readable format
def parse_search_vector_options(column, options)
settings = options[:as]&.scan(SEARCH_VECTOR_SCANNER)
return if settings.blank?
languages = settings.map(&:shift).uniq
return if languages.many?
language = languages.first
language = language[0] == "'" ? language[1..-2] : language.to_sym
columns = parse_search_vector_columns(settings)
options.except!(:as, :type)
options.merge!(language: language.inspect, columns: columns)
end
# Simplify the whole columns configuration to make it more manageable
def parse_search_vector_columns(settings)
return ":#{settings.first.first}" if settings.one?
settings = settings.sort_by(&:last)
weights = %w[A B C D]
columns = settings.each.with_index.reduce([]) do |acc, (setting, index)|
column, weight = setting
break if (weights[index] || 'D') != weight
acc << column
acc
end
return columns.map(&:to_sym).inspect if columns
settings.to_h.transform_values(&:inspect)
end
# Simply add all versioned commands to the stream
def versioned_commands(stream, type, add_newline = false)
return unless with_versioned_commands?
list = @versioned_commands.versions_of(type.to_s)
return if list.empty?
existing = list_existing_versioned_commands(type)
stream.puts if add_newline
stream.puts " # These are #{type.to_s.pluralize} managed by versioned commands"
list.each do |(name, version)|
next if existing.exclude?(name)
stream.puts " create_#{type} \"#{name}\", version: #{version}"
end
stream.puts unless add_newline
end
def list_existing_versioned_commands(type)
@connection.list_versioned_commands(type).each_with_object(Set.new) do |entry, set|
set << (entry.first == 'public' ? entry.last : entry.join('_'))
end
end
def with_versioned_commands?
PostgreSQL.config.versioned_commands.enabled
end
def fx_functions_position
return unless defined?(::Fx::SchemaDumper::Function)
Fx.configuration.dump_functions_at_beginning_of_schema ? :beginning : :end
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend SchemaDumper
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/schema_overrides.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module SchemaOverrides
# This adds better support for handling the quotation of table names
def quote_table_name(name)
ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting::QUOTED_TABLE_NAMES.then do |m|
m[name] ||= quote_identifier_name(name)
end
end
%i[
table_exists? indexes index_exists? columns column_exists? primary_key
create_table change_table add_column add_columns remove_columns remove_column
change_column change_column_default change_column_null rename_column
add_index remove_index rename_index index_name_exists? foreign_keys
add_timestamps remove_timestamps change_table_comment change_column_comment
bulk_change_table
rename_table add_foreign_key remove_foreign_key foreign_key_exists?
].each do |method_name|
define_method(method_name) do |table_name, *args, **options, &block|
table_name = sanitize_name_with_schema(table_name, options)
super(table_name, *args, **options, &block)
end
end
def drop_table(*table_names, **options)
table_names = table_names.map { |name| sanitize_name_with_schema(name, options.dup) }
super(*table_names, **options)
end
private
def validate_table_length!(table_name)
super(table_name.to_s)
end
end
include SchemaOverrides
end
end
end
================================================
FILE: lib/torque/postgresql/adapter/schema_statements.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Adapter
module SchemaStatements
# Drops a type
def drop_type(name, options = {})
force = options.fetch(:force, '').upcase
check = 'IF EXISTS' if options.fetch(:check, true)
name = sanitize_name_with_schema(name, options)
internal_exec_query(<<-SQL.squish).tap { reload_type_map }
DROP TYPE #{check}
#{quote_type_name(name)} #{force}
SQL
end
# Renames a type
def rename_type(type_name, new_name, options = {})
type_name = sanitize_name_with_schema(type_name, options)
internal_exec_query(<<-SQL.squish).tap { reload_type_map }
ALTER TYPE #{quote_type_name(type_name)}
RENAME TO #{Quoting::Name.new(nil, new_name.to_s).quoted}
SQL
end
# Creates a column that stores the underlying language of the record so
# that a search vector can be created dynamically based on it. It uses
# a `regconfig` type, so string conversions are mandatory
def add_search_language(table, name, options = {})
add_column(table, name, :regconfig, options)
end
# Creates a column and setup a search vector as a virtual column. The
# options are dev-friendly and controls how the vector function will be
# defined
#
# === Options
# [:columns]
# The list of columns that will be used to create the search vector.
# It can be a single column, an array of columns, or a hash as a
# combination of column name and weight (A, B, C, or D).
# [:language]
# Specify the language config to be used for the search vector. If a
# string is provided, then the value will be statically embedded. If a
# symbol is provided, then it will reference another column.
# [:stored]
# Specify if the value should be stored in the database. As of now,
# PostgreSQL only supports `true`, which will create a stored column.
def add_search_vector(table, name, columns, options = {})
options = Builder.search_vector_options(columns: columns, **options)
add_column(table, name, options.delete(:type), options)
end
# Changes the enumerator by adding new values
#
# Example:
# add_enum_values 'status', ['baz']
# add_enum_values 'status', ['baz'], before: 'bar'
# add_enum_values 'status', ['baz'], after: 'foo'
# add_enum_values 'status', ['baz'], prepend: true
def add_enum_values(name, values, options = {})
name = sanitize_name_with_schema(name, options)
before = options.fetch(:before, false)
after = options.fetch(:after, false)
before = enum_values(name).first if options.key? :prepend
before = quote(before) unless before == false
after = quote(after) unless after == false
quote_enum_values(name, values, options).each do |value|
reference = "BEFORE #{before}" unless before == false
reference = "AFTER #{after}" unless after == false
execute <<-SQL.squish
ALTER TYPE #{quote_type_name(name)}
ADD VALUE #{value} #{reference}
SQL
before = false
after = value
end
end
# Returns all values that an enum type can have.
def enum_values(name)
select_values(<<-SQL.squish, 'SCHEMA')
SELECT enumlabel FROM pg_enum
WHERE enumtypid = #{quote(name)}::regtype::oid
ORDER BY enumsortorder
SQL
end
# Add the schema option when extracting table options
def table_options(table_name)
options = super
if PostgreSQL.config.schemas.enabled
table, schema = table_name.split('.').reverse
if table.present? && schema.present? && schema != current_schema
options[:schema] = schema
end
end
if options[:options]&.start_with?('INHERITS (')
options.delete(:options)
tables = inherited_table_names(table_name)
options[:inherits] = tables.one? ? tables.first : tables
end
options
end
# When dumping the schema we need to add all schemas, not only those
# active for the current +schema_search_path+
def quoted_scope(name = nil, type: nil)
return super unless name.nil?
scope = super
global = scope[:schema].start_with?('ANY (')
scope[:schema] = "ANY ('{#{user_defined_schemas.join(',')}}')"
scope
end
# Fix the query to include the schema on tables names when dumping
def data_source_sql(name = nil, type: nil)
return super unless name.nil?
super.sub('SELECT c.relname FROM', "SELECT n.nspname || '.' || c.relname FROM")
end
# Add schema and inherits as one of the valid options for table
# definition
def valid_table_definition_options
super + [:schema, :inherits]
end
# Add proper support for schema load when using versioned commands
def assume_migrated_upto_version(version)
return super unless PostgreSQL.config.versioned_commands.enabled
return super if (commands = pool.migration_context.migration_commands).empty?
version = version.to_i
migration_context = pool.migration_context
migrated = migration_context.get_all_versions
versions = migration_context.migrations.map(&:version)
inserting = (versions - migrated).select { |v| v < version }
inserting << version unless migrated.include?(version)
return if inserting.empty?
duplicated = inserting.tally.filter_map { |v, count| v if count > 1 }
raise <<~MSG.squish if duplicated.present?
Duplicate migration #{duplicated.first}.
Please renumber your migrations to resolve the conflict.
MSG
VersionedCommands::SchemaTable.new(pool).create_table
execute insert_versions_sql(inserting)
end
# Add proper support for schema load when using versioned commands
def insert_versions_sql(versions)
return super unless PostgreSQL.config.versioned_commands.enabled
commands = pool.migration_context.migration_commands.select do |migration|
versions.include?(migration.version)
end
return super if commands.empty?
table = quote_table_name(VersionedCommands::SchemaTable.new(pool).table_name)
sql = super(versions - commands.map(&:version))
sql << "\nINSERT INTO #{table} (version, type, object_name) VALUES\n"
sql << commands.map do |m|
+"(#{quote(m.version)}, #{quote(m.type)}, #{quote(m.object_name)})"
end.join(",\n")
sql << ";"
sql
end
private
# Remove the schema from the sequence name
def sequence_name_from_parts(table_name, column_name, suffix)
super(table_name.split('.').last, column_name, suffix)
end
# Helper for supporting schema name in several methods
def sanitize_name_with_schema(name, options)
return name if (schema = options&.delete(:schema)).blank?
Quoting::Name.new(schema.to_s, name.to_s)
end
def quote_enum_values(name, values, options)
prefix = options[:prefix]
prefix = name if prefix === true
suffix = options[:suffix]
suffix = name if suffix === true
values.map! do |value|
quote([prefix, value, suffix].compact.join('_'))
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/adapter.rb
================================================
# frozen_string_literal: true
require_relative 'adapter/database_statements'
require_relative 'adapter/oid'
require_relative 'adapter/quoting'
require_relative 'adapter/schema_creation'
require_relative 'adapter/schema_definitions'
require_relative 'adapter/schema_dumper'
require_relative 'adapter/schema_statements'
module Torque
module PostgreSQL
module Adapter
include Quoting
include DatabaseStatements
include SchemaStatements
# :nodoc:
class DeduplicatableArray < ::Array
def deduplicate
map { |value| -value }
end
alias :-@ :deduplicate
end
# Get the current PostgreSQL version as a Gem Version.
def version
@version ||= Gem::Version.new(
select_value('SELECT version()').match(/#{Adapter::ADAPTER_NAME} ([\d\.]+)/)[1]
)
end
# Add `inherits` and `schema` to the list of extracted table options
def extract_table_options!(options)
super.merge(options.extract!(:inherits, :schema))
end
# Allow filtered bulk insert by adding the where clause. This method is
# only used by +InsertAll+, so it somewhat safe to override it
def build_insert_sql(insert)
super.tap do |sql|
if insert.update_duplicates? && insert.where_condition?
if insert.returning
sql.sub!(' RETURNING ', " WHERE #{insert.where} RETURNING ")
else
sql << " WHERE #{insert.where}"
end
end
end
end
end
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend Adapter
end
end
================================================
FILE: lib/torque/postgresql/arel/infix_operation.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
Math = Module.new
def self.build_operations(operations)
default_alias = :visit_Arel_Nodes_InfixOperation
operations&.each do |name, operator|
klass_name = name.to_s.camelize
next if ::Arel::Nodes.const_defined?(klass_name)
klass = Class.new(::Arel::Nodes::InfixOperation)
operator = (-operator).to_sym
klass.send(:define_method, :initialize) { |*args| super(operator, *args) }
::Arel::Nodes.const_set(klass_name, klass)
visitor = :"visit_Arel_Nodes_#{klass_name}"
::Arel::Visitors::PostgreSQL.send(:alias_method, visitor, default_alias)
# Don't worry about quoting here, if the right side is something that
# doesn't need quoting, it will leave it as it is
Math.send(:define_method, klass_name.underscore) { |other| klass.new(self, other) }
end
end
::Arel::Nodes::Node.include(Math)
::Arel::Attribute.include(Math)
end
end
end
================================================
FILE: lib/torque/postgresql/arel/join_source.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
module JoinSource
attr_accessor :only
def only?
only === true
end
end
::Arel::Nodes::JoinSource.include JoinSource
end
end
end
================================================
FILE: lib/torque/postgresql/arel/nodes.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
module Nodes
class Cast < ::Arel::Nodes::Binary
include ::Arel::Expressions
include ::Arel::Predications
include ::Arel::AliasPredication
include ::Arel::OrderPredications
include ::Arel::Math
def initialize(left, right, array = false)
right = +right.to_s
right << '[]' if array
super left, right
end
end
class Ref < ::Arel::Nodes::Unary
attr_reader :reference
alias to_s expr
def initialize(expr, reference = nil)
@reference = reference
super expr
end
def as(other)
@reference&.as(other) || super
end
end
end
::Arel.define_singleton_method(:array) do |*values, cast: nil|
values = values.first if values.size.eql?(1) && values.first.is_a?(::Enumerable)
result = ::Arel::Nodes.build_quoted(values)
result = result.pg_cast(cast, true) if cast.present?
result
end
::Arel::Nodes::Function.include(::Arel::Math)
end
end
end
================================================
FILE: lib/torque/postgresql/arel/operations.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
module Operations
# Create a cast operation
def pg_cast(type, array = false)
Nodes::Cast.new(self, type, array)
end
# Make sure to add proper support over AR's own +cast+ method while
# still allow attributes to be casted
def cast(type, array = false)
defined?(super) && !array ? super(type) : pg_cast(type, array)
end
end
::Arel::Attributes::Attribute.include(Operations)
::Arel::Nodes::SqlLiteral.include(Operations)
::Arel::Nodes::Node.include(Operations)
end
end
end
================================================
FILE: lib/torque/postgresql/arel/select_manager.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
module SelectManager
def only
@ctx.source.only = true
end
end
::Arel::SelectManager.include SelectManager
end
end
end
================================================
FILE: lib/torque/postgresql/arel/visitors.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Arel
module Visitors
# Add ONLY modifier to query
def visit_Arel_Nodes_JoinSource(o, collector)
collector << 'ONLY ' if o.only?
super
end
# Allow quoted arrays to get here
def visit_Arel_Nodes_Quoted(o, collector)
return super unless o.expr.is_a?(::Enumerable)
quote_array(o.expr, collector)
end
# Allow quoted arrays to get here
def visit_Arel_Nodes_Casted(o, collector)
value = o.value_for_database
klass = ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array::Data
return super unless value.is_a?(klass)
quote_array(value.values, collector)
end
## TORQUE VISITORS
def visit_Torque_PostgreSQL_Arel_Nodes_Ref(o, collector)
collector << quote_table_name(o.expr)
end
# Allow casting any node
def visit_Torque_PostgreSQL_Arel_Nodes_Cast(o, collector)
visit(o.left, collector) << '::' << o.right
end
private
def quote_array(value, collector)
value = value.map(&::Arel::Nodes.method(:build_quoted))
collector << 'ARRAY['
visit_Array(value, collector)
collector << ']'
end
end
::Arel::Visitors::PostgreSQL.prepend(Visitors)
end
end
end
================================================
FILE: lib/torque/postgresql/arel.rb
================================================
require_relative 'arel/infix_operation'
require_relative 'arel/join_source'
require_relative 'arel/nodes'
require_relative 'arel/operations'
require_relative 'arel/select_manager'
require_relative 'arel/visitors'
================================================
FILE: lib/torque/postgresql/associations/association_scope.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module AssociationScope
# A customized predicate builder for array attributes that can be used
# standalone and changes the behavior of the blank state
class PredicateBuilderArray
include PredicateBuilder::ArrayHandler
def call_with_empty(attribute)
'1=0' # Does not match records with empty arrays
end
end
module ClassMethods
def get_bind_values(*)
super.flatten
end
end
private
# When loading a join by value (last as in we know which records to
# load) only has many array need to have a different behavior, so it
# can properly match array values
def last_chain_scope(scope, reflection, owner)
return super unless reflection.connected_through_array?
return super if reflection.macro == :belongs_to_many
constraint = PredicateBuilderArray.new.call_for_array(
reflection.array_attribute,
transform_value(owner[reflection.join_foreign_key]),
)
scope.where!(constraint)
end
# When loading a join by reference (next as in we don't know which
# records to load), it can take advantage of the new predicate builder
# to figure out the most optimal way to connect both properties
def next_chain_scope(scope, reflection, next_reflection)
return super unless reflection.connected_through_array?
primary_key = reflection.aliased_table[reflection.join_primary_key]
foreign_key = next_reflection.aliased_table[reflection.join_foreign_key]
constraint = PredicateBuilder::ArelAttributeHandler.call(primary_key, foreign_key)
scope.joins!(join(foreign_table, constraint))
end
# For array-like values, it needs to call the method as many times as
# the array size
def transform_value(value)
if value.is_a?(::Enumerable)
value.map { |v| value_transformation.call(v) }
else
value_transformation.call(value)
end
end
end
::ActiveRecord::Associations::AssociationScope.singleton_class.prepend(AssociationScope::ClassMethods)
::ActiveRecord::Associations::AssociationScope.prepend(AssociationScope)
end
end
end
================================================
FILE: lib/torque/postgresql/associations/belongs_to_many_association.rb
================================================
# frozen_string_literal: true
require 'active_record/associations/collection_association'
# FIXME: build, create
module Torque
module PostgreSQL
module Associations
class BelongsToManyAssociation < ::ActiveRecord::Associations::CollectionAssociation
include ::ActiveRecord::Associations::ForeignAssociation
## CUSTOM
def ids_reader
if loaded?
target.pluck(reflection.active_record_primary_key)
elsif !target.empty?
load_target.pluck(reflection.active_record_primary_key)
else
stale_state || column_default_value
end
end
def ids_writer(ids)
ids = ids.presence || column_default_value
owner.write_attribute(source_attr, ids)
return unless owner.persisted? && owner.attribute_changed?(source_attr)
owner.update_attribute(source_attr, ids)
end
def size
if loaded?
target.size
elsif !target.empty?
unsaved_records = target.select(&:new_record?)
unsaved_records.size + stale_state.size
else
stale_state&.size || 0
end
end
def empty?
size.zero?
end
def include?(record)
return false unless record.is_a?(reflection.klass)
return include_in_memory?(record) if record.new_record?
(!target.empty? && target.include?(record)) ||
stale_state&.include?(record.read_attribute(klass_attr))
end
def load_target
if stale_target? || find_target?
persisted_records = (find_target || []) + target.extract!(&:persisted?)
@target = merge_target_lists(persisted_records, target)
end
loaded!
target
end
def build_changes(from_target = false)
return yield if defined?(@_building_changes) && @_building_changes
@_building_changes = true
yield.tap { ids_writer(from_target ? ids_reader : stale_state) }
ensure
@_building_changes = nil
end
def trigger(prefix, before_ids, after_ids)
removed_ids = before_ids - after_ids
added_ids = after_ids - before_ids
if removed_ids.any?
callbacks_for(method = :"#{prefix}_remove").each do |callback|
target_scope.find(removed_ids).each do |record|
callback.call(method, owner, record)
end
end
end
if added_ids.any?
callbacks_for(method = :"#{prefix}_add").each do |callback|
target_scope.find(added_ids).each do |record|
callback.call(method, owner, record)
end
end
end
end
## HAS MANY
def handle_dependency
case options[:dependent]
when :restrict_with_exception
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
when :restrict_with_error
unless empty?
record = owner.class.human_attribute_name(reflection.name).downcase
owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
throw(:abort)
end
when :destroy
load_target.each { |t| t.destroyed_by_association = reflection }
destroy_all
when :destroy_async
load_target.each do |t|
t.destroyed_by_association = reflection
end
unless target.empty?
association_class = target.first.class
primary_key_column = association_class.primary_key.to_sym
ids = target.collect do |assoc|
assoc.public_send(primary_key_column)
end
enqueue_destroy_association(
owner_model_name: owner.class.to_s,
owner_id: owner.id,
association_class: association_class.to_s,
association_ids: ids,
association_primary_key_column: primary_key_column,
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
)
end
else
delete_all
end
end
def insert_record(record, *)
(record.persisted? || super).tap do |saved|
ids_rewriter(record.read_attribute(klass_attr), :<<) if saved
end
end
## BELONGS TO
def default(&block)
writer(owner.instance_exec(&block)) if reader.nil?
end
private
## CUSTOM
def _create_record(attributes, raises = false, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| _create_record(attr, raises, &block) }
else
build_record(attributes, &block).tap do |record|
transaction do
result = nil
add_to_target(record) do
result = insert_record(record, true, raises) { @_was_loaded = loaded? }
end
raise ActiveRecord::Rollback unless result
end
end
end
end
# When the idea is to nullify the association, then just set the owner
# +primary_key+ as empty
def delete_count(method, scope, ids)
size_cache = scope.delete_all if method == :delete_all
(size_cache || ids.size).tap { ids_rewriter(ids, :-) }
end
def delete_or_nullify_all_records(method)
delete_count(method, scope, ids_reader)
end
# Deletes the records according to the <tt>:dependent</tt> option.
def delete_records(records, method)
ids = read_records_ids(records)
if method == :destroy
records.each(&:destroy!)
ids_rewriter(ids, :-)
else
scope = self.scope.where(klass_attr => records)
delete_count(method, scope, ids)
end
end
def source_attr
reflection.foreign_key
end
def klass_attr
reflection.active_record_primary_key
end
def read_records_ids(records)
return unless records.present?
Array.wrap(records).each_with_object(klass_attr).map(&:read_attribute).presence
end
def ids_rewriter(ids, operator)
list = owner[source_attr] ||= []
list = list.public_send(operator, ids)
owner[source_attr] = list.uniq.compact.presence || column_default_value
return if @_building_changes || !owner.persisted?
owner.update_attribute(source_attr, list)
end
def column_default_value
owner.class.columns_hash[source_attr].default
end
def callback(*)
true # This is handled/trigger when the owner record actually changes
end
## HAS MANY
def replace_records(*)
build_changes(true) { super }
end
def concat_records(*)
build_changes(true) { super }
end
def delete_or_destroy(*)
build_changes(true) { super }
end
def difference(a, b)
a - b
end
def intersection(a, b)
a & b
end
## BELONGS TO
def scope_for_create
super.except!(klass.primary_key)
end
def find_target?
!loaded? && foreign_key_present? && klass
end
def foreign_key_present?
stale_state.present?
end
def invertible_for?(record)
return unless (inverse = inverse_reflection_for(record))
collection_class = ::ActiveRecord::Associations::HasManyAssociation
inverse.is_a?(collection_class) && inverse.connected_through_array?
end
def stale_state
owner.read_attribute(source_attr)
end
end
::ActiveRecord::Associations.const_set(:BelongsToManyAssociation, BelongsToManyAssociation)
end
end
end
================================================
FILE: lib/torque/postgresql/associations/builder/belongs_to_many.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module Builder
class BelongsToMany < ::ActiveRecord::Associations::Builder::CollectionAssociation
def self.macro
:belongs_to_many
end
def self.valid_options(options)
super + [:touch, :optional, :default, :dependent, :primary_key, :required]
end
def self.valid_dependent_options
[:restrict_with_error, :restrict_with_exception]
end
def self.define_callbacks(model, reflection)
super
add_touch_callbacks(model, reflection) if reflection.options[:touch]
add_default_callbacks(model, reflection) if reflection.options[:default]
add_change_callbacks(model, reflection)
end
def self.define_readers(mixin, name)
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}
association(:#{name}).reader
end
CODE
end
def self.define_writers(mixin, name)
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}=(value)
association(:#{name}).writer(value)
end
CODE
end
def self.add_default_callbacks(model, reflection)
model.before_validation ->(o) do
o.association(reflection.name).default(&reflection.options[:default])
end
end
def self.add_touch_callbacks(model, reflection)
foreign_key = reflection.foreign_key
n = reflection.name
touch = reflection.options[:touch]
callback = ->(changes_method) do
->(record) do
BelongsToMany.touch_record(record, record.send(changes_method), foreign_key,
n, touch, belongs_to_touch_method)
end
end
model.after_create callback.call(:saved_changes), if: :saved_changes?
model.after_update callback.call(:saved_changes), if: :saved_changes?
model.after_destroy callback.call(:changes_to_save)
model.after_touch callback.call(:changes_to_save)
end
def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc:
old_foreign_ids = changes[foreign_key] && changes[foreign_key].first
if old_foreign_ids.present?
association = o.association(name)
reflection = association.reflection
klass = association.klass
primary_key = reflection.association_primary_key(klass)
old_records = klass.find_by(primary_key => old_foreign_ids)
old_records&.map do |old_record|
if touch != true
old_record.send(touch_method, touch)
else
old_record.send(touch_method)
end
end
end
o.send(name)&.map do |record|
if record && record.persisted?
if touch != true
record.send(touch_method, touch)
else
record.send(touch_method)
end
end
end
end
def self.add_change_callbacks(model, reflection)
foreign_key = reflection.foreign_key
name = reflection.name
model.before_save ->(record) do
before, after = record.changes[foreign_key]
record.association(name).trigger(:before, before, after) if before && after
end
model.after_save ->(record) do
before, after = record.previous_changes[foreign_key]
record.association(name).trigger(:after, before, after) if before && after
end
end
def self.add_destroy_callbacks(model, reflection)
model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
end
def self.define_validations(model, reflection)
if reflection.options.key?(:required)
reflection.options[:optional] = !reflection.options.delete(:required)
end
if reflection.options[:optional].nil?
required = model.belongs_to_many_required_by_default
else
required = !reflection.options[:optional]
end
super
if required
model.validates_presence_of reflection.name, message: :required
end
end
end
::ActiveRecord::Associations::Builder.const_set(:BelongsToMany, BelongsToMany)
end
end
end
end
================================================
FILE: lib/torque/postgresql/associations/builder/has_many.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module Builder
module HasMany
def valid_options(options)
super + [:array]
end
end
::ActiveRecord::Associations::Builder::HasMany.extend(HasMany)
end
end
end
end
================================================
FILE: lib/torque/postgresql/associations/builder.rb
================================================
require_relative 'builder/belongs_to_many'
require_relative 'builder/has_many'
================================================
FILE: lib/torque/postgresql/associations/foreign_association.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module ForeignAssociation
# There is no problem of adding temporary items on target because
# CollectionProxy will handle memory and persisted relationship
def inversed_from(record)
return super unless reflection.connected_through_array?
self.target ||= []
self.target.push(record) unless self.target.include?(record)
@inversed = self.target.present?
end
# The binds and the cache are getting mixed and caching the wrong query
def skip_statement_cache?(*)
super || reflection.connected_through_array?
end
private
# This is mainly for the has many when connect through an array to add
# its id to the list of the inverse belongs to many association
def set_owner_attributes(record)
return super unless reflection.connected_through_array?
add_id = owner[reflection.active_record_primary_key]
list = record[reflection.foreign_key] ||= []
list.push(add_id) unless list.include?(add_id)
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/associations/preloader/association.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module Preloader
module Association
delegate :connected_through_array?, to: :@reflection
# For reflections connected through an array, make sure to properly
# decuple the list of ids and set them as associated with the owner
def run
return self if run?
return super unless connected_through_array?
@run = true
send("run_array_for_#{@reflection.macro}")
self
end
# Correctly correlate records when they are connected theough an array
def set_inverse(record)
return super unless connected_through_array? && @reflection.macro == :has_many
# Only the first owner is associated following the same instruction
# on the original implementation
convert_key(record[association_key_name])&.each do |key|
if owners = owners_by_key[key]
association = owners.first.association(reflection.name)
association.set_inverse_instance(record)
end
end
end
# Requires a slight change when running on has many since the value
# of the foreign key being an array
def load_records(raw_records = nil)
return super unless connected_through_array? && @reflection.macro == :has_many
@records_by_owner = {}.compare_by_identity
raw_records ||= loader_query.records_for([self])
@preloaded_records = raw_records.select do |record|
assignments = false
keys = convert_key(record[association_key_name]) || []
owners_by_key.values_at(*keys).each do |owner|
entries = (@records_by_owner[owner] ||= [])
if reflection.collection? || entries.empty?
entries << record
assignments = true
end
end
assignments
end
end
# Make sure to change the process when connected through an array
def owners_by_key
return super unless connected_through_array?
@owners_by_key ||= owners.each_with_object({}) do |owner, result|
Array.wrap(convert_key(owner[owner_key_name])).each do |key|
(result[key] ||= []) << owner
end
end
end
private
# Specific run for belongs_many association
def run_array_for_belongs_to_many
# Add reverse to has_many
records = groupped_records
owners.each do |owner|
items = records.values_at(*Array.wrap(owner[owner_key_name]))
associate_records_to_owner(owner, items.flatten)
end
end
# Specific run for has_many association
def run_array_for_has_many
# Add reverse to belongs_to_many
records = Hash.new { |h, k| h[k] = [] }
groupped_records.each do |ids, record|
ids.each { |id| records[id].concat(Array.wrap(record)) }
end
records.default_proc = nil
owners.each do |owner|
associate_records_to_owner(owner, records[owner[owner_key_name]] || [])
end
end
# Build correctly the constraint condition in order to get the
# associated ids
def records_for(ids, &block)
return super unless connected_through_array?
condition = scope.arel_table[association_key_name]
condition = reflection.build_id_constraint(condition, ids.flatten.uniq)
scope.where(condition).load(&block)
end
def associate_records_to_owner(owner, records)
return super unless connected_through_array?
association = owner.association(reflection.name)
association.loaded!
association.target.concat(records)
end
def groupped_records
preloaded_records.group_by do |record|
convert_key(record[association_key_name])
end
end
end
::ActiveRecord::Associations::Preloader::Association.prepend(Association)
end
end
end
end
================================================
FILE: lib/torque/postgresql/associations/preloader/loader_query.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Associations
module Preloader
module LoaderQuery
def foreign_column
@foreign_column ||= scope.columns_hash[association_key_name.to_s]
end
def load_records_for_keys(keys, &block)
condition = query_condition_for(keys)
return super if condition.nil?
scope.where(condition).load(&block)
end
def query_condition_for(keys)
return unless connected_through_array?
value = scope.cast_for_condition(foreign_column, keys.to_a)
scope.table[association_key_name].overlaps(value)
end
def connected_through_array?
!association_key_name.is_a?(Array) && foreign_column&.array?
end
end
::ActiveRecord::Associations::Preloader::Association::LoaderQuery
.prepend(LoaderQuery)
end
end
end
end
================================================
FILE: lib/torque/postgresql/associations/preloader.rb
================================================
require_relative 'preloader/association'
require_relative 'preloader/loader_query'
================================================
FILE: lib/torque/postgresql/associations.rb
================================================
require_relative 'associations/association_scope'
require_relative 'associations/belongs_to_many_association'
require_relative 'associations/foreign_association'
require_relative 'associations/builder'
require_relative 'associations/preloader'
association_mod = Torque::PostgreSQL::Associations::ForeignAssociation
::ActiveRecord::Associations::HasManyAssociation.prepend(association_mod)
::ActiveRecord::Associations::BelongsToManyAssociation.prepend(association_mod)
================================================
FILE: lib/torque/postgresql/attributes/builder/enum.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
module Builder
class Enum
VALID_TYPES = %i[enum enum_set].freeze
FN = '::Torque::PostgreSQL::FN'
attr_accessor :klass, :attribute, :subtype, :options, :values,
:klass_module, :instance_module
# Start a new builder of methods for enum values on ActiveRecord::Base
def initialize(klass, attribute, options)
@klass = klass
@attribute = attribute.to_s
@subtype = klass.attribute_types[@attribute]
@options = options
raise Interrupt unless subtype.respond_to?(:klass)
@values = subtype.klass.values
if @options[:only]
@values &= Array(@options[:only]).map(&:to_s)
end
if @options[:except]
@values -= Array(@options[:except]).map(&:to_s)
end
end
# Get the list of methods based on enum values
def values_methods
return @values_methods if defined?(@values_methods)
prefix = options.fetch(:prefix, nil)
suffix = options.fetch(:suffix, nil)
prefix = attribute if prefix == true
suffix = attribute if suffix == true
base = [prefix, '%s', suffix].compact.join('_')
@values_methods = begin
values.map do |val|
key = val.downcase.tr('- ', '__')
scope = base % key
ask = scope + '?'
bang = scope + '!'
[key, [scope, ask, bang, val]]
end.to_h
end
end
# Check if it's building the methods for sets
def set_features?
options[:set_features].present?
end
# Check if any of the methods that will be created get in conflict
# with the base class methods
def conflicting?
return if options[:force] == true
attributes = attribute.pluralize
dangerous?(attributes, true)
dangerous?("#{attributes}_keys", true)
dangerous?("#{attributes}_texts", true)
dangerous?("#{attributes}_options", true)
dangerous?("#{attribute}_text")
if set_features?
dangerous?("has_#{attributes}", true)
dangerous?("has_any_#{attributes}", true)
end
values_methods.each do |attr, (scope, ask, bang, *)|
dangerous?(scope, true)
dangerous?(bang)
dangerous?(ask)
end
rescue Interrupt => err
raise ArgumentError, <<-MSG.squish
Enum #{subtype.name} was not able to generate requested
methods because the method #{err} already exists in
#{klass.name}.
MSG
end
# Create all methods needed
def build
@klass_module = Module.new
@instance_module = Module.new
plural
stringify
all_values
set_scopes if set_features?
klass.extend klass_module
klass.include instance_module
end
private
# Check if the method already exists in the reference class
def dangerous?(method_name, class_method = false)
if class_method
if klass.dangerous_class_method?(method_name)
raise Interrupt, method_name.to_s
end
else
if klass.dangerous_attribute_method?(method_name)
raise Interrupt, method_name.to_s
end
end
rescue Interrupt => e
raise e if Torque::PostgreSQL.config.enum.raise_conflicting
type = class_method ? 'class method' : 'instance method'
indicator = class_method ? '.' : '#'
Torque::PostgreSQL.logger.info(<<~MSG.squish)
Creating #{class_method} :#{method_name} for enum.
Overwriting existing method #{klass.name}#{indicator}#{method_name}.
MSG
end
# Create the method that allow access to the list of values
def plural
enum_klass = subtype.klass.name
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{attribute.pluralize} # def roles
::#{enum_klass}.values # Enum::Roles.values
end # end
def #{attribute.pluralize}_keys # def roles_keys
::#{enum_klass}.keys # Enum::Roles.keys
end # end
def #{attribute.pluralize}_texts # def roles_texts
::#{enum_klass}.members.map do |member| # Enum::Roles.members do |member|
member.text('#{attribute}', self) # member.text('role', self)
end # end
end # end
def #{attribute.pluralize}_options # def roles_options
#{attribute.pluralize}_texts.zip(::#{enum_klass}.values) # roles_texts.zip(Enum::Roles.values)
end # end
RUBY
end
# Create additional methods when the enum is a set, which needs
# better ways to check if values are present or not
def set_scopes
cast_type = subtype.name.chomp('[]')
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
def has_#{attribute.pluralize}(*values) # def has_roles(*values)
attr = arel_table['#{attribute}'] # attr = arel_table['role']
value = #{FN}.bind_with(attr, values) # value = ::Torque::PostgreSQL::FN.bind_with(attr, values)
where(attr.contains(value.pg_cast('#{cast_type}[]'))) # where(attr.contains(value.pg_cast('roles[]')))
end # end
def has_any_#{attribute.pluralize}(*values) # def has_any_roles(*values)
attr = arel_table['#{attribute}'] # attr = arel_table['role']
value = #{FN}.bind_with(attr, values) # value = ::Torque::PostgreSQL::FN.bind_with(attr, values)
where(attr.overlaps(value.pg_cast('#{cast_type}[]'))) # where(attr.overlaps(value.pg_cast('roles[]')))
end # end
RUBY
end
# Create the method that turn the attribute value into text using
# the model scope
def stringify
instance_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{attribute}_text # def role_text
#{attribute}.text('#{attribute}', self) # role.text('role', self)
end # end
RUBY
end
# Create all the methods that represent actions related to the
# attribute value
def all_values
klass_content = ''
instance_content = ''
enum_klass = subtype.klass.name
values_methods.each do |key, (scope, ask, bang, val)|
klass_content += <<-RUBY
def #{scope} # def admin
attr = arel_table['#{attribute}'] # attr = arel_table['role']
where(::#{enum_klass}.scope(attr, '#{val}')) # where(Enum::Roles.scope(attr, 'admin'))
end # end
RUBY
instance_content += <<-RUBY
def #{ask} # def admin?
#{attribute}.#{key}? # role.admin?
end # end
def #{bang} # admin!
self.#{attribute} = '#{val}' # self.role = 'admin'
return unless #{attribute}_changed? # return unless role_changed?
return save! if Torque::PostgreSQL.config.enum.save_on_bang
true # true
end # end
RUBY
end
klass_module.module_eval(klass_content)
instance_module.module_eval(instance_content)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/builder/full_text_search.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
module Builder
class FullTextSearch
attr_accessor :klass, :attribute, :options, :klass_module,
:default_rank, :default_mode, :default_order, :default_language
def initialize(klass, attribute, options = {})
@klass = klass
@attribute = attribute
@options = options
@default_rank = options[:with_rank] == true ? 'rank' : options[:with_rank]&.to_s
@default_mode = options[:mode] || PostgreSQL.config.full_text_search.default_mode
@default_order =
case options[:order]
when :asc, true then :asc
when :desc then :desc
else false
end
@default_language = options[:language] if options[:language].is_a?(String) ||
options[:language].is_a?(Symbol)
@default_language ||= PostgreSQL.config.full_text_search.default_language.to_s
end
# What is the name of the scope to be added to the model
def scope_name
@scope_name ||= [
options[:prefix],
:full_text_search,
options[:suffix],
].compact.join('_')
end
# Just check if the scope name is already defined
def conflicting?
return if options[:force] == true
if klass.dangerous_class_method?(scope_name)
raise Interrupt, scope_name.to_s
end
end
# Create the proper scope
def build
@klass_module = Module.new
add_scope_to_module
klass.extend klass_module
end
# Creates a class method as the scope that builds the full text search
def add_scope_to_module
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{scope_name}(value#{scope_args})
attr = arel_table['#{attribute}']
fn = ::Torque::PostgreSQL::FN
lang = language.to_s if !language.is_a?(::Symbol)
lang ||= arel_table[language.to_s] if has_attribute?(language)
lang ||= public_send(language) if respond_to?(language)
function = {
default: :to_tsquery,
phrase: :phraseto_tsquery,
plain: :plainto_tsquery,
web: :websearch_to_tsquery,
}[mode.to_sym]
raise ::ArgumentError, <<~MSG.squish if lang.blank?
Unable to determine language from \#{language.inspect}.
MSG
raise ::ArgumentError, <<~MSG.squish if function.nil?
Invalid mode \#{mode.inspect} for full text search.
MSG
value = fn.bind(:value, value.to_s, attr.type_caster)
lang = fn.bind(:lang, lang, attr.type_caster) if lang.is_a?(::String)
query = fn.public_send(function, lang, value)
ranker = fn.ts_rank(attr, query) if rank || order
result = where(fn.infix(:"@@", attr, query))
result = result.order(ranker.public_send(order == :desc ? :desc : :asc)) if order
result.select_extra_values += [ranker.as(rank == true ? 'rank' : rank.to_s)] if rank
result
end
RUBY
end
# Returns the arguments to be used on the scope
def scope_args
args = +''
args << ", order: #{default_order.inspect}"
args << ", rank: #{default_rank.inspect}"
args << ", language: #{default_language.inspect}"
args << ", mode: :#{default_mode}"
args
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/builder/period.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
module Builder
class Period
DIRECT_ACCESS_REGEX = /_?%s_?/
SUPPORTED_TYPES = %i[daterange tsrange tstzrange].freeze
CURRENT_GETTERS = {
daterange: 'Date.current',
tsrange: 'Time.zone.now',
tstzrange: 'Time.zone.now',
}.freeze
TYPE_CASTERS = {
daterange: :date,
tsrange: :timestamp,
tstzrange: :timestamp,
}.freeze
FN = '::Torque::PostgreSQL::FN'
attr_accessor :klass, :attribute, :options, :type, :default, :current_getter,
:type_caster, :threshold, :dynamic_threshold, :klass_module, :instance_module
# Start a new builder of methods for period values on
# ActiveRecord::Base
def initialize(klass, attribute, options)
@klass = klass
@attribute = attribute.to_s
@options = options
@type = klass.attribute_types[@attribute].type
raise ArgumentError, <<-MSG.squish unless SUPPORTED_TYPES.include?(type)
Period cannot be generated for #{attribute} because its type
#{type} is not supported. Only #{SUPPORTED_TYPES.join(', ')} are supported.
MSG
@current_getter = CURRENT_GETTERS[type]
@type_caster = TYPE_CASTERS[type]
@default = options[:pessimistic].blank?
end
# Check if can identify a threshold field
def threshold
@threshold ||= begin
option = options[:threshold]
return if option.eql?(false)
unless option.eql?(true)
return option.is_a?(String) ? option.to_sym : option
end
attributes = klass.attribute_names
default_name = Torque::PostgreSQL.config.period.auto_threshold.to_s
raise ArgumentError, <<-MSG.squish unless attributes.include?(default_name)
Unable to find the #{default_name} to use as threshold for period
features for #{attribute} in #{klass.name} model.
MSG
check_type = klass.attribute_types[default_name].type
raise ArgumentError, <<-MSG.squish unless check_type.eql?(:interval)
The #{default_name} has the wrong type to be used as threshold.
Expected :interval got #{check_type.inspect} in #{klass.name} model.
MSG
default_name.to_sym
end
end
# Generate all the method names
def method_names
@method_names ||= default_method_names.merge(options.fetch(:methods, {}))
end
# Get the list of methods associated withe the class
def klass_method_names
@klass_method_names ||= method_names.to_a[0..22].to_h
end
# Get the list of methods associated withe the instances
def instance_method_names
@instance_method_names ||= method_names.to_a[23..29].to_h
end
# Check if any of the methods that will be created get in conflict
# with the base class methods
def conflicting?
return if options[:force] == true
klass_method_names.values.each { |name| dangerous?(name, true) }
instance_method_names.values.each { |name| dangerous?(name) }
rescue Interrupt => err
raise ArgumentError, <<-MSG.squish
#{subtype.class.name} was not able to generate requested
methods because the method #{err} already exists in
#{klass.name}.
MSG
end
# Create all methods needed
def build
@klass_module = Module.new
@instance_module = Module.new
value_args = ['value']
left_right_args = ['left', 'right = nil']
## Klass methods
build_method_helper :klass, :current_on, value_args # 00
build_method_helper :klass, :current # 01
build_method_helper :klass, :not_current # 02
build_method_helper :klass, :containing, value_args # 03
build_method_helper :klass, :not_containing, value_args # 04
build_method_helper :klass, :overlapping, left_right_args # 05
build_method_helper :klass, :not_overlapping, left_right_args # 06
build_method_helper :klass, :starting_after, value_args # 07
build_method_helper :klass, :starting_before, value_args # 08
build_method_helper :klass, :finishing_after, value_args # 09
build_method_helper :klass, :finishing_before, value_args # 10
if threshold.present?
build_method_helper :klass, :real_containing, value_args # 11
build_method_helper :klass, :real_overlapping, left_right_args # 12
build_method_helper :klass, :real_starting_after, value_args # 13
build_method_helper :klass, :real_starting_before, value_args # 14
build_method_helper :klass, :real_finishing_after, value_args # 15
build_method_helper :klass, :real_finishing_before, value_args # 16
end
unless type.eql?(:daterange)
build_method_helper :klass, :containing_date, value_args # 17
build_method_helper :klass, :not_containing_date, value_args # 18
build_method_helper :klass, :overlapping_date, left_right_args # 19
build_method_helper :klass, :not_overlapping_date, left_right_args # 20
if threshold.present?
build_method_helper :klass, :real_containing_date, value_args # 21
build_method_helper :klass, :real_overlapping_date, left_right_args # 22
end
end
## Instance methods
build_method_helper :instance, :current? # 23
build_method_helper :instance, :current_on?, value_args # 24
build_method_helper :instance, :start # 25
build_method_helper :instance, :finish # 26
if threshold.present?
build_method_helper :instance, :real # 27
build_method_helper :instance, :real_start # 28
build_method_helper :instance, :real_finish # 29
end
klass.extend klass_module
klass.include instance_module
end
def build_method_helper(type, key, args = [])
method_name = method_names[key]
return if method_name.nil?
method_content = send("#{type}_#{key}")
method_content = define_string_method(method_name, method_content, args)
source_module = send("#{type}_module")
source_module.module_eval(method_content)
end
private
# Generates the default method names
def default_method_names
list = Torque::PostgreSQL.config.period.method_names.dup
if options.fetch(:prefixed, true)
list.transform_values { |value| format(value, attribute) }
else
list = list.merge(Torque::PostgreSQL.config.period.direct_method_names)
list.transform_values { |value| value.gsub(DIRECT_ACCESS_REGEX, '') }
end
end
# Check if the method already exists in the reference class
def dangerous?(method_name, class_method = false)
if class_method
if klass.dangerous_class_method?(method_name)
raise Interrupt, method_name.to_s
end
else
if klass.dangerous_attribute_method?(method_name)
raise Interrupt, method_name.to_s
end
end
end
## BUILDER HELPERS
def define_string_method(name, body, args = [])
headline = "def #{name}"
headline += "(#{args.join(', ')})"
[headline, body, 'end'].join("\n")
end
def arel_attribute
@arel_attribute ||= "arel_table[#{attribute.inspect}]"
end
def arel_default_sql
@arel_default_sql ||= arel_sql_bind(@default.inspect)
end
def arel_sql_bind(value)
"#{FN}.bind_with(#{arel_attribute}, #{value})"
end
# Check how to provide the threshold value
def arel_threshold_value
@arel_threshold_value ||= begin
case threshold
when Symbol, String
"arel_table['#{threshold}']"
when ActiveSupport::Duration
value = "'#{threshold.to_i} seconds'"
"::Arel.sql(\"#{value}\").pg_cast(:interval)"
when Numeric
value = threshold.to_i.to_s
value << type_caster.eql?(:date) ? ' days' : ' seconds'
value = "'#{value}'"
"::Arel.sql(\"#{value}\").pg_cast(:interval)"
end
end
end
# Start at version of the value
def arel_start_at
@arel_start_at ||= arel_named_function('lower', arel_attribute)
end
# Finish at version of the value
def arel_finish_at
@arel_finish_at ||= arel_named_function('upper', arel_attribute)
end
# Start at version of the value with threshold
def arel_real_start_at
return arel_start_at unless threshold.present?
@arel_real_start_at ||= begin
result = +"(#{arel_start_at} - #{arel_threshold_value})"
result << '.pg_cast(:date)' if type.eql?(:daterange)
result
end
end
# Finish at version of the value with threshold
def arel_real_finish_at
return arel_finish_at unless threshold.present?
@arel_real_finish_at ||= begin
result = +"(#{arel_finish_at} + #{arel_threshold_value})"
result << '.pg_cast(:date)' if type.eql?(:daterange)
result
end
end
# When the time has a threshold, then the real attribute is complex
def arel_real_attribute
return arel_attribute unless threshold.present?
@arel_real_attribute ||= arel_named_function(
type, arel_real_start_at, arel_real_finish_at,
)
end
# Create an arel version of the type with the following values
def arel_convert_to_type(left, right = nil, set_type = nil)
arel_named_function(set_type || type, left, right || left)
end
# Create an arel named function
def arel_named_function(name, *args)
result = +"#{FN}.#{name}"
result << '(' << args.join(', ') << ')' if args.present?
result
end
# Create an arel version of +nullif+ function
def arel_nullif(*args)
arel_named_function('nullif', *args)
end
# Create an arel version of +coalesce+ function
def arel_coalesce(*args)
arel_named_function('coalesce', *args)
end
# Create an arel version of an empty value for the range
def arel_empty_value
arel_convert_to_type('::Arel.sql(\'NULL\')')
end
# Convert timestamp range to date range format
def arel_daterange(real = false)
arel_named_function(
'daterange',
(real ? arel_real_start_at : arel_start_at) + '.pg_cast(:date)',
(real ? arel_real_finish_at : arel_finish_at) + '.pg_cast(:date)',
'::Arel.sql("\'[]\'")',
)
end
def arel_check_condition(type)
checker = arel_nullif(arel_real_attribute, arel_empty_value)
checker << ".#{type}(value.pg_cast(#{type_caster.inspect}))"
arel_coalesce(checker, arel_default_sql)
end
def arel_formatting_value(condition = nil, value = 'value', cast: nil)
[
"#{value} = arel_table[#{value}] if #{value}.is_a?(Symbol)",
"unless #{value}.respond_to?(:pg_cast)",
" #{value} = #{FN}.bind_with(#{arel_attribute}, #{value})",
(" #{value} = #{value}.pg_cast(#{cast.inspect})" if cast),
'end',
condition,
].compact.join("\n")
end
def arel_formatting_left_right(condition, set_type = nil, cast: nil)
[
arel_formatting_value(nil, 'left', cast: cast),
'',
'if right.present?',
' ' + arel_formatting_value(nil, 'right', cast: cast),
" value = #{arel_convert_to_type('left', 'right', set_type)}",
'else',
' value = left',
'end',
'',
condition,
].join("\n")
end
## METHOD BUILDERS
def klass_current_on
arel_formatting_value("where(#{arel_check_condition(:contains)})")
end
def klass_current
[
"value = #{arel_sql_bind(current_getter)}",
"where(#{arel_check_condition(:contains)})",
].join("\n")
end
def klass_not_current
[
"value = #{arel_sql_bind(current_getter)}",
"where.not(#{arel_check_condition(:contains)})",
].join("\n")
end
def klass_containing
arel_formatting_value("where(#{arel_attribute}.contains(value))")
end
def klass_not_containing
arel_formatting_value("where.not(#{arel_attribute}.contains(value))")
end
def klass_overlapping
arel_formatting_left_right("where(#{arel_attribute}.overlaps(value))")
end
def klass_not_overlapping
arel_formatting_left_right("where.not(#{arel_attribute}.overlaps(value))")
end
def klass_starting_after
arel_formatting_value("where((#{arel_start_at}).gt(value))")
end
def klass_starting_before
arel_formatting_value("where((#{arel_start_at}).lt(value))")
end
def klass_finishing_after
arel_formatting_value("where((#{arel_finish_at}).gt(value))")
end
def klass_finishing_before
arel_formatting_value("where((#{arel_finish_at}).lt(value))")
end
def klass_real_containing
arel_formatting_value("where(#{arel_real_attribute}.contains(value))")
end
def klass_real_overlapping
arel_formatting_left_right("where(#{arel_real_attribute}.overlaps(value))")
end
def klass_real_starting_after
arel_formatting_value("where(#{arel_real_start_at}.gt(value))")
end
def klass_real_starting_before
arel_formatting_value("where(#{arel_real_start_at}.lt(value))")
end
def klass_real_finishing_after
arel_formatting_value("where(#{arel_real_finish_at}.gt(value))")
end
def klass_real_finishing_before
arel_formatting_value("where(#{arel_real_finish_at}.lt(value))")
end
def klass_containing_date
arel_formatting_value("where(#{arel_daterange}.contains(value))",
cast: :date)
end
def klass_not_containing_date
arel_formatting_value("where.not(#{arel_daterange}.contains(value))",
cast: :date)
end
def klass_overlapping_date
arel_formatting_left_right("where(#{arel_daterange}.overlaps(value))",
:daterange, cast: :date)
end
def klass_not_overlapping_date
arel_formatting_left_right("where.not(#{arel_daterange}.overlaps(value))",
:daterange, cast: :date)
end
def klass_real_containing_date
arel_formatting_value("where(#{arel_daterange(true)}.contains(value))",
cast: :date)
end
def klass_real_overlapping_date
arel_formatting_left_right("where(#{arel_daterange(true)}.overlaps(value))",
:daterange, cast: :date)
end
def instance_current?
"#{method_names[:current_on?]}(#{current_getter})"
end
def instance_current_on?
attr_value = threshold.present? ? method_names[:real] : attribute
default_value = default.inspect
[
"return #{default_value} if #{attr_value}.nil?",
"(#{attr_value}.min.try(:infinite?) || #{attr_value}.min <= value) &&",
" (#{attr_value}.max.try(:infinite?) || #{attr_value}.max > value)",
].join("\n")
end
def instance_start
"#{attribute}&.min"
end
def instance_finish
"#{attribute}&.max"
end
def instance_real
left = method_names[:real_start]
right = method_names[:real_finish]
[
"left = #{left}",
"right = #{right}",
'return unless left || right',
'((left || -::Float::INFINITY)..(right || ::Float::INFINITY))',
].join("\n")
end
def instance_real_start
suffix = type.eql?(:daterange) ? '.to_date' : ''
threshold_value = threshold.is_a?(Symbol) \
? threshold.to_s \
: threshold.to_i.to_s + '.seconds'
[
"return if #{method_names[:start]}.nil?",
"value = #{method_names[:start]}",
"value -= (#{threshold_value} || 0)",
"value#{suffix}"
].join("\n")
end
def instance_real_finish
suffix = type.eql?(:daterange) ? '.to_date' : ''
threshold_value = threshold.is_a?(Symbol) \
? threshold.to_s \
: threshold.to_i.to_s + '.seconds'
[
"return if #{method_names[:finish]}.nil?",
"value = #{method_names[:finish]}",
"value += (#{threshold_value} || 0)",
"value#{suffix}"
].join("\n")
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/builder.rb
================================================
# frozen_string_literal: true
require_relative 'builder/enum'
require_relative 'builder/period'
require_relative 'builder/full_text_search'
module Torque
module PostgreSQL
module Attributes
module Builder
def self.include_on(klass, method_name, builder_klass, **extra, &block)
klass.define_singleton_method(method_name) do |*args, **options|
return unless table_exists?
args.each do |attribute|
# Generate methods on self class
builder = builder_klass.new(self, attribute, extra.merge(options))
builder.conflicting?
builder.build
# Additional settings for the builder
instance_exec(builder, &block) if block.present?
rescue Interrupt
# Not able to build the attribute, maybe pending migrations
end
end
end
def self.search_vector_options(columns:, language: nil, stored: true, **options)
weights = to_search_weights(columns)
operation = to_search_vector_operation(language, weights).to_sql
options[:index] = {
using: PostgreSQL.config.full_text_search.default_index_type,
} if options[:index] == true
options.merge(type: :tsvector, as: operation, stored: stored)
end
def self.to_search_weights(columns)
if !columns.is_a?(Hash)
extras = columns.size > 3 ? columns.size - 3 : 0
weights = %w[A B C] + (['D'] * extras)
columns = Array.wrap(columns).zip(weights).to_h
end
columns.transform_keys(&:to_s)
end
def self.to_search_vector_operation(language, weights)
language ||= PostgreSQL.config.full_text_search.default_language
language = ::Arel.sql(language.is_a?(Symbol) ? language.to_s : "'#{language}'")
simple = weights.size == 1
empty_string = ::Arel.sql("''")
operations = weights.map do |column, weight|
column = ::Arel.sql(column.to_s)
weight = ::Arel.sql("'#{weight}'")
op = FN.to_tsvector(language, FN.coalesce(column, empty_string))
op = FN.setweight(op, weight) unless simple
op
end
FN.concat(*operations)
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/enum.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
class Enum < String
include Comparable
class EnumError < ArgumentError; end
LAZY_VALUE = 0.chr
class << self
include Enumerable
delegate :each, :sample, :size, :length, to: :members
# Find or create the class that will handle the value
def lookup(name)
const = name.to_s.camelize
namespace = PostgreSQL.config.enum.namespace
return namespace.const_get(const) if namespace.const_defined?(const)
namespace.const_set(const, Class.new(Enum))
end
# Provide a method on the given class to setup which enums will be
# manually initialized
def include_on(klass, method_name = nil)
method_name ||= PostgreSQL.config.enum.base_method
Builder.include_on(klass, method_name, Builder::Enum) do |builder|
defined_enums[builder.attribute.to_s] = builder.subtype.klass
end
end
# Overpass new so blank values return only nil
def new(value)
return Lazy.new(self, LAZY_VALUE) if value.blank?
super
end
# Load the list of values in a lazy way
def values
@values ||= self == Enum ? nil : begin
connection.enum_values(type_name).freeze
end
end
# List of values as symbols
def keys
values.map(&:to_sym)
end
# Different from values, it returns the list of items already casted
def members
values.map(&method(:new))
end
# Get the list of the values translated by I18n
def texts
members.map(&:text)
end
# Get a list of values translated and ready for select
def to_options
texts.zip(values)
end
# Fetch a value from the list
# see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/fixtures.rb#L656
# see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/validations/uniqueness.rb#L101
def fetch(value, *)
new(value.to_s) if values.include?(value)
end
alias [] fetch
# Get the type name from its class name
def type_name
@type_name ||= self.name.demodulize.underscore
end
# Check if the value is valid
def valid?(value)
return false if self == Enum
return true if value.equal?(LAZY_VALUE)
self.values.include?(value.to_s)
end
# Build an active record scope for a given attribute against a value
def scope(attribute, value)
attribute.eq(value)
end
private
# Allows checking value existance
def respond_to_missing?(method_name, include_private = false)
valid?(method_name) || super
end
# Allow fast creation of values
def method_missing(method_name, *arguments)
return super if self == Enum
valid?(method_name) ? new(method_name.to_s) : super
end
# Get a connection based on its name
def connection
::ActiveRecord::Base.connection
end
end
# Override string initializer to check for a valid value
def initialize(value)
str_value = value.is_a?(Numeric) ? self.class.values[value.to_i] : value.to_s
raise_invalid(value) unless self.class.valid?(str_value)
super(str_value)
end
# Allow comparison between values of the same enum
def <=>(other)
raise_comparison(other) if other.is_a?(Enum) && other.class != self.class
case other
when Numeric, Enum then to_i <=> other.to_i
when String, Symbol then to_i <=> self.class.values.index(other.to_s)
else raise_comparison(other)
end
end
# Only allow value comparison with values of the same class
def ==(other)
(self <=> other) == 0
rescue EnumError
false
end
alias eql? ==
# Since it can have a lazy value, nil can be true here
def nil?
self == LAZY_VALUE
end
alias empty? nil?
# It only accepts if the other value is valid
def replace(value)
raise_invalid(value) unless self.class.valid?(value)
super
end
# Get a translated version of the value
def text(attr = nil, model = nil)
keys = i18n_keys(attr, model) << self.underscore.humanize
::I18n.translate(keys.shift, default: keys)
end
# Change the string result for lazy value
def to_s
nil? ? '' : super
end
# Get the index of the value
def to_i
self.class.values.index(self)
end
# Change the inspection to show the enum name
def inspect
nil? ? 'nil' : ":#{to_s}"
end
private
# Get the i18n keys to check
def i18n_keys(attr = nil, model = nil)
values = { type: self.class.type_name, value: to_s }
list_from = :i18n_type_scopes
if attr && model
values[:attr] = attr
values[:model] = model.model_name.i18n_key
list_from = :i18n_scopes
end
PostgreSQL.config.enum.send(list_from).map do |key|
(key % values).to_sym
end
end
# Check for valid '?' and '!' methods
def respond_to_missing?(method_name, include_private = false)
name = method_name.to_s
return true if name.chomp!('?')
name.chomp!('!') && self.class.valid?(name)
end
# Allow '_' to be associated to '-'
def method_missing(method_name, *arguments)
name = method_name.to_s
if name.chomp!('?')
self == name
elsif name.chomp!('!')
replace(name) unless self == name
else
super
end
end
# Throw an exception for invalid values
def raise_invalid(value)
if value.is_a?(Numeric)
raise EnumError, "#{value.inspect} is out of bounds of #{self.class.name}"
else
raise EnumError, "#{value.inspect} is not valid for #{self.class.name}"
end
end
# Throw an exception for comparison between different enums
def raise_comparison(other)
raise EnumError, "Comparison of #{self.class.name} with #{self.inspect} failed"
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/enum_set.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
class EnumSet < Set
include Comparable
class EnumSetError < Enum::EnumError; end
class << self
include Enumerable
delegate :each, to: :members
delegate :values, :keys, :members, :texts, :to_options, :valid?, :size,
:length, :connection_specification_name, to: :enum_source
# Find or create the class that will handle the value
def lookup(name, enum_klass)
const = name.to_s.camelize + 'Set'
namespace = PostgreSQL.config.enum.namespace
return namespace.const_get(const) if namespace.const_defined?(const)
klass = Class.new(EnumSet)
klass.const_set('EnumSource', enum_klass)
namespace.const_set(const, klass)
end
# Provide a method on the given class to setup which enum sets will be
# manually initialized
def include_on(klass, method_name = nil)
method_name ||= PostgreSQL.config.enum.set_method
Builder.include_on(klass, method_name, Builder::Enum, set_features: true) do |builder|
defined_enums[builder.attribute.to_s] = builder.subtype
end
end
# The original Enum implementation, for individual values
def enum_source
const_get('EnumSource')
end
# Use the power to get a sample of the value
def sample
new(rand(0..((2 ** size) - 1)))
end
# Overpass new so blank values return only nil
def new(*values)
return Lazy.new(self, []) if values.compact.blank?
super
end
# Get the type name from its class name
def type_name
@type_name ||= enum_source.type_name + '[]'
end
# Fetch a value from the list
# see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/fixtures.rb#L656
# see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/validations/uniqueness.rb#L101
def fetch(value, *)
new(value.to_s) if values.include?(value)
end
alias [] fetch
# Get the power, 2 ** index, of each element
def power(*values)
values.flatten.map do |item|
item = item.to_i if item.is_a?(Enum)
item = values.index(item) unless item.is_a?(Numeric)
next 0 if item.nil? || item >= size
2 ** item
end.reduce(:+)
end
# Build an active record scope for a given attribute against a value
def scope(attribute, value)
attribute.contains(FN.bind_with(attribute, value).pg_cast(type_name))
end
private
# Allows checking value existence
def respond_to_missing?(method_name, include_private = false)
valid?(method_name) || super
end
# Allow fast creation of values
def method_missing(method_name, *arguments)
return super if self == Enum
valid?(method_name) ? new(method_name.to_s) : super
end
end
# Override string initializer to check for a valid value
def initialize(*values)
items =
if values.size === 1 && values.first.is_a?(Numeric)
transform_power(values.first)
else
transform_values(values)
end
@hash = items.zip(Array.new(items.size, true)).to_h
end
# Allow comparison between values of the same enum
def <=>(other)
raise_comparison(other) if other.is_a?(EnumSet) && other.class != self.class
to_i <=>
case other
when Numeric, EnumSet then other.to_i
when String, Symbol then self.class.power(other.to_s)
when Array, Set then self.class.power(*other)
else raise_comparison(other)
end
end
# Only allow value comparison with values of the same class
def ==(other)
(self <=> other) == 0
rescue EnumSetError
false
end
alias eql? ==
# It only accepts if the other value is valid
def replace(*values)
super(transform_values(values))
end
# Get a translated version of the value
def text(attr = nil, model = nil)
map { |item| item.text(attr, model) }.to_sentence
end
alias to_s text
# Get the index of the value
def to_i
self.class.power(@hash.keys)
end
# Change the inspection to show the enum name
def inspect
"[#{map(&:inspect).join(', ')}]"
end
# Replace the setter by instantiating the value
def []=(key, value)
super(key, instantiate(value))
end
# Override the merge method to ensure formatted values
def merge(other)
super other.map(&method(:instantiate))
end
# Override bitwise & operator to ensure formatted values
def &(other)
other = other.entries.map(&method(:instantiate))
values = @hash.keys.select { |k| other.include?(k) }
self.class.new(values)
end
# Operations that requries the other values to be transformed as well
%i[add delete include? subtract].each do |method_name|
define_method(method_name) do |other|
other =
if other.is_a?(self.class)
other
elsif other.is_a?(::Enumerable)
other.map(&method(:instantiate))
else
instantiate(other)
end
super(other)
end
end
private
# Create a new enum instance of the value
def instantiate(value)
value.is_a?(self.class.enum_source) ? value : self.class.enum_source.new(value)
end
# Turn a binary (power) definition into real values
def transform_power(value)
list = value.to_s(2).reverse.chars.map.with_index do |item, idx|
next idx if item.eql?('1')
end
raise raise_invalid(value) if list.size > self.class.size
self.class.members.values_at(*list.compact)
end
# Turn all the values into their respective Enum representations
def transform_values(values)
values = values.first if values.size.eql?(1) && values.first.is_a?(::Enumerable)
values.map(&method(:instantiate)).reject(&:nil?)
end
# Check for valid '?' and '!' methods
def respond_to_missing?(method_name, include_private = false)
name = method_name.to_s
return true if name.chomp!('?')
name.chomp!('!') && self.class.valid?(name)
end
# Allow '_' to be associated to '-'
def method_missing(method_name, *arguments)
name = method_name.to_s
if name.chomp!('?')
include?(name)
elsif name.chomp!('!')
add(name) unless include?(name)
else
super
end
end
# Throw an exception for invalid values
def raise_invalid(value)
if value.is_a?(Numeric)
raise EnumSetError, "#{value.inspect} is out of bounds of #{self.class.name}"
else
raise EnumSetError, "#{value.inspect} is not valid for #{self.class.name}"
end
end
# Throw an exception for comparison between different enums
def raise_comparison(other)
raise EnumSetError, "Comparison of #{self.class.name} with #{self.inspect} failed"
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/full_text_search.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
# For now, full text search doesn't have it's own class
module FullTextSearch
class << self
# Provide a method on the given class to setup which full text search
# columns will be manually initialized
def include_on(klass, method_name = nil)
method_name ||= PostgreSQL.config.full_text_search.base_method
Builder.include_on(klass, method_name, Builder::FullTextSearch)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/lazy.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
class Lazy < BasicObject
def initialize(klass, *values)
@klass, @values = klass, values
end
def ==(other)
other.nil?
end
def nil?
true
end
def inspect
'nil'
end
def __class__
Lazy
end
def method_missing(name, *args, &block)
@klass.new(*@values).send(name, *args, &block)
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes/period.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Attributes
# For now, period doesn't have it's own class
module Period
class << self
# Provide a method on the given class to setup which period columns
# will be manually initialized
def include_on(klass, method_name = nil)
method_name ||= PostgreSQL.config.period.base_method
Builder.include_on(klass, method_name, Builder::Period)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/attributes.rb
================================================
require_relative 'attributes/lazy'
require_relative 'attributes/builder'
================================================
FILE: lib/torque/postgresql/autosave_association.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module AutosaveAssociation
module ClassMethods
# Since belongs to many is a collection, the callback would normally go
# to +after_create+. However, since it is a +belongs_to+ kind of
# association, it neds to be executed +before_save+
def add_autosave_association_callbacks(reflection)
return super unless reflection.macro.eql?(:belongs_to_many)
save_method = :"autosave_associated_records_for_#{reflection.name}"
define_non_cyclic_method(save_method) do
save_belongs_to_many_association(reflection)
end
before_save(save_method)
define_autosave_validation_callbacks(reflection)
end
end
# Ensure the right way to execute +save_collection_association+ and also
# keep it as a single change using +build_changes+
def save_belongs_to_many_association(reflection)
previously_new_record_before_save = (@new_record_before_save ||= false)
@new_record_before_save = new_record?
association = association_instance_get(reflection.name)
association&.build_changes { save_collection_association(reflection) }
rescue ::ActiveRecord::RecordInvalid
throw(:abort)
ensure
@new_record_before_save = previously_new_record_before_save
end
end
::ActiveRecord::Base.singleton_class.prepend(AutosaveAssociation::ClassMethods)
::ActiveRecord::Base.include(AutosaveAssociation)
end
end
================================================
FILE: lib/torque/postgresql/auxiliary_statement/recursive.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class AuxiliaryStatement
class Recursive < AuxiliaryStatement
# Setup any additional option in the recursive mode
def initialize(*, **options)
super
@connect = options[:connect]&.to_a&.first
@union_all = options[:union_all]
@sub_query = options[:sub_query]
if options.key?(:with_depth)
@depth = options[:with_depth].values_at(:name, :start, :as)
@depth[0] ||= 'depth'
end
if options.key?(:with_path)
@path = options[:with_path].values_at(:name, :source, :as)
@path[0] ||= 'path'
end
end
private
# Build the string or arel query
def build_query(base)
# Expose columns and get the list of the ones for select
columns = expose_columns(base, @query.try(:arel_table))
sub_columns = columns.dup
type = @union_all.present? ? 'all' : ''
# Build any extra columns that are dynamic and from the recursion
extra_columns(base, columns, sub_columns)
# Prepare the query depending on its type
if @query.is_a?(String) && @sub_query.is_a?(String)
args = @args.each_with_object({}) { |h, (k, v)| h[k] = base.connection.quote(v) }
::Arel.sql("(#{@query} UNION #{type.upcase} #{@sub_query})" % args)
elsif relation_query?(@query)
@query = @query.where(@where) if @where.present?
@bound_attributes.concat(@query.send(:bound_attributes))
if relation_query?(@sub_query)
@bound_attributes.concat(@sub_query.send(:bound_attributes))
sub_query = @sub_query.select(*sub_columns).arel
sub_query.from([@sub_query.arel_table, table])
else
sub_query = ::Arel.sql(@sub_query)
end
@query.select(*columns).arel.union(type, sub_query)
else
raise ArgumentError, <<-MSG.squish
Only String and ActiveRecord::Base objects are accepted as query and sub query
objects, #{@query.class.name} given for #{self.class.name}.
MSG
end
end
# Setup the statement using the class configuration
def prepare(base, settings)
super
prepare_sub_query(base, settings)
end
# Make sure that both parts of the union are ready
def prepare_sub_query(base, settings)
@union_all = settings.union_all if @union_all.nil?
@sub_query ||= settings.sub_query
@depth ||= settings.depth
@path ||= settings.path
# Collect the connection
@connect ||= settings.connect || begin
key = base.primary_key
[key.to_sym, :"parent_#{key}"] unless key.nil?
end
raise ArgumentError, <<-MSG.squish if @sub_query.nil? && @query.is_a?(String)
Unable to generate sub query from a string query. Please provide a `sub_query`
property on the "#{table_name}" settings.
MSG
if @sub_query.nil?
raise ArgumentError, <<-MSG.squish if @connect.blank?
Unable to generate sub query without setting up a proper way to connect it
with the main query. Please provide a `connect` property on the "#{table_name}"
settings.
MSG
left, right = @connect.map(&:to_s)
condition = @query.arel_table[right].eq(table[left])
if @query.where_values_hash.key?(right)
@sub_query = @query.unscope(where: right.to_sym).where(condition)
else
@sub_query = @query.where(condition)
@query = @query.where(right => nil)
end
elsif @sub_query.respond_to?(:call)
# Call a proc to get the real sub query
call_args = @sub_query.try(:arity) === 0 ? [] : [OpenStruct.new(@args)]
@sub_query = @sub_query.call(*call_args)
end
end
# Add depth and path if they were defined in settings
def extra_columns(base, columns, sub_columns)
return if @query.is_a?(String) || @sub_query.is_a?(String)
# Add the connect attribute to the query
if defined?(@connect)
columns.unshift(@query.arel_table[@connect[0]])
sub_columns.unshift(@sub_query.arel_table[@connect[0]])
end
# Build a column to represent the depth of the recursion
if @depth.present?
name, start, as = @depth
col = table[name]
base.select_extra_values += [col.as(as)] unless as.nil?
columns << ::Arel.sql(start.to_s).as(name)
sub_columns << (col + ::Arel.sql('1')).as(name)
end
# Build a column to represent the path of the record access
if @path.present?
name, source, as = @path
source = @query.arel_table[source || @connect[0]]
col = table[name]
base.select_extra_values += [col.as(as)] unless as.nil?
parts = [col, source.pg_cast(:varchar)]
columns << ::Arel.array([source]).pg_cast(:varchar, true).as(name)
sub_columns << FN.array_append(*parts).as(name)
end
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/auxiliary_statement/settings.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
class AuxiliaryStatement
class Settings < Collector.new(:attributes, :join, :join_type, :query, :requires,
:polymorphic, :through, :union_all, :connect)
attr_reader :base, :source, :depth, :path
alias_method :select, :attributes
alias_method :cte, :source
delegate :relation_query?, to: Torque::PostgreSQL::AuxiliaryStatement
delegate :table, :table_name, to: :@source
delegate :sql, to: ::Arel
def initialize(base, source, recursive = false)
@base = base
@source = source
@recursive = recursive
end
def base_name
@base.name
end
def base_table
@base.arel_table
end
def recursive?
@recursive
end
def depth?
defined?(@depth)
end
def path?
defined?(@path)
end
# Add an attribute to the result showing the depth of each iteration
def with_depth(name = 'depth', start: 0, as: nil)
@depth = [name.to_s, start, as&.to_s] if recursive?
end
# Add an attribute to the result showing the path of each record
def with_path(name = 'path', source: nil, as: nil)
@path = [name.to_s, source&.to_s, as&.to_s] if recursive?
end
# Set recursive operation to use union all
def union_all!
@union_all = true if recursive?
end
# Add both depth and path to the result
def with_depth_and_path
with_depth && with_path
end
# Get the arel version of the table set on the query
def query_table
raise StandardError, 'The query is not defined yet' if query.nil?
return query.arel_table if relation_query?(query)
@query_table
end
# Grant an easy access to arel table columns
def col(name)
query_table[name.to_s]
end
alias column col
# There are three ways of setting the query:
# - A simple relation based on a Model
# - A Arel-based select manager
# - A string or a proc
def query(value = nil, command = nil)
return @query if value.nil?
@query = sanitize_query(value, command)
end
# Same as query, but for the second part of the union for recursive cte
def sub_query(value = nil, command = nil)
return unless recursive?
return @sub_query if value.nil?
@sub_query = sanitize_query(value, command)
end
# Assume `parent_` as the other part if provided a Symbol or String
def connect(value = nil)
return @connect if value.nil?
value = [value.to_sym, :"parent_#{value}"] \
if value.is_a?(String) || value.is_a?(Symbol)
value = value.to_a.first if value.is_a?(Hash)
@connect = value
end
alias connect= connect
private
# Get the query and table from the params
def sanitize_query(value, command = nil)
return value if relation_query?(value)
return value if value.is_a?(::Arel::SelectManager)
command = value if command.nil? # For compatibility purposes
valid_type = command.respond_to?(:call) || command.is_a?(String)
raise ArgumentError, <<-MSG.squish unless valid_type
Only relation, string and proc are valid object types for query,
#{command.inspect} given.
MSG
command
end
end
end
end
end
================================================
FILE: lib/torque/postgresql/auxiliary_statement.rb
================================================
# frozen_string_literal: true
require_relative 'auxiliary_statement/settings'
require_relative 'auxiliary_statement/recursive'
module Torque
module PostgreSQL
class AuxiliaryStatement
TABLE_COLUMN_AS_STRING = /\A(?:"?(\w+)"?\.)?"?(\w+)"?\z/.freeze
class << self
attr_reader :config, :table_name
# Find or create the class that will handle statement
def lookup(name, base)
const = name.to_s.camelize << '_' << self.name.demodulize
return base.const_get(const, false) if base.const_defined?(const, false)
base.const_set(const, Class.new(self)).tap do |klass|
klass.instance_variable_set(:@table_name, name.to_s)
end
end
# Create a new instance of an auxiliary statement
def instantiate(statement, base, **options)
klass = while base < ActiveRecord::Base
list = base.auxiliary_statements_list
break list[statement] if list.present? && list.key?(statement)
base = base.superclass
end
return klass.new(**options) unless klass.nil?
raise ArgumentError, <<-MSG.squish
There's no '#{statement}' auxiliary statement defined for #{base.class.name}.
MSG
end
# Fast access to statement build
def build(statement, base, bound_attributes = [], join_sources = [], **options)
klass = instantiate(statement, base, **options)
result = klass.build(base)
bound_attributes.concat(klass.bound_attributes)
join_sources.concat(klass.join_sources)
result
end
# Identify if the query set may be used as a relation
def relation_query?(obj)
!obj.nil? && obj.respond_to?(:ancestors) && \
obj.ancestors.include?(ActiveRecord::Base)
end
# Identify if the query set may be used as arel
def arel_query?(obj)
!obj.nil? && obj.is_a?(::Arel::SelectManager)
end
# A way to create auxiliary statements outside of models configurations,
# being able to use on extensions
def create(table_or_settings, &block)
klass = Class.new(self)
if block_given?
klass.instance_variable_set(:@table_name, table_or_settings)
klass.configurator(block)
elsif relation_query?(table_or_settings)
klass.configurator(query: table_or_settings)
else
klass.configurator(table_or_settings)
end
klass
end
# Set a configuration block or static hash
def configurator(config)
if config.is_a?(Hash)
# Map the aliases
config[:attributes] = config.delete(:select) if config.key?(:select)
# Create the struct that mocks a configuration result
config = OpenStruct.new(config)
table_name = config[:query]&.klass&.name&.underscore
instance_variable_set(:@table_name, table_name)
end
@config = config
end
# Run a configuration block or get the static configuration
def configure(base, instance)
return @config unless @config.respond_to?(:call)
recursive = self < AuxiliaryStatement::Recursive
settings = Settings.new(base, instance, recursive)
settings.instance_exec(settings, &@config)
settings
end
# Get the arel version of the statement table
def table
@table ||= ::Arel::Table.new(table_name)
end
end
delegate :config, :table, :table_name, :relation, :configure, :relation_query?,
to: :class
attr_reader :bound_attributes, :join_sources
# Start a new auxiliary statement giving extra options
def initialize(*, **options)
args_key = Torque::PostgreSQL.config.auxiliary_statement.send_arguments_key
@join = options.fetch(:join, {})
@args = options.fetch(args_key, {})
@where = options.fetch(:where, {})
@select = options.fetch(:select, {})
@join_type = options[:join_type]
@bound_attributes = []
@join_sources = []
end
# Build the statement on the given arel and return the WITH statement
def build(base)
@bound_attributes.clear
@join_sources.clear
# Prepare all the data for the statement
prepare(base, configure(base, self))
# Add the join condition to the list
@join_sources << build_join(base)
# Return the statement with its dependencies
[@dependencies, ::Arel::Nodes::As.new(table, build_query(base))]
end
private
# Setup the statement using the class configuration
def prepare(base, settings)
requires = Array.wrap(settings.requires).flatten.compact
@dependencies = ensure_dependencies(requires, base).flatten.compact
@join_type ||= settings.join_type || :inner
@query = settings.query
# Call a proc to get the real query
if @query.respond_to?(:call)
call_args = @query.try(:arity) === 0 ? [] : [OpenStruct.new(@args)]
@query = @query.call(*call_args)
end
# Merge select attributes provided on the instance creation
@select = settings.attributes.merge(@select) if settings.attributes.present?
# Merge join settings
if settings.join.present?
@join = settings.join.merge(@join)
elsif settings.through.present?
@association = settings.through.to_s
elsif relation_query?(@query)
@association = base.reflections.find do |name, reflection|
break name if @query.klass.eql?(reflection.klass)
end
end
end
# Build the string or arel query
def build_query(base)
# Expose columns and get the list of the ones for select
columns = expose_columns(base, @query.try(:arel_table))
# Prepare the query depending on its type
if @query.is_a?(String)
args = @args.map{ |k, v| [k, base.connection.quote(v)] }.to_h
::Arel.sql("(#{@query})" % args)
elsif relation_query?(@query)
@query = @query.where(@where) if @where.present?
@bound_attributes.concat(@query.send(:bound_attributes))
@query.select(*columns).arel
else
raise ArgumentError, <<-MSG.squish
Only String and ActiveRecord::Base objects are accepted as query objects,
#{@query.class.name} given for #{self.class.name}.
MSG
end
end
# Build the join statement that will be sent to the main arel
def build_join(base)
conditions = table.create_and([])
builder = base.predicate_builder
foreign_table = base.arel_table
# Check if it's necessary to load the join from an association
if @association.present?
association = base.reflections[@association]
# Require source of a through reflection
if association.through_reflection?
base.joins(association.source_reflection_name)
# Changes the base of the connection to the reflection table
builder = association.klass.predicate_builder
foreign_table = ::Arel::Table.new(association.plural_name)
end
@query.merge(association.join_scope(@query.arel_table, foreign_table, base))
# Add the join constraints
constraint = association.build_join_constraint(table, foreign_table)
constraint = constraint.children if constraint.is_a?(::Arel::Nodes::And)
conditions.children.concat(Array.wrap(constraint))
end
# Build all conditions for the join on statement
@join.inject(conditions.children) do |arr, (left, right)|
left = project(left, foreign_table)
item = right.is_a?(Symbol) ? project(right).eq(left) : builder.build(left, right)
arr.push(item)
end
# Raise an error when there's no join conditions
raise ArgumentError, <<-MSG.squish if conditions.children.empty?
You must provide the join columns when using '#{@query.class.name}'
as a query object on #{self.class.name}.
MSG
# Build the join based on the join type
arel_join.new(table, table.create_on(conditions))
end
# Get the class of the join on arel
def arel_join
case @join_type
when :inner then ::Arel::Nodes::InnerJoin
when :left then ::Arel::Nodes::OuterJoin
when :right then ::Arel::Nodes::RightOuterJoin
when :full then ::Arel::Nodes::FullOuterJoin
else
raise ArgumentError, <<-MSG.squish
The '#{@join_type}' is not implemented as a join type.
MSG
end
end
# Mount the list of selected attributes
def expose_columns(base, query_table = nil)
# Add the columns necessary for the join
list = @join_sources.each_with_object(@select) do |join, hash|
join.right.expr.children.each do |item|
hash[item.left.name] = nil if item.left.relation.eql?(table)
end
end
# Add select columns to the query and get exposed columns
list.filter_map do |left, right|
base.select_extra_values += [table[right.to_s]] unless right.nil?
next unless query_table
col = project(left, query_table)
right.nil? ? col : col.as(right.to_s)
end
end
# Ensure that all the dependencies are loaded in the base relation
def ensure_dependencies(list, base)
with_options = list.extract_options!.to_a
(list + with_options).map do |name, options|
dependent_klass = base.model.auxiliary_statements_list[name]
raise ArgumentError, <<-MSG.squish if dependent_klass.nil?
The '#{name}' auxiliary statement dependency can't found on
#{self.class.name}.
MSG
next if base.auxiliary_statements_values.any? do |cte|
cte.is_a?(dependent_klass)
end
options ||= {}
AuxiliaryStatement.build(name, base, bound_attributes, join_sources, **options)
end
end
# Project a column on a given table, or use the column table
def project(column, arel_table = nil)
if column.respond_to?(:as)
return column
elsif (as_string = TABLE_COLUMN_AS_STRING.match(column.to_s))
column = as_string[2]
arel_table = ::Arel::Table.new(as_string[1]) unless as_string[1].nil?
end
arel_table ||= table
arel_table[column.to_s]
end
end
end
end
================================================
FILE: lib/torque/postgresql/base.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Base
extend ActiveSupport::Concern
##
# :singleton-method: schema
# :call-seq: schema
#
# The schema to which the table belongs to.
included do
mattr_accessor :belongs_to_many_required_by_default, instance_accessor: false
class_attribute :schema, instance_writer: false
end
class_methods do
delegate :distinct_on, :with, :itself_only, :cast_records, :join_series,
:buckets, to: :all
# Make sure that table name is an instance of TableName class
def reset_table_name
return super unless PostgreSQL.config.schemas.enabled
self.table_name = TableName.new(self, super)
end
# Whenever the base model is inherited, add a list of auxiliary
# statements like the one that loads inherited records' relname
def inherited(subclass)
super
subclass.class_attribute(:auxiliary_statements_list)
subclass.auxiliary_statements_list = {}
record_class = ActiveRecord::Relation._record_class_attribute
# Define the dynamic attribute that returns the same information as
# the one provided by the auxiliary statement
subclass.dynamic_attribute(record_class) do
klass = self.class
next klass.table_name unless klass.physically_inheritances?
query = klass.unscoped.where(subclass.primary_key => id)
query.pluck(klass.arel_table['tableoid'].pg_cast('regclass')).first
end
end
# Specifies a one-to-many association. The following methods for
# retrieval and query of collections of associated objects will be
# added:
#
# +collection+ is a placeholder for the symbol passed as the +name+
# argument, so <tt>belongs_to_many :tags</tt> would add among others
# <tt>tags.empty?</tt>.
#
# [collection]
# Returns a Relation of all the associated objects.
# An empty Relation is returned if none are found.
# [collection<<(object, ...)]
# Adds one or more objects to the collection by adding their ids to
# the array of ids on the parent object.
# Note that this operation instantly fires update SQL without waiting
# for the save or update call on the parent object, unless the parent
# object is a new record.
# This will also run validations and callbacks of associated
# object(s).
# [collection.delete(object, ...)]
# Removes one or more objects from the collection by removing their
# ids from the list on the parent object.
# Objects will be in addition destroyed if they're associated with
# <tt>dependent: :destroy</tt>, and deleted if they're associated
# with <tt>dependent: :delete_all</tt>.
# [collection.destroy(object, ...)]
# Removes one or more objects from the collection by running
# <tt>destroy</tt> on each record, regardless of any dependent option,
# ensuring callbacks are run. They will also be removed from the list
# on the parent object.
# [collection=objects]
# Replaces the collections content by deleting and adding objects as
# appropriate.
# [collection_singular_ids]
# Returns an array of the associated objects' ids
# [collection_singular_ids=ids]
# Replace the collection with the objects identified by the primary
# keys in +ids+. This method loads the models and calls
# <tt>collection=</tt>. See above.
# [collection.clear]
# Removes every object from the collection. This destroys the
# associated objects if they are associated with
# <tt>dependent: :destroy</tt>, deletes them directly from the
# database if <tt>dependent: :delete_all</tt>, otherwise just remove
# them from the list on the parent object.
# [collection.empty?]
# Returns +true+ if there are no associated objects.
# [collection.size]
# Returns the number of associated objects.
# [collection.find(...)]
# Finds an associated object according to the same rules as
# ActiveRecord::FinderMethods#find.
# [collection.exists?(...)]
# Checks whether an associated object with the given conditions exists.
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
# [collection.build(attributes = {}, ...)]
# Returns one or more new objects of the collection type that have
# been instantiated with +attributes+ and linked to this object by
# adding its +id+ to the list after saving.
# [collection.create(attributes = {})]
# Returns a new object of the collection type that has been
# instantiated with +attributes+, linked to this object by adding its
# +id+ to the list after performing the save (if it passed the
# validation).
# [collection.create!(attributes = {})]
# Does the same as <tt>collection.create</tt>, but raises
# ActiveRecord::RecordInvalid if the record is invalid.
# [collection.reload]
# Returns a Relation of all of the associated objects, forcing a
# database read. An empty Relation is returned if none are found.
#
# === Example
#
# A <tt>Video</tt> class declares <tt>belongs_to_many :tags</tt>,
# which will add:
# * <tt>Video#tags</tt> (similar to <tt>Tag.where([id] && tag_ids)</tt>)
# * <tt>Video#tags<<</tt>
# * <tt>Video#tags.delete</tt>
# * <tt>Video#tags.destroy</tt>
# * <tt>Video#tags=</tt>
# * <tt>Video#tag_ids</tt>
# * <tt>Video#tag_ids=</tt>
# * <tt>Video#tags.clear</tt>
# * <tt>Video#tags.empty?</tt>
# * <tt>Video#tags.size</tt>
# * <tt>Video#tags.find</tt>
# * <tt>Video#tags.exists?(name: 'ACME')</tt>
# * <tt>Video#tags.build</tt>
# * <tt>Video#tags.create</tt>
# * <tt>Video#tags.create!</tt>
# * <tt>Video#tags.reload</tt>
# The declaration can also include an +options+ hash to specialize the
# behavior of the association.
#
# === Options
# [:class_name]
# Specify the class name of the association. Use it only if that name
# can't be inferred from the association name. So <tt>belongs_to_many
# :tags</tt> will by default be linked to the +Tag+ class, but if the
# real class name is +SpecialTag+, you'll have to specify it with this
# option.
# [:foreign_key]
# Specify the foreign key used for the association. By default this is
# guessed to be the name of this class in lower-case and "_ids"
# suffixed. So a Video class that makes a #belongs_to_many association
# with Tag will use "tag_ids" as the default <tt>:foreign_key</tt>.
#
# It is a good idea to set the <tt>:inverse_of</tt> option as well.
# [:primary_key]
# Specify the name of the column to use as the primary key for the
# association. By default this is +id+.
# [:dependent]
# Controls what happens to the associated objects when their owner is
# destroyed. Note that these are implemented as callbacks, and Rails
# executes callbacks in order. Therefore, other similar callbacks may
# affect the <tt>:dependent</tt> behavior, and the <tt>:dependent</tt>
# behavior may affect other callbacks.
# [:touch]
# If true, the associated objects will be touched (the updated_at/on
# attributes set to current time) when this record is either saved or
# destroyed. If you specify a symbol, that attribute will be updated
# with the current time in addition to the updated_at/on attribute.
# Please note that with touching no validation is performed and only
# the +after_touch+, +after_commit+ and +after_rollback+ callbacks are
# executed.
# [:optional]
# When set to +true+, the association will not have its presence
# validated.
# [:required]
# When set to +true+, the association will also have its presence
# validated. This will validate the association itself, not the id.
# You can use +:inverse_of+ to avoid an extra query during validation.
# NOTE: <tt>required</tt> is set to <tt>false</tt> by default and is
# deprecated. If you want to have association presence validated,
# use <tt>required: true</tt>.
# [:default]
# Provide a callable (i.e. proc or lambda) to specify that the
# association should be initialized with a particular record before
# validation.
# [:inverse_of]
# Specifies the name of the #has_many association on the associated
# object that is the inverse of this #belongs_to_many association.
# See ActiveRecord::Associations::ClassMethods's overview on
# Bi-directional associations for more detail.
#
# Option examples:
# belongs_to_many :tags, dependent: :nullify
# belongs_to_many :tags, required: true, touch: true
# belongs_to_many :tags, default: -> { Tag.default }
def belongs_to_many(name, scope = nil, **options, &extension)
klass = Associations::Builder::BelongsToMany
reflection = klass.build(self, name, scope, options, &extension)
::ActiveRecord::Reflection.add_reflection(self, name, reflection)
end
protected
# Allow optional select attributes to be loaded manually when they are
# not present. This is associated with auxiliary statement, which
# permits columns that can be loaded through CTEs, be loaded
# individually for a single record
#
# For instance, if you have a statement that can load an user's last
# comment content, by querying the comments using an auxiliary
# statement.
# subclass.auxiliary_statement :last_comment do |cte|
# cte.query Comment.order(:user_id, id: :desc)
# .distinct_on(:user_id)
# cte.attributes col(:content) => :last_comment
# cte.join_type :left
# end
#
# In case you don't use 'with(:last_comment)', you can do the
# following.
# dynamic_attribute(:last_comment) do
# comments.order(id: :desc).first.content
# end
#
# This means that any auxiliary statements can have their columns
# granted even when they are not used
def dynamic_attribute(name, &block)
define_method(name) do
return read_attribute(name) if has_attribute?(name)
result = self.instance_exec(&block)
type_klass = ActiveRecord::Type.respond_to?(:default_value) \
? ActiveRecord::Type.default_value \
: self.class.connection.type_map.send(:default_value)
@attributes[name.to_s] = ActiveRecord::Relation::QueryAttribute.new(
name.to_s, result, type_klass,
)
read_attribute(name)
end
end
# Creates a new auxiliary statement (CTE) under the base class
# attributes key:
# Provides a map of attributes to be exposed to the main query.
#
# For instance, if the statement query has an 'id' column that you
# want it to be accessed on the main query as 'item_id',
# you can use:
# attributes id: :item_id, 'MAX(id)' => :max_id,
# col(:id).minimum => :min_id
#
# If its statement has more tables, and you want to expose those
# fields, then:
# attributes 'table.name': :item_name
#
# join_type key:
# Changes the type of the join and set the constraints
#
# The left side of the hash is the source table column, the right
# side is the statement table column, now it's only accepting '='
# constraints
# join id: :user_id
# join id: :'user.id'
# join 'post.id': :'user.last_post_id'
#
# It's possible to change the default type of join
# join :left, id: :user_id
#
# join key:
# Changes the type of the join
#
# query key:
# Save the query command to be performand
#
# requires key:
# Indicates dependencies with another statements
#
# polymorphic key:
# Indicates a polymorphic relationship, with will affect the way the
# auto join works, by giving a polymorphic connection
def auxiliary_statement(table, &block)
klass = AuxiliaryStatement.lookup(table, self)
auxiliary_statements_list[table.to_sym] = klass
klass.configurator(block)
end
alias cte auxiliary_statement
# Creates a new recursive auxiliary statement (CTE) under the base
# Very similar to the regular auxiliary statement, but with two-part
# query where one is executed first and the second recursively
def recursive_auxiliary_statement(table, &block)
klass = AuxiliaryStatement::Recursive.lookup(table, self)
auxiliary_statements_list[table.to_sym] = klass
klass.configurator(block)
end
alias recursive_cte recursive_auxiliary_statement
end
end
::ActiveRecord::Base.include(Base)
end
end
================================================
FILE: lib/torque/postgresql/collector.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
module Collector
# This class helps to collect data in different ways. Used to configure
# auxiliary statements
def self.new(*args)
klass = Class.new
args.flatten!
args.compact!
klass.module_eval do
args.each do |attribute|
define_method attribute do |*args|
if args.empty?
instance_variable_get("@#{attribute}")
elsif args.size > 1
instance_variable_set("@#{attribute}", args)
else
instance_variable_set("@#{attribute}", args.first)
end
end
alias_method "#{attribute}=", attribute
end
end
klass
end
end
end
end
================================================
FILE: lib/torque/postgresql/config.rb
================================================
# frozen_string_literal: true
module Torque
module PostgreSQL
include ActiveSupport::Configurable
# Use the same logger as the Active Record one
def self.logger
ActiveRecord::Base.logger
end
# Allow nested configurations
# :TODO: Rely on +inheritable_copy+ to make nested configurations
config.define_singleton_method(:nested) do |name, &block|
klass = Class.new(ActiveSupport::Configurable::Configuration).new
block.call(klass) if block
send("#{name}=", klass)
end
# Set if any information that requires querying and searching or collecting
# information should be eager loaded. This automatically changes when rails
# same configuration is set to true
config.eager_load = false
# Add support for joining any query/association with a generated series
config.join_series = true
# Add support for querying and calculating histogram buckets
config.buckets = true
# Set a list of irregular model name when associated with table names
config.irregular_models = {}
def config.irregular_models=(hash)
PostgreSQL.config[:irregular_models] = hash.map do |(table, model)|
[table.to_s, model.to_s]
end.to_h
end
# Configure associations features
config.nested(:associations) do |assoc|
# Define if +belongs_to_many+ associations are marked as required by
# default. False means that no validation will be performed
assoc.belongs_to_many_required_by_default = false
# Although +belongs_to_many+ does not need a custom handler when joining
# the last chain scope, this can allow devs to pick which way they prefer:
# Rails default, or ANY with a single bind to improve prepared statements
# assoc.optimize_for_binds = false TODO: Add support
end
# Configure multiple schemas
config.nested(:schemas) do |schemas|
# Enables schemas handler by this gem, not Rails's own implementation
schemas.enabled = true
# Defines a list of LIKE-based schemas to not consider for a multiple
# schema database
schemas.blacklist = %w[information_schema pg_%]
# Defines a list of LIKE-based schemas to consider for a multiple schema
# database
schemas.whitelist = %w[public]
end
# Configure auxiliary statement features
config.nested(:auxiliary_statement) do |cte|
# Enables auxiliary statements handler by this gem, not Rails's own
# implementation
cte.enabled = true
# Define the key that is used on auxiliary statements to send extra
# arguments to format string or send on a proc
cte.send_arguments_key = :args
# Estipulate a class name (which may contain namespace) that exposes the
# auxiliary statement in order to perform detached CTEs
cte.exposed_class = 'TorqueCTE'
# Estipulate a class name (which may contain namespace) that exposes the
# recursive auxiliary statement in order to perform detached CTEs
cte.exposed_recursive_class = 'TorqueRecursiveCTE'
end
# Configure ENUM features
config.nested(:enum) do |enum|
# Enables enum handler by this gem, not Rails's own implementation
enum.enabled = true
# The name of the method to be used on any ActiveRecord::Base to
# initialize model-based enum features
enum.base_method = :torque_enum
# The name of the method to be used on any ActiveRecord::Base to
# initialize model-based enum set features
enum.set_method = :torque_enum_set
# Indicates if bang methods like 'disabled!' should update the record on
# database or not
enum.save_on_bang = true
# Indicates if it should raise errors when a generated method would
# conflict with an existing one
enum.raise_conflicting = false
# Specify the namespace of each enum type of value
enum.namespace = nil
# Specify the scopes for I18n translations
enum.i18n_scopes = [
'activerecord.attributes.%{model}.%{attr}.%{value}',
'activerecord.attributes.%{attr}.%{value}',
'activerecord.enums.%{type}.%{value}',
'enum.%{type}.%{value}',
'enum.%{value}'
]
# Specify the scopes for I18n translations but with type only
enum.i18n_type_scopes = Enumerator.new do |yielder|
enum.i18n_scopes.each do |key|
next if key.include?('%{model}') || key.include?('%{attr}')
yielder << key
end
end
end
# Configure geometry data types
config.nested(:geometry) do |geometry|
# Enables geometry handler by this gem, not Rails's own implementation
geometry.enabled = true
# Define the class that will be handling Point data types after decoding
# it. Any class provided here must respond to 'x', and 'y'
geometry.point_class = ActiveRecord::Point
# Define the class that will be handling Box data types after decoding it.
# Any class provided here must respond to 'x1', 'y1', 'x2', and 'y2'
geometry.box_class = nil
# Define the class that will be handling Circle data types after decoding
# it. Any class provided here must respond to 'x', 'y', and 'r'
geometry.circle_class = nil
# Define the class that will be handling Line data types after decoding
# it. Any class provided here must respond to 'a', 'b', and 'c'
geometry.line_class = nil
# Define the class that will be handling Segment data types after decoding
# it. Any class provided here must respond to 'x1', 'y1', 'x2', and 'y2'
geometry.segment_class = nil
end
# Configure inheritance features
config.nested(:inheritance) do |inheritance|
# Define the lookup of models from their given name to be inverted, which
# means that they are going to be form the last namespaced one to the
# most namespaced one
inheritance.inverse_lookup = true
# Determines the name of the column used to collect the table of each
# record. When the table has inheritance tables, this column will return
# the name of the table that actually holds the record
inheritance.record_class_column_name = :_record_class
# Determines the name of the column used when identifying that the loaded
# records should be casted to its correctly model. This will be TRUE for
# the records mentioned on `cast_records`
inheritance.auto_cast_column_name = :_auto_cast
end
# Configure period features
config.nested(:period) do |period|
# Enables period handler by this gem
period.enabled = true
# The name of the method to be used on any ActiveRecord::Base to
# initialize model-based period features
period.base_method = :period_for
# The default name for a threshold attribute, which will automatically
# enable threshold features
period.auto_threshold = :threshold
# Define the list of methods that will be created by default while setting
# up a new period field
period.method_names = {
current_on: '%s_on', # 00
current: 'current_%s', # 01
not_current: 'not_current_%s', # 02
containing: '%s_containing', # 03
not_containing: '%s_not_containing', # 04
overlapping: '%s_overlapping', # 05
not_overlapping: '%s_not_overlapping', # 06
starting_after: '%s_starting_after', # 07
starting_before: '%s_starting_before', # 08
finishing_after: '%s_finishing_after', # 09
finishing_before: '%s_finishing_before', # 10
real_containing: '%s_real_containing', # 11
real_overlapping: '%s_real_overlapping', # 12
real_starting_after: '%s_real_starting_after', # 13
real_starting_before: '%s_real_starting_before', # 14
real_finishing_after: '%s_real_finishing_after', # 15
real_finishing_before: '%s_real_finishing_before', # 16
containing_date: '%s_containing_date', # 17
not_containing_date: '%s_not_containing_date', # 18
overlapping_date: '%s_overlapping_date', # 19
not_overlapping_date: '%s_not_overlapping_date', # 20
real_containing_date: '%s_real_containing_date', # 21
real_overlapping_date: '%s_real_overlapping_date', # 22
current?: 'current_%s?', # 23
current_on?: 'current_%s_on?', # 24
start: '%s_start', # 25
finish: '%s_finish', # 26
real: 'real_%s', # 27
real_start: '%s_real_start', # 28
real_finish: '%s_real_finish', # 29
}
# If the period is marked as direct access, without the field name,
# then these method names will replace the default ones
period.direct_method_names = {
current_on: 'happening_in',
containing: 'during',
not_containing: 'not_during',
real_containing: 'real_during',
containing_date: 'during_date',
not_containing_date: 'not_during_date',
current_on?: 'happening_in?',
start: 'start_at',
finish: 'finish_at',
real: 'real_time',
real_start: 'real_start_at',
real_finish: 'real_finish_at',
}
end
# Configure period features
config.nested(:interval) do |interval|
# Enables interval handler by this gem, not Rails's own implementation
interval.enabled = true
end
# Configure arel additional features
config.nested(:arel) do |arel|
# When provided, the initializer will expose the Arel function helper on
# the given module
config.expose_function_helper_on = nil
# List of Arel INFIX operators that will be made available for using as
# methods on Arel::Nodes::Node and Arel::Attribute
arel.infix_operators = {
'contained_by' => '<@',
'has_key' => '?',
'has_all_keys' => '?&',
'has_any_keys' => '?|',
'strictly_left' => '<<',
'strictly_right' => '>>',
'doesnt_right_extend' => '&<',
'doesnt_left_extend' => '&>',
'adjacent_to' => '-|-',
}
end
# Configure full text search features
config.nested(:full_text_search) do |fts|
gitextract_u1kant5h/ ├── .circleci/ │ └── config.yml ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .rspec ├── Gemfile ├── MIT-LICENSE ├── README.md ├── README.rdoc ├── Rakefile ├── gemfiles/ │ └── Gemfile.rails-8.0 ├── lib/ │ ├── generators/ │ │ └── torque/ │ │ ├── function_generator.rb │ │ ├── templates/ │ │ │ ├── function.sql.erb │ │ │ ├── type.sql.erb │ │ │ └── view.sql.erb │ │ ├── type_generator.rb │ │ └── view_generator.rb │ ├── torque/ │ │ ├── postgresql/ │ │ │ ├── adapter/ │ │ │ │ ├── database_statements.rb │ │ │ │ ├── oid/ │ │ │ │ │ ├── array.rb │ │ │ │ │ ├── box.rb │ │ │ │ │ ├── circle.rb │ │ │ │ │ ├── enum.rb │ │ │ │ │ ├── enum_set.rb │ │ │ │ │ ├── interval.rb │ │ │ │ │ ├── line.rb │ │ │ │ │ ├── range.rb │ │ │ │ │ └── segment.rb │ │ │ │ ├── oid.rb │ │ │ │ ├── quoting.rb │ │ │ │ ├── schema_creation.rb │ │ │ │ ├── schema_definitions.rb │ │ │ │ ├── schema_dumper.rb │ │ │ │ ├── schema_overrides.rb │ │ │ │ └── schema_statements.rb │ │ │ ├── adapter.rb │ │ │ ├── arel/ │ │ │ │ ├── infix_operation.rb │ │ │ │ ├── join_source.rb │ │ │ │ ├── nodes.rb │ │ │ │ ├── operations.rb │ │ │ │ ├── select_manager.rb │ │ │ │ └── visitors.rb │ │ │ ├── arel.rb │ │ │ ├── associations/ │ │ │ │ ├── association_scope.rb │ │ │ │ ├── belongs_to_many_association.rb │ │ │ │ ├── builder/ │ │ │ │ │ ├── belongs_to_many.rb │ │ │ │ │ └── has_many.rb │ │ │ │ ├── builder.rb │ │ │ │ ├── foreign_association.rb │ │ │ │ ├── preloader/ │ │ │ │ │ ├── association.rb │ │ │ │ │ └── loader_query.rb │ │ │ │ └── preloader.rb │ │ │ ├── associations.rb │ │ │ ├── attributes/ │ │ │ │ ├── builder/ │ │ │ │ │ ├── enum.rb │ │ │ │ │ ├── full_text_search.rb │ │ │ │ │ └── period.rb │ │ │ │ ├── builder.rb │ │ │ │ ├── enum.rb │ │ │ │ ├── enum_set.rb │ │ │ │ ├── full_text_search.rb │ │ │ │ ├── lazy.rb │ │ │ │ └── period.rb │ │ │ ├── attributes.rb │ │ │ ├── autosave_association.rb │ │ │ ├── auxiliary_statement/ │ │ │ │ ├── recursive.rb │ │ │ │ └── settings.rb │ │ │ ├── auxiliary_statement.rb │ │ │ ├── base.rb │ │ │ ├── collector.rb │ │ │ ├── config.rb │ │ │ ├── function.rb │ │ │ ├── geometry_builder.rb │ │ │ ├── i18n.rb │ │ │ ├── inheritance.rb │ │ │ ├── insert_all.rb │ │ │ ├── migration/ │ │ │ │ └── command_recorder.rb │ │ │ ├── migration.rb │ │ │ ├── predicate_builder/ │ │ │ │ ├── arel_attribute_handler.rb │ │ │ │ ├── array_handler.rb │ │ │ │ ├── enumerator_lazy_handler.rb │ │ │ │ └── regexp_handler.rb │ │ │ ├── predicate_builder.rb │ │ │ ├── railtie.rb │ │ │ ├── reflection/ │ │ │ │ ├── abstract_reflection.rb │ │ │ │ ├── association_reflection.rb │ │ │ │ ├── belongs_to_many_reflection.rb │ │ │ │ ├── has_many_reflection.rb │ │ │ │ ├── runtime_reflection.rb │ │ │ │ └── through_reflection.rb │ │ │ ├── reflection.rb │ │ │ ├── relation/ │ │ │ │ ├── auxiliary_statement.rb │ │ │ │ ├── buckets.rb │ │ │ │ ├── distinct_on.rb │ │ │ │ ├── inheritance.rb │ │ │ │ ├── join_series.rb │ │ │ │ └── merger.rb │ │ │ ├── relation.rb │ │ │ ├── schema_cache/ │ │ │ │ ├── bound_schema_reflection.rb │ │ │ │ ├── inheritance.rb │ │ │ │ └── schema_reflection.rb │ │ │ ├── schema_cache.rb │ │ │ ├── table_name.rb │ │ │ ├── version.rb │ │ │ ├── versioned_commands/ │ │ │ │ ├── command_migration.rb │ │ │ │ ├── generator.rb │ │ │ │ ├── migration_context.rb │ │ │ │ ├── migrator.rb │ │ │ │ └── schema_table.rb │ │ │ └── versioned_commands.rb │ │ └── postgresql.rb │ └── torque-postgresql.rb ├── spec/ │ ├── en.yml │ ├── factories/ │ │ ├── authors.rb │ │ ├── comments.rb │ │ ├── item.rb │ │ ├── posts.rb │ │ ├── tags.rb │ │ ├── texts.rb │ │ ├── users.rb │ │ └── videos.rb │ ├── fixtures/ │ │ └── migrations/ │ │ ├── 20250101000001_create_users.rb │ │ ├── 20250101000002_create_function_count_users_v1.sql │ │ ├── 20250101000003_create_internal_users.rb │ │ ├── 20250101000004_update_function_count_users_v2.sql │ │ ├── 20250101000005_create_view_all_users_v1.sql │ │ ├── 20250101000006_create_type_user_id_v1.sql │ │ └── 20250101000007_remove_function_count_users_v2.sql │ ├── initialize.rb │ ├── mocks/ │ │ ├── cache_query.rb │ │ └── create_table.rb │ ├── models/ │ │ ├── activity.rb │ │ ├── activity_book.rb │ │ ├── activity_post/ │ │ │ └── sample.rb │ │ ├── activity_post.rb │ │ ├── author.rb │ │ ├── author_journalist.rb │ │ ├── category.rb │ │ ├── comment.rb │ │ ├── course.rb │ │ ├── geometry.rb │ │ ├── guest_comment.rb │ │ ├── internal/ │ │ │ └── user.rb │ │ ├── item.rb │ │ ├── post.rb │ │ ├── question.rb │ │ ├── question_select.rb │ │ ├── tag.rb │ │ ├── text.rb │ │ ├── time_keeper.rb │ │ ├── user.rb │ │ └── video.rb │ ├── schema.rb │ ├── spec_helper.rb │ └── tests/ │ ├── arel_spec.rb │ ├── auxiliary_statement_spec.rb │ ├── belongs_to_many_spec.rb │ ├── collector_spec.rb │ ├── distinct_on_spec.rb │ ├── enum_set_spec.rb │ ├── enum_spec.rb │ ├── full_text_seach_test.rb │ ├── function_spec.rb │ ├── geometric_builder_spec.rb │ ├── has_many_spec.rb │ ├── insert_all_spec.rb │ ├── interval_spec.rb │ ├── lazy_spec.rb │ ├── period_spec.rb │ ├── predicate_builder_spec.rb │ ├── quoting_spec.rb │ ├── relation_spec.rb │ ├── schema_spec.rb │ ├── table_inheritance_spec.rb │ └── versioned_commands_spec.rb └── torque_postgresql.gemspec
SYMBOL INDEX (1018 symbols across 116 files)
FILE: lib/generators/torque/function_generator.rb
type Torque (line 5) | module Torque
type Generators (line 6) | module Generators
class FunctionGenerator (line 7) | class FunctionGenerator < Rails::Generators::Base
FILE: lib/generators/torque/type_generator.rb
type Torque (line 5) | module Torque
type Generators (line 6) | module Generators
class TypeGenerator (line 7) | class TypeGenerator < Rails::Generators::Base
FILE: lib/generators/torque/view_generator.rb
type Torque (line 5) | module Torque
type Generators (line 6) | module Generators
class ViewGenerator (line 7) | class ViewGenerator < Rails::Generators::Base
FILE: lib/torque/postgresql/adapter.rb
type Torque (line 11) | module Torque
type PostgreSQL (line 12) | module PostgreSQL
type Adapter (line 13) | module Adapter
class DeduplicatableArray (line 19) | class DeduplicatableArray < ::Array
method deduplicate (line 20) | def deduplicate
function version (line 28) | def version
function extract_table_options! (line 35) | def extract_table_options!(options)
function build_insert_sql (line 41) | def build_insert_sql(insert)
FILE: lib/torque/postgresql/adapter/database_statements.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type DatabaseStatements (line 6) | module DatabaseStatements
function dump_mode! (line 11) | def dump_mode!
function schemas_blacklist (line 16) | def schemas_blacklist
function schemas_whitelist (line 22) | def schemas_whitelist
function schemas_search_path_sanitized (line 28) | def schemas_search_path_sanitized
function valid_type? (line 36) | def valid_type?(type)
function extended_types (line 41) | def extended_types
function schema_exists? (line 48) | def schema_exists?(name, filtered: true)
function type_exists? (line 57) | def type_exists?(name)
function initialize_type_map (line 63) | def initialize_type_map(m = type_map)
function load_additional_types (line 79) | def load_additional_types(oids = nil)
function torque_load_additional_types (line 87) | def torque_load_additional_types(oids = nil)
function torque_load_additional_types? (line 116) | def torque_load_additional_types?
function user_defined_types (line 122) | def user_defined_types(*categories)
function inherited_tables (line 135) | def inherited_tables
function user_defined_schemas (line 151) | def user_defined_schemas
function user_defined_schemas_sql (line 156) | def user_defined_schemas_sql
function column_definitions (line 167) | def column_definitions(table_name)
function list_versioned_commands (line 188) | def list_versioned_commands(type)
function filter_by_schema (line 220) | def filter_by_schema
FILE: lib/torque/postgresql/adapter/oid/array.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type OID (line 6) | module OID
type Array (line 7) | module Array
function force_equality? (line 8) | def force_equality?(value)
FILE: lib/torque/postgresql/adapter/oid/box.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class Box (line 5) | class Box < Struct.new(:x1, :y1, :x2, :y2)
method points (line 6) | def points
type Adapter (line 19) | module Adapter
type OID (line 20) | module OID
class Box (line 21) | class Box < Torque::PostgreSQL::GeometryBuilder
FILE: lib/torque/postgresql/adapter/oid/circle.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class Circle (line 5) | class Circle < Struct.new(:x, :y, :r)
method center (line 9) | def center
method center= (line 13) | def center=(value)
method point_class (line 21) | def point_class
type Adapter (line 28) | module Adapter
type OID (line 29) | module OID
class Circle (line 30) | class Circle < Torque::PostgreSQL::GeometryBuilder
FILE: lib/torque/postgresql/adapter/oid/enum.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type OID (line 6) | module OID
class Enum (line 7) | class Enum < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::...
method create (line 11) | def self.create(row, type_map)
method initialize (line 24) | def initialize(name)
method hash (line 31) | def hash
method serialize (line 35) | def serialize(value)
method assert_valid_value (line 41) | def assert_valid_value(value)
method type_cast_for_schema (line 46) | def type_cast_for_schema(value)
method == (line 50) | def ==(other)
method cast_value (line 58) | def cast_value(value)
FILE: lib/torque/postgresql/adapter/oid/enum_set.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type OID (line 6) | module OID
class EnumSet (line 7) | class EnumSet < Enum
method initialize (line 8) | def initialize(name, enum_klass)
method type (line 16) | def type
method deserialize (line 20) | def deserialize(value)
method serialize (line 26) | def serialize(value)
method type_cast_for_schema (line 35) | def type_cast_for_schema(value)
method cast_value (line 41) | def cast_value(value)
FILE: lib/torque/postgresql/adapter/oid/interval.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type OID (line 6) | module OID
class Interval (line 7) | class Interval < ActiveModel::Type::Value
method type (line 11) | def type
method cast (line 27) | def cast(value)
method deserialize (line 52) | def deserialize(value)
method serialize (line 59) | def serialize(value)
method type_cast_for_schema (line 67) | def type_cast_for_schema(value)
method assert_valid_value (line 72) | def assert_valid_value(value)
method parts_to_duration (line 77) | def parts_to_duration(parts)
method remove_weeks (line 98) | def remove_weeks(value)
FILE: lib/torque/postgresql/adapter/oid/line.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class Line (line 5) | class Line < Struct.new(:slope, :intercept)
method a= (line 9) | def a=(value)
method a (line 13) | def a
method b= (line 17) | def b=(value)
method b (line 21) | def b
method horizontal? (line 25) | def horizontal?
method vertical? (line 29) | def vertical?
type Adapter (line 36) | module Adapter
type OID (line 37) | module OID
class Line (line 38) | class Line < Torque::PostgreSQL::GeometryBuilder
method build_klass (line 45) | def build_klass(*args)
FILE: lib/torque/postgresql/adapter/oid/range.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type OID (line 6) | module OID
class Range (line 7) | class Range < ActiveRecord::ConnectionAdapters::PostgreSQL::OID:...
type Comparison (line 10) | module Comparison
function <=> (line 11) | def <=>(other)
method cast_value (line 18) | def cast_value(value)
method map (line 30) | def map(value) # :nodoc:
method cast_custom (line 39) | def cast_custom(from, to)
method custom_cast_single (line 45) | def custom_cast_single(value, negative = false)
method custom_infinity (line 49) | def custom_infinity(negative)
FILE: lib/torque/postgresql/adapter/oid/segment.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class Segment (line 5) | class Segment < Struct.new(:point0, :point1)
method x1= (line 6) | def x1=(value)
method x1 (line 10) | def x1
method y1= (line 14) | def y1=(value)
method y1 (line 18) | def y1
method x2= (line 22) | def x2=(value)
method x2 (line 26) | def x2
method y2= (line 30) | def y2=(value)
method y2 (line 34) | def y2
method new_point (line 40) | def new_point(x, y)
type Adapter (line 47) | module Adapter
type OID (line 48) | module OID
class Segment (line 49) | class Segment < Torque::PostgreSQL::GeometryBuilder
method point_class (line 56) | def point_class
method build_klass (line 60) | def build_klass(*args)
FILE: lib/torque/postgresql/adapter/quoting.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type Quoting (line 6) | module Quoting
function quote_type_name (line 15) | def quote_type_name(name, *args)
function quote_identifier_name (line 24) | def quote_identifier_name(name, schema = nil)
function quote_default_expression (line 30) | def quote_default_expression(value, column)
FILE: lib/torque/postgresql/adapter/schema_creation.rb
type Torque (line 1) | module Torque
type PostgreSQL (line 2) | module PostgreSQL
type Adapter (line 3) | module Adapter
type SchemaCreation (line 4) | module SchemaCreation
function add_table_options! (line 8) | def add_table_options!(create_sql, o)
FILE: lib/torque/postgresql/adapter/schema_definitions.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type ColumnMethods (line 6) | module ColumnMethods
function search_language (line 9) | def search_language(*names, **options)
function search_vector (line 15) | def search_vector(*names, columns:, **options)
type TableDefinition (line 23) | module TableDefinition
function initialize (line 28) | def initialize(*args, **options)
function set_primary_key (line 35) | def set_primary_key(tn, id, primary_key, *, **)
function create_column_definition (line 41) | def create_column_definition(name, type, options)
type Definition (line 55) | module Definition
function create_function (line 57) | def create_function(name, version:, dir: pool.migrations_paths)
function create_type (line 62) | def create_type(name, version:, dir: pool.migrations_paths)
function create_view (line 67) | def create_view(name, version:, dir: pool.migrations_paths)
FILE: lib/torque/postgresql/adapter/schema_dumper.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type SchemaDumper (line 6) | module SchemaDumper
function initialize (line 15) | def initialize(*)
function dump (line 24) | def dump(stream) # :nodoc:
function types (line 34) | def types(stream) # :nodoc:
function tables (line 41) | def tables(stream) # :nodoc:
function around_tables (line 45) | def around_tables(stream)
function dump_tables (line 55) | def dump_tables(stream)
function remove_prefix_and_suffix (line 101) | def remove_prefix_and_suffix(table)
function schemas (line 106) | def schemas(stream)
function schema_type_with_virtual (line 116) | def schema_type_with_virtual(column)
function schema_type (line 121) | def schema_type(column)
function prepare_column_options (line 126) | def prepare_column_options(column)
function parse_search_vector_options (line 133) | def parse_search_vector_options(column, options)
function parse_search_vector_columns (line 149) | def parse_search_vector_columns(settings)
function versioned_commands (line 168) | def versioned_commands(stream, type, add_newline = false)
function list_existing_versioned_commands (line 186) | def list_existing_versioned_commands(type)
function with_versioned_commands? (line 192) | def with_versioned_commands?
function fx_functions_position (line 196) | def fx_functions_position
FILE: lib/torque/postgresql/adapter/schema_overrides.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type SchemaOverrides (line 6) | module SchemaOverrides
function quote_table_name (line 8) | def quote_table_name(name)
function drop_table (line 30) | def drop_table(*table_names, **options)
function validate_table_length! (line 37) | def validate_table_length!(table_name)
FILE: lib/torque/postgresql/adapter/schema_statements.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Adapter (line 5) | module Adapter
type SchemaStatements (line 6) | module SchemaStatements
function drop_type (line 8) | def drop_type(name, options = {})
function rename_type (line 20) | def rename_type(type_name, new_name, options = {})
function add_search_language (line 31) | def add_search_language(table, name, options = {})
function add_search_vector (line 51) | def add_search_vector(table, name, columns, options = {})
function add_enum_values (line 63) | def add_enum_values(name, values, options = {})
function enum_values (line 86) | def enum_values(name)
function table_options (line 96) | def table_options(table_name)
function quoted_scope (line 118) | def quoted_scope(name = nil, type: nil)
function data_source_sql (line 128) | def data_source_sql(name = nil, type: nil)
function valid_table_definition_options (line 136) | def valid_table_definition_options
function assume_migrated_upto_version (line 141) | def assume_migrated_upto_version(version)
function insert_versions_sql (line 165) | def insert_versions_sql(versions)
function sequence_name_from_parts (line 188) | def sequence_name_from_parts(table_name, column_name, suffix)
function sanitize_name_with_schema (line 193) | def sanitize_name_with_schema(name, options)
function quote_enum_values (line 198) | def quote_enum_values(name, values, options)
FILE: lib/torque/postgresql/arel/infix_operation.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
function build_operations (line 8) | def self.build_operations(operations)
FILE: lib/torque/postgresql/arel/join_source.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
type JoinSource (line 6) | module JoinSource
function only? (line 9) | def only?
FILE: lib/torque/postgresql/arel/nodes.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
type Nodes (line 6) | module Nodes
class Cast (line 8) | class Cast < ::Arel::Nodes::Binary
method initialize (line 15) | def initialize(left, right, array = false)
class Ref (line 22) | class Ref < ::Arel::Nodes::Unary
method initialize (line 26) | def initialize(expr, reference = nil)
method as (line 31) | def as(other)
FILE: lib/torque/postgresql/arel/operations.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
type Operations (line 6) | module Operations
function pg_cast (line 9) | def pg_cast(type, array = false)
function cast (line 15) | def cast(type, array = false)
FILE: lib/torque/postgresql/arel/select_manager.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
type SelectManager (line 6) | module SelectManager
function only (line 8) | def only
FILE: lib/torque/postgresql/arel/visitors.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Arel (line 5) | module Arel
type Visitors (line 6) | module Visitors
function visit_Arel_Nodes_JoinSource (line 8) | def visit_Arel_Nodes_JoinSource(o, collector)
function visit_Arel_Nodes_Quoted (line 14) | def visit_Arel_Nodes_Quoted(o, collector)
function visit_Arel_Nodes_Casted (line 20) | def visit_Arel_Nodes_Casted(o, collector)
function visit_Torque_PostgreSQL_Arel_Nodes_Ref (line 28) | def visit_Torque_PostgreSQL_Arel_Nodes_Ref(o, collector)
function visit_Torque_PostgreSQL_Arel_Nodes_Cast (line 33) | def visit_Torque_PostgreSQL_Arel_Nodes_Cast(o, collector)
function quote_array (line 39) | def quote_array(value, collector)
FILE: lib/torque/postgresql/associations/association_scope.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type AssociationScope (line 6) | module AssociationScope
class PredicateBuilderArray (line 9) | class PredicateBuilderArray
method call_with_empty (line 12) | def call_with_empty(attribute)
type ClassMethods (line 17) | module ClassMethods
function get_bind_values (line 18) | def get_bind_values(*)
function last_chain_scope (line 28) | def last_chain_scope(scope, reflection, owner)
function next_chain_scope (line 43) | def next_chain_scope(scope, reflection, next_reflection)
function transform_value (line 55) | def transform_value(value)
FILE: lib/torque/postgresql/associations/belongs_to_many_association.rb
type Torque (line 6) | module Torque
type PostgreSQL (line 7) | module PostgreSQL
type Associations (line 8) | module Associations
class BelongsToManyAssociation (line 9) | class BelongsToManyAssociation < ::ActiveRecord::Associations::Col...
method ids_reader (line 13) | def ids_reader
method ids_writer (line 23) | def ids_writer(ids)
method size (line 31) | def size
method empty? (line 42) | def empty?
method include? (line 46) | def include?(record)
method load_target (line 54) | def load_target
method build_changes (line 64) | def build_changes(from_target = false)
method trigger (line 73) | def trigger(prefix, before_ids, after_ids)
method handle_dependency (line 95) | def handle_dependency
method insert_record (line 137) | def insert_record(record, *)
method default (line 144) | def default(&block)
method _create_record (line 151) | def _create_record(attributes, raises = false, &block)
method delete_count (line 169) | def delete_count(method, scope, ids)
method delete_or_nullify_all_records (line 174) | def delete_or_nullify_all_records(method)
method delete_records (line 179) | def delete_records(records, method)
method source_attr (line 191) | def source_attr
method klass_attr (line 195) | def klass_attr
method read_records_ids (line 199) | def read_records_ids(records)
method ids_rewriter (line 204) | def ids_rewriter(ids, operator)
method column_default_value (line 213) | def column_default_value
method callback (line 217) | def callback(*)
method replace_records (line 222) | def replace_records(*)
method concat_records (line 226) | def concat_records(*)
method delete_or_destroy (line 230) | def delete_or_destroy(*)
method difference (line 234) | def difference(a, b)
method intersection (line 238) | def intersection(a, b)
method scope_for_create (line 243) | def scope_for_create
method find_target? (line 247) | def find_target?
method foreign_key_present? (line 251) | def foreign_key_present?
method invertible_for? (line 255) | def invertible_for?(record)
method stale_state (line 261) | def stale_state
FILE: lib/torque/postgresql/associations/builder/belongs_to_many.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type Builder (line 6) | module Builder
class BelongsToMany (line 7) | class BelongsToMany < ::ActiveRecord::Associations::Builder::Col...
method macro (line 8) | def self.macro
method valid_options (line 12) | def self.valid_options(options)
method valid_dependent_options (line 16) | def self.valid_dependent_options
method define_callbacks (line 20) | def self.define_callbacks(model, reflection)
method define_readers (line 27) | def self.define_readers(mixin, name)
method define_writers (line 35) | def self.define_writers(mixin, name)
method add_default_callbacks (line 43) | def self.add_default_callbacks(model, reflection)
method add_touch_callbacks (line 49) | def self.add_touch_callbacks(model, reflection)
method touch_record (line 67) | def self.touch_record(o, changes, foreign_key, name, touch, to...
method add_change_callbacks (line 98) | def self.add_change_callbacks(model, reflection)
method add_destroy_callbacks (line 113) | def self.add_destroy_callbacks(model, reflection)
method define_validations (line 117) | def self.define_validations(model, reflection)
FILE: lib/torque/postgresql/associations/builder/has_many.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type Builder (line 6) | module Builder
type HasMany (line 7) | module HasMany
function valid_options (line 8) | def valid_options(options)
FILE: lib/torque/postgresql/associations/foreign_association.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type ForeignAssociation (line 6) | module ForeignAssociation
function inversed_from (line 10) | def inversed_from(record)
function skip_statement_cache? (line 19) | def skip_statement_cache?(*)
function set_owner_attributes (line 27) | def set_owner_attributes(record)
FILE: lib/torque/postgresql/associations/preloader/association.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type Preloader (line 6) | module Preloader
type Association (line 7) | module Association
function run (line 13) | def run
function set_inverse (line 23) | def set_inverse(record)
function load_records (line 38) | def load_records(raw_records = nil)
function owners_by_key (line 62) | def owners_by_key
function run_array_for_belongs_to_many (line 74) | def run_array_for_belongs_to_many
function run_array_for_has_many (line 84) | def run_array_for_has_many
function records_for (line 99) | def records_for(ids, &block)
function associate_records_to_owner (line 106) | def associate_records_to_owner(owner, records)
function groupped_records (line 113) | def groupped_records
FILE: lib/torque/postgresql/associations/preloader/loader_query.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Associations (line 5) | module Associations
type Preloader (line 6) | module Preloader
type LoaderQuery (line 7) | module LoaderQuery
function foreign_column (line 8) | def foreign_column
function load_records_for_keys (line 12) | def load_records_for_keys(keys, &block)
function query_condition_for (line 19) | def query_condition_for(keys)
function connected_through_array? (line 26) | def connected_through_array?
FILE: lib/torque/postgresql/attributes/builder.rb
type Torque (line 7) | module Torque
type PostgreSQL (line 8) | module PostgreSQL
type Attributes (line 9) | module Attributes
type Builder (line 10) | module Builder
function include_on (line 11) | def self.include_on(klass, method_name, builder_klass, **extra, ...
function search_vector_options (line 29) | def self.search_vector_options(columns:, language: nil, stored: ...
function to_search_weights (line 40) | def self.to_search_weights(columns)
function to_search_vector_operation (line 50) | def self.to_search_vector_operation(language, weights)
FILE: lib/torque/postgresql/attributes/builder/enum.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
type Builder (line 6) | module Builder
class Enum (line 7) | class Enum
method initialize (line 15) | def initialize(klass, attribute, options)
method values_methods (line 34) | def values_methods
method set_features? (line 57) | def set_features?
method conflicting? (line 63) | def conflicting?
method build (line 92) | def build
method dangerous? (line 108) | def dangerous?(method_name, class_method = false)
method plural (line 130) | def plural
method set_scopes (line 155) | def set_scopes
method stringify (line 174) | def stringify
method all_values (line 184) | def all_values
FILE: lib/torque/postgresql/attributes/builder/full_text_search.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
type Builder (line 6) | module Builder
class FullTextSearch (line 7) | class FullTextSearch
method initialize (line 11) | def initialize(klass, attribute, options = {})
method scope_name (line 32) | def scope_name
method conflicting? (line 41) | def conflicting?
method build (line 50) | def build
method add_scope_to_module (line 57) | def add_scope_to_module
method scope_args (line 97) | def scope_args
FILE: lib/torque/postgresql/attributes/builder/period.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
type Builder (line 6) | module Builder
class Period (line 7) | class Period
method initialize (line 29) | def initialize(klass, attribute, options)
method threshold (line 47) | def threshold
method method_names (line 74) | def method_names
method klass_method_names (line 79) | def klass_method_names
method instance_method_names (line 84) | def instance_method_names
method conflicting? (line 90) | def conflicting?
method build (line 104) | def build
method build_method_helper (line 161) | def build_method_helper(type, key, args = [])
method default_method_names (line 175) | def default_method_names
method dangerous? (line 187) | def dangerous?(method_name, class_method = false)
method define_string_method (line 200) | def define_string_method(name, body, args = [])
method arel_attribute (line 206) | def arel_attribute
method arel_default_sql (line 210) | def arel_default_sql
method arel_sql_bind (line 214) | def arel_sql_bind(value)
method arel_threshold_value (line 219) | def arel_threshold_value
method arel_start_at (line 237) | def arel_start_at
method arel_finish_at (line 242) | def arel_finish_at
method arel_real_start_at (line 247) | def arel_real_start_at
method arel_real_finish_at (line 257) | def arel_real_finish_at
method arel_real_attribute (line 267) | def arel_real_attribute
method arel_convert_to_type (line 275) | def arel_convert_to_type(left, right = nil, set_type = nil)
method arel_named_function (line 280) | def arel_named_function(name, *args)
method arel_nullif (line 287) | def arel_nullif(*args)
method arel_coalesce (line 292) | def arel_coalesce(*args)
method arel_empty_value (line 297) | def arel_empty_value
method arel_daterange (line 302) | def arel_daterange(real = false)
method arel_check_condition (line 311) | def arel_check_condition(type)
method arel_formatting_value (line 317) | def arel_formatting_value(condition = nil, value = 'value', ca...
method arel_formatting_left_right (line 328) | def arel_formatting_left_right(condition, set_type = nil, cast...
method klass_current_on (line 344) | def klass_current_on
method klass_current (line 348) | def klass_current
method klass_not_current (line 355) | def klass_not_current
method klass_containing (line 362) | def klass_containing
method klass_not_containing (line 366) | def klass_not_containing
method klass_overlapping (line 370) | def klass_overlapping
method klass_not_overlapping (line 374) | def klass_not_overlapping
method klass_starting_after (line 378) | def klass_starting_after
method klass_starting_before (line 382) | def klass_starting_before
method klass_finishing_after (line 386) | def klass_finishing_after
method klass_finishing_before (line 390) | def klass_finishing_before
method klass_real_containing (line 394) | def klass_real_containing
method klass_real_overlapping (line 398) | def klass_real_overlapping
method klass_real_starting_after (line 402) | def klass_real_starting_after
method klass_real_starting_before (line 406) | def klass_real_starting_before
method klass_real_finishing_after (line 410) | def klass_real_finishing_after
method klass_real_finishing_before (line 414) | def klass_real_finishing_before
method klass_containing_date (line 418) | def klass_containing_date
method klass_not_containing_date (line 423) | def klass_not_containing_date
method klass_overlapping_date (line 428) | def klass_overlapping_date
method klass_not_overlapping_date (line 433) | def klass_not_overlapping_date
method klass_real_containing_date (line 438) | def klass_real_containing_date
method klass_real_overlapping_date (line 443) | def klass_real_overlapping_date
method instance_current? (line 448) | def instance_current?
method instance_current_on? (line 452) | def instance_current_on?
method instance_start (line 463) | def instance_start
method instance_finish (line 467) | def instance_finish
method instance_real (line 471) | def instance_real
method instance_real_start (line 483) | def instance_real_start
method instance_real_finish (line 497) | def instance_real_finish
FILE: lib/torque/postgresql/attributes/enum.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
class Enum (line 6) | class Enum < String
class EnumError (line 9) | class EnumError < ArgumentError; end
method lookup (line 19) | def lookup(name)
method include_on (line 29) | def include_on(klass, method_name = nil)
method new (line 37) | def new(value)
method values (line 43) | def values
method keys (line 50) | def keys
method members (line 55) | def members
method texts (line 60) | def texts
method to_options (line 65) | def to_options
method fetch (line 72) | def fetch(value, *)
method type_name (line 78) | def type_name
method valid? (line 83) | def valid?(value)
method scope (line 90) | def scope(attribute, value)
method respond_to_missing? (line 97) | def respond_to_missing?(method_name, include_private = false)
method method_missing (line 102) | def method_missing(method_name, *arguments)
method connection (line 108) | def connection
method initialize (line 115) | def initialize(value)
method <=> (line 122) | def <=>(other)
method == (line 133) | def ==(other)
method nil? (line 141) | def nil?
method replace (line 147) | def replace(value)
method text (line 153) | def text(attr = nil, model = nil)
method to_s (line 159) | def to_s
method to_i (line 164) | def to_i
method inspect (line 169) | def inspect
method i18n_keys (line 176) | def i18n_keys(attr = nil, model = nil)
method respond_to_missing? (line 192) | def respond_to_missing?(method_name, include_private = false)
method method_missing (line 200) | def method_missing(method_name, *arguments)
method raise_invalid (line 213) | def raise_invalid(value)
method raise_comparison (line 222) | def raise_comparison(other)
FILE: lib/torque/postgresql/attributes/enum_set.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
class EnumSet (line 6) | class EnumSet < Set
class EnumSetError (line 9) | class EnumSetError < Enum::EnumError; end
method lookup (line 19) | def lookup(name, enum_klass)
method include_on (line 32) | def include_on(klass, method_name = nil)
method enum_source (line 40) | def enum_source
method sample (line 45) | def sample
method new (line 50) | def new(*values)
method type_name (line 56) | def type_name
method fetch (line 63) | def fetch(value, *)
method power (line 69) | def power(*values)
method scope (line 80) | def scope(attribute, value)
method respond_to_missing? (line 87) | def respond_to_missing?(method_name, include_private = false)
method method_missing (line 92) | def method_missing(method_name, *arguments)
method initialize (line 99) | def initialize(*values)
method <=> (line 111) | def <=>(other)
method == (line 124) | def ==(other)
method replace (line 132) | def replace(*values)
method text (line 137) | def text(attr = nil, model = nil)
method to_i (line 143) | def to_i
method inspect (line 148) | def inspect
method []= (line 153) | def []=(key, value)
method merge (line 158) | def merge(other)
method & (line 163) | def &(other)
method instantiate (line 188) | def instantiate(value)
method transform_power (line 193) | def transform_power(value)
method transform_values (line 203) | def transform_values(values)
method respond_to_missing? (line 209) | def respond_to_missing?(method_name, include_private = false)
method method_missing (line 217) | def method_missing(method_name, *arguments)
method raise_invalid (line 230) | def raise_invalid(value)
method raise_comparison (line 239) | def raise_comparison(other)
FILE: lib/torque/postgresql/attributes/full_text_search.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
type FullTextSearch (line 7) | module FullTextSearch
function include_on (line 11) | def include_on(klass, method_name = nil)
FILE: lib/torque/postgresql/attributes/lazy.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
class Lazy (line 6) | class Lazy < BasicObject
method initialize (line 8) | def initialize(klass, *values)
method == (line 12) | def ==(other)
method nil? (line 16) | def nil?
method inspect (line 20) | def inspect
method __class__ (line 24) | def __class__
method method_missing (line 28) | def method_missing(name, *args, &block)
FILE: lib/torque/postgresql/attributes/period.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Attributes (line 5) | module Attributes
type Period (line 7) | module Period
function include_on (line 11) | def include_on(klass, method_name = nil)
FILE: lib/torque/postgresql/autosave_association.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type AutosaveAssociation (line 5) | module AutosaveAssociation
type ClassMethods (line 6) | module ClassMethods
function add_autosave_association_callbacks (line 10) | def add_autosave_association_callbacks(reflection)
function save_belongs_to_many_association (line 26) | def save_belongs_to_many_association(reflection)
FILE: lib/torque/postgresql/auxiliary_statement.rb
type Torque (line 6) | module Torque
type PostgreSQL (line 7) | module PostgreSQL
class AuxiliaryStatement (line 8) | class AuxiliaryStatement
method lookup (line 15) | def lookup(name, base)
method instantiate (line 25) | def instantiate(statement, base, **options)
method build (line 40) | def build(statement, base, bound_attributes = [], join_sources = [...
method relation_query? (line 50) | def relation_query?(obj)
method arel_query? (line 56) | def arel_query?(obj)
method create (line 62) | def create(table_or_settings, &block)
method configurator (line 78) | def configurator(config)
method configure (line 93) | def configure(base, instance)
method table (line 103) | def table
method initialize (line 114) | def initialize(*, **options)
method build (line 128) | def build(base)
method prepare (line 145) | def prepare(base, settings)
method build_query (line 174) | def build_query(base)
method build_join (line 195) | def build_join(base)
method arel_join (line 239) | def arel_join
method expose_columns (line 253) | def expose_columns(base, query_table = nil)
method ensure_dependencies (line 272) | def ensure_dependencies(list, base)
method project (line 292) | def project(column, arel_table = nil)
FILE: lib/torque/postgresql/auxiliary_statement/recursive.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class AuxiliaryStatement (line 5) | class AuxiliaryStatement
class Recursive (line 6) | class Recursive < AuxiliaryStatement
method initialize (line 8) | def initialize(*, **options)
method build_query (line 29) | def build_query(base)
method prepare (line 65) | def prepare(base, settings)
method prepare_sub_query (line 72) | def prepare_sub_query(base, settings)
method extra_columns (line 113) | def extra_columns(base, columns, sub_columns)
FILE: lib/torque/postgresql/auxiliary_statement/settings.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class AuxiliaryStatement (line 5) | class AuxiliaryStatement
class Settings (line 6) | class Settings < Collector.new(:attributes, :join, :join_type, :qu...
method initialize (line 17) | def initialize(base, source, recursive = false)
method base_name (line 23) | def base_name
method base_table (line 27) | def base_table
method recursive? (line 31) | def recursive?
method depth? (line 35) | def depth?
method path? (line 39) | def path?
method with_depth (line 44) | def with_depth(name = 'depth', start: 0, as: nil)
method with_path (line 49) | def with_path(name = 'path', source: nil, as: nil)
method union_all! (line 54) | def union_all!
method with_depth_and_path (line 59) | def with_depth_and_path
method query_table (line 64) | def query_table
method col (line 71) | def col(name)
method query (line 81) | def query(value = nil, command = nil)
method sub_query (line 88) | def sub_query(value = nil, command = nil)
method connect (line 96) | def connect(value = nil)
method sanitize_query (line 111) | def sanitize_query(value, command = nil)
FILE: lib/torque/postgresql/base.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Base (line 5) | module Base
function reset_table_name (line 24) | def reset_table_name
function inherited (line 31) | def inherited(subclass)
function belongs_to_many (line 199) | def belongs_to_many(name, scope = nil, **options, &extension)
function dynamic_attribute (line 230) | def dynamic_attribute(name, &block)
function auxiliary_statement (line 286) | def auxiliary_statement(table, &block)
function recursive_auxiliary_statement (line 296) | def recursive_auxiliary_statement(table, &block)
FILE: lib/torque/postgresql/collector.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Collector (line 5) | module Collector
function new (line 9) | def self.new(*args)
FILE: lib/torque/postgresql/config.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
function logger (line 8) | def self.logger
function irregular_models= (line 33) | def config.irregular_models=(hash)
FILE: lib/torque/postgresql/function.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Function (line 7) | module Function
function bind (line 12) | def bind(*args)
function bind_for (line 19) | def bind_for(model, attribute, value)
function bind_with (line 24) | def bind_with(arel_attribute, value)
function bind_type (line 29) | def bind_type(value, type = nil, name: 'value', cast: nil)
function infix (line 37) | def infix(op, left, right)
function concat (line 44) | def concat(*args)
function group_by (line 51) | def group_by(arel, name)
function respond_to_missing? (line 58) | def respond_to_missing?(*)
function method_missing (line 66) | def method_missing(name, *args, &block)
function ruby_type_to_model_type (line 72) | def ruby_type_to_model_type(value)
FILE: lib/torque/postgresql/geometry_builder.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class GeometryBuilder (line 5) | class GeometryBuilder < ActiveModel::Type::Value
method type (line 10) | def type
method pieces (line 15) | def pieces
method formation (line 19) | def formation
method cast (line 23) | def cast(value)
method serialize (line 38) | def serialize(value)
method deserialize (line 56) | def deserialize(value)
method type_cast_for_schema (line 60) | def type_cast_for_schema(value)
method changed_in_place? (line 68) | def changed_in_place?(raw_old_value, new_value)
method number_serializer (line 74) | def number_serializer
method config_class (line 78) | def config_class
method build_klass (line 82) | def build_klass(*args)
method check_invalid_format! (line 89) | def check_invalid_format!(args)
FILE: lib/torque/postgresql/i18n.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type I18n (line 5) | module I18n
function localize (line 10) | def localize(locale, object, format = :default, options = {})
FILE: lib/torque/postgresql/inheritance.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Inheritance (line 7) | module Inheritance
function cast_record (line 11) | def cast_record
function inheritance_merged_attributes (line 27) | def inheritance_merged_attributes
function inheritance_mergeable_attributes (line 36) | def inheritance_mergeable_attributes
function physically_inherited? (line 56) | def physically_inherited?
function inheritance_dependents (line 68) | def inheritance_dependents
function physically_inheritances? (line 73) | def physically_inheritances?
function casted_dependents (line 79) | def casted_dependents
function reset_table_name (line 87) | def reset_table_name
function decorated_table_name (line 99) | def decorated_table_name
function base_class (line 112) | def base_class
function primary_key (line 118) | def primary_key
function compute_table_name (line 124) | def compute_table_name
function raise_unable_to_cast (line 130) | def raise_unable_to_cast(record_class_value)
function instantiate_instance_of (line 143) | def instantiate_instance_of(klass, attributes, types = {}, &block)
function sanitize_attributes (line 155) | def sanitize_attributes(real_class, attributes, types)
function torque_discriminate_class_for_record (line 184) | def torque_discriminate_class_for_record(klass, record)
FILE: lib/torque/postgresql/insert_all.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type InsertAll (line 5) | module InsertAll
function initialize (line 8) | def initialize(*args, where: nil, **xargs)
type InsertAll::Builder (line 15) | module InsertAll::Builder
function where_condition? (line 18) | def where_condition?
FILE: lib/torque/postgresql/migration/command_recorder.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Migration (line 5) | module Migration
type CommandRecorder (line 6) | module CommandRecorder
function rename_type (line 9) | def rename_type(*args, &block)
function invert_rename_type (line 14) | def invert_rename_type(args)
function create_schema (line 19) | def create_schema(*args, &block)
function invert_create_schema (line 24) | def invert_create_schema(args)
FILE: lib/torque/postgresql/predicate_builder.rb
type Torque (line 9) | module Torque
type PostgreSQL (line 10) | module PostgreSQL
type PredicateBuilder (line 11) | module PredicateBuilder
function initialize (line 14) | def initialize(*)
FILE: lib/torque/postgresql/predicate_builder/arel_attribute_handler.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type PredicateBuilder (line 5) | module PredicateBuilder
class ArelAttributeHandler (line 6) | class ArelAttributeHandler
method call (line 8) | def self.call(*args)
method initialize (line 12) | def initialize(*)
method call (line 16) | def call(attribute, value)
method array_typed? (line 27) | def array_typed?(attribute)
FILE: lib/torque/postgresql/predicate_builder/array_handler.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type PredicateBuilder (line 5) | module PredicateBuilder
type ArrayHandler (line 6) | module ArrayHandler
function call (line 7) | def call(attribute, value)
function call_for_array (line 14) | def call_for_array(attribute, value)
function call_with_value (line 26) | def call_with_value(attribute, value)
function call_with_array (line 30) | def call_with_array(attribute, value)
function call_with_empty (line 34) | def call_with_empty(attribute)
function array_attribute? (line 38) | def array_attribute?(attribute)
FILE: lib/torque/postgresql/predicate_builder/enumerator_lazy_handler.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type PredicateBuilder (line 5) | module PredicateBuilder
class EnumeratorLazyHandler (line 6) | class EnumeratorLazyHandler < ::ActiveRecord::PredicateBuilder::Ar...
method call (line 9) | def call(attribute, value)
method with_timeout (line 17) | def with_timeout
method timeout (line 27) | def timeout
method limit (line 31) | def limit
FILE: lib/torque/postgresql/predicate_builder/regexp_handler.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type PredicateBuilder (line 5) | module PredicateBuilder
class RegexpHandler (line 6) | class RegexpHandler
method initialize (line 7) | def initialize(predicate_builder)
method call (line 11) | def call(attribute, value)
FILE: lib/torque/postgresql/railtie.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class Railtie (line 6) | class Railtie < Rails::Railtie # :nodoc:
FILE: lib/torque/postgresql/reflection.rb
type Torque (line 10) | module Torque
type PostgreSQL (line 11) | module PostgreSQL
type Reflection (line 12) | module Reflection
function create (line 14) | def create(macro, name, scope, options, ar)
FILE: lib/torque/postgresql/reflection/abstract_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
type AbstractReflection (line 6) | module AbstractReflection
function connected_through_array? (line 11) | def connected_through_array?
function join_scope (line 18) | def join_scope(table, foreign_table, foreign_klass)
function build_join_constraint (line 31) | def build_join_constraint(table, foreign_table)
function build_id_constraint_between (line 43) | def build_id_constraint_between(table, foreign_table)
FILE: lib/torque/postgresql/reflection/association_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
type AssociationReflection (line 6) | module AssociationReflection
function initialize (line 8) | def initialize(name, scope, options, active_record)
function derive_foreign_key (line 20) | def derive_foreign_key(*, **)
function automatic_inverse_of (line 28) | def automatic_inverse_of
FILE: lib/torque/postgresql/reflection/belongs_to_many_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
class BelongsToManyReflection (line 6) | class BelongsToManyReflection < ::ActiveRecord::Reflection::Associ...
method macro (line 7) | def macro
method connected_through_array? (line 11) | def connected_through_array?
method belongs_to? (line 15) | def belongs_to?
method collection? (line 19) | def collection?
method association_class (line 23) | def association_class
method foreign_key (line 27) | def foreign_key
method association_foreign_key (line 31) | def association_foreign_key
method active_record_primary_key (line 35) | def active_record_primary_key
method join_primary_key (line 39) | def join_primary_key(*)
method join_foreign_key (line 43) | def join_foreign_key
method array_attribute (line 47) | def array_attribute
method derive_primary_key (line 53) | def derive_primary_key
method derive_foreign_key (line 57) | def derive_foreign_key
FILE: lib/torque/postgresql/reflection/has_many_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
type HasManyReflection (line 6) | module HasManyReflection
function connected_through_array? (line 7) | def connected_through_array?
function array_attribute (line 11) | def array_attribute
FILE: lib/torque/postgresql/reflection/runtime_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
type RuntimeReflection (line 6) | module RuntimeReflection
FILE: lib/torque/postgresql/reflection/through_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Reflection (line 5) | module Reflection
type ThroughReflection (line 6) | module ThroughReflection
FILE: lib/torque/postgresql/relation.rb
type Torque (line 8) | module Torque
type PostgreSQL (line 9) | module PostgreSQL
type Relation (line 10) | module Relation
function select_extra_values (line 27) | def select_extra_values
function select_extra_values= (line 31) | def select_extra_values=(value)
function calculate (line 38) | def calculate(operation, column_name)
function resolve_column (line 54) | def resolve_column(list, base = false)
function resolve_base_table (line 75) | def resolve_base_table(relation)
function cast_for_condition (line 88) | def cast_for_condition(column, value)
function build_arel (line 96) | def build_arel(*)
function _record_class_attribute (line 105) | def _record_class_attribute
function _auto_cast_attribute (line 112) | def _auto_cast_attribute
type Initializer (line 121) | module Initializer
function initialize (line 122) | def initialize(klass, *, **)
function upsert_all (line 130) | def upsert_all(attributes, **xargs)
FILE: lib/torque/postgresql/relation/auxiliary_statement.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type AuxiliaryStatement (line 6) | module AuxiliaryStatement
function auxiliary_statements_values (line 9) | def auxiliary_statements_values
function auxiliary_statements_values= (line 13) | def auxiliary_statements_values=(value)
function with (line 19) | def with(*args, **settings)
function with! (line 24) | def with!(*args, **settings)
function bound_attributes (line 34) | def bound_attributes
function build_arel (line 45) | def build_arel(*)
function instantiate_auxiliary_statements (line 53) | def instantiate_auxiliary_statements(*args, **options)
function build_auxiliary_statements (line 67) | def build_auxiliary_statements(arel)
function auxiliary_statement_type (line 75) | def auxiliary_statement_type
function auxiliary_statement_error (line 82) | def auxiliary_statement_error(name)
FILE: lib/torque/postgresql/relation/buckets.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type Buckets (line 6) | module Buckets
function buckets_value (line 9) | def buckets_value
function buckets_value= (line 13) | def buckets_value=(value)
function buckets (line 26) | def buckets(*value, **xargs)
function buckets! (line 31) | def buckets!(attribute, values, count: nil, cast: nil, as: nil)
function calculate (line 45) | def calculate(*)
type Initializer (line 57) | module Initializer
function records (line 59) | def records
function build_arel (line 74) | def build_arel(*)
function build_buckets_node (line 82) | def build_buckets_node
function buckets_column (line 98) | def buckets_column
function buckets_keys (line 103) | def buckets_keys
FILE: lib/torque/postgresql/relation/distinct_on.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type DistinctOn (line 6) | module DistinctOn
function distinct_on_values (line 9) | def distinct_on_values
function distinct_on_values= (line 13) | def distinct_on_values=(value)
function distinct_on (line 29) | def distinct_on(*value)
function distinct_on! (line 34) | def distinct_on!(*value)
function build_arel (line 42) | def build_arel(*)
FILE: lib/torque/postgresql/relation/inheritance.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type Inheritance (line 6) | module Inheritance
function cast_records_values (line 9) | def cast_records_values
function cast_records_values= (line 13) | def cast_records_values=(value)
function itself_only_value (line 19) | def itself_only_value
function itself_only_value= (line 23) | def itself_only_value=(value)
function itself_only (line 35) | def itself_only
function itself_only! (line 40) | def itself_only!(*)
function cast_records (line 51) | def cast_records(*types, **options)
function cast_records! (line 56) | def cast_records!(*types, **options)
function build_arel (line 66) | def build_arel(*)
function build_inheritances (line 74) | def build_inheritances(arel)
function build_inheritances_joins (line 95) | def build_inheritances_joins(arel, types)
function build_auto_caster_marker (line 114) | def build_auto_caster_marker(arel, types)
function regclass (line 119) | def regclass
FILE: lib/torque/postgresql/relation/join_series.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type JoinSeries (line 6) | module JoinSeries
function build (line 10) | def build(relation, range, with: nil, as: :series, step: nil, ti...
function validate_build! (line 26) | def validate_build!(range, step)
function bind_value (line 45) | def bind_value(value)
function arel_join (line 69) | def arel_join(mode)
function build_join_on (line 83) | def build_join_on(result, relation, with, cast)
function join_series (line 101) | def join_series(range, **xargs, &block)
function join_series! (line 106) | def join_series!(range, **xargs, &block)
FILE: lib/torque/postgresql/relation/merger.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type Relation (line 5) | module Relation
type Merger (line 6) | module Merger
function merge (line 8) | def merge # :nodoc:
function merge_select_extra (line 23) | def merge_select_extra
function merge_distinct_on (line 29) | def merge_distinct_on
function merge_auxiliary_statements (line 37) | def merge_auxiliary_statements
function merge_inheritance (line 50) | def merge_inheritance
function merge_buckets (line 62) | def merge_buckets
FILE: lib/torque/postgresql/schema_cache.rb
type Torque (line 7) | module Torque
type PostgreSQL (line 8) | module PostgreSQL
type SchemaCache (line 12) | module SchemaCache
function initialize (line 15) | def initialize(*) # :nodoc:
function initialize_dup (line 24) | def initialize_dup(*) # :nodoc:
function encode_with (line 31) | def encode_with(coder) # :nodoc:
function init_with (line 38) | def init_with(coder) # :nodoc:
function add (line 45) | def add(connection_or_table_name, table_name = connection_or_table...
function clear! (line 56) | def clear! # :nodoc:
function size (line 64) | def size # :nodoc:
function clear_data_source_cache! (line 72) | def clear_data_source_cache!(connection_or_name, name = connection...
function marshal_dump (line 79) | def marshal_dump # :nodoc:
function marshal_load (line 88) | def marshal_load(array) # :nodoc:
function add_model_name (line 97) | def add_model_name(*args)
function dependencies (line 105) | def dependencies(source, table_name = source)
function associations (line 112) | def associations(source, table_name = source)
function lookup_model (line 119) | def lookup_model(*args, **xargs)
function reload_inheritance_data! (line 127) | def reload_inheritance_data!(source)
function generate_associations (line 139) | def generate_associations
function add_all (line 144) | def add_all(source = nil)
FILE: lib/torque/postgresql/schema_cache/bound_schema_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type BoundSchemaReflection (line 5) | module BoundSchemaReflection
function add_model_name (line 6) | def add_model_name(table_name, model)
function dependencies (line 11) | def dependencies(table_name)
function associations (line 16) | def associations(table_name)
function lookup_model (line 21) | def lookup_model(table_name, scoped_class = '')
FILE: lib/torque/postgresql/schema_cache/inheritance.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type SchemaCache (line 5) | module SchemaCache
type Inheritance (line 6) | module Inheritance
function lookup_model (line 9) | def lookup_model(table_name, scoped_class = '', source_to_model:)
function find_model (line 47) | def find_model(max_name, table_name, scope = Object)
function generate_associations (line 80) | def generate_associations(inheritance_dependencies)
function prepare_irregular_models (line 107) | def prepare_irregular_models(data_sources)
FILE: lib/torque/postgresql/schema_cache/schema_reflection.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type SchemaReflection (line 5) | module SchemaReflection
function add_model_name (line 6) | def add_model_name(source, table_name, model)
function dependencies (line 10) | def dependencies(source, table_name)
function associations (line 14) | def associations(source, table_name)
function lookup_model (line 18) | def lookup_model(source, table_name, scoped_class)
FILE: lib/torque/postgresql/table_name.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class TableName (line 5) | class TableName < Delegator
method initialize (line 6) | def initialize(klass, table_name)
method schema (line 11) | def schema
method to_s (line 20) | def to_s
method == (line 26) | def ==(other)
method __setobj__ (line 30) | def __setobj__(value)
method search_path_schemes (line 36) | def search_path_schemes
FILE: lib/torque/postgresql/version.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
FILE: lib/torque/postgresql/versioned_commands.rb
type Torque (line 8) | module Torque
type PostgreSQL (line 9) | module PostgreSQL
type VersionedCommands (line 15) | module VersionedCommands
function valid_type? (line 21) | def valid_type?(type)
function validate! (line 26) | def validate!(type, content, name)
function fetch_command (line 33) | def fetch_command(dirs, type, name, version)
function filename_regexp (line 50) | def filename_regexp
function validate_function! (line 68) | def validate_function!(content, name)
function validate_type! (line 90) | def validate_type!(content, name)
function validate_view! (line 121) | def validate_view!(content, name)
FILE: lib/torque/postgresql/versioned_commands/command_migration.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type VersionedCommands (line 5) | module VersionedCommands
type Migration (line 6) | module Migration
function initialize (line 7) | def initialize(*args)
function migrate (line 13) | def migrate(direction)
function exec_migration (line 19) | def exec_migration(conn, direction)
function announce (line 28) | def announce(message)
function description_for (line 46) | def description_for(direction)
function execute (line 59) | def execute(command)
function initialize (line 68) | def initialize(filename, *args)
function name (line 74) | def name
function disable_ddl_transaction (line 79) | def disable_ddl_transaction
function migrate (line 84) | def migrate(direction)
function up (line 94) | def up
function down (line 101) | def down
function drop (line 109) | def drop
function drop_function (line 118) | def drop_function
function drop_type (line 129) | def drop_type
function drop_view (line 135) | def drop_view
FILE: lib/torque/postgresql/versioned_commands/generator.rb
type Torque (line 6) | module Torque
type PostgreSQL (line 7) | module PostgreSQL
type VersionedCommands (line 8) | module VersionedCommands
type Generator (line 9) | module Generator
function included (line 14) | def self.included(base)
function type (line 32) | def type
function create_migration_file (line 36) | def create_migration_file
function count_object_entries (line 45) | def count_object_entries
function validate_file_name! (line 49) | def validate_file_name!
FILE: lib/torque/postgresql/versioned_commands/migration_context.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
class IllegalCommandTypeError (line 5) | class IllegalCommandTypeError < ActiveRecord::MigrationError
method initialize (line 6) | def initialize(file)
type VersionedCommands (line 16) | module VersionedCommands
type MigrationContext (line 17) | module MigrationContext
function migrations (line 21) | def migrations
function migrations_status (line 38) | def migrations_status
function migration_commands (line 57) | def migration_commands
function running_for_pg? (line 64) | def running_for_pg?
function command_files (line 69) | def command_files
function parse_command_filename (line 75) | def parse_command_filename(filename)
FILE: lib/torque/postgresql/versioned_commands/migrator.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type VersionedCommands (line 5) | module VersionedCommands
type Migrator (line 6) | module Migrator
function execute_migration_in_transaction (line 7) | def execute_migration_in_transaction(migration)
function record_version_state_after_migrating (line 14) | def record_version_state_after_migrating(version)
function versioned_command? (line 31) | def versioned_command?(migration)
FILE: lib/torque/postgresql/versioned_commands/schema_table.rb
type Torque (line 3) | module Torque
type PostgreSQL (line 4) | module PostgreSQL
type VersionedCommands (line 5) | module VersionedCommands
class SchemaTable (line 6) | class SchemaTable
method initialize (line 9) | def initialize(pool)
method create_version (line 14) | def create_version(command)
method delete_version (line 27) | def delete_version(command)
method primary_key (line 36) | def primary_key
method name (line 40) | def name
method table_name (line 44) | def table_name
method create_table (line 52) | def create_table
method drop_table (line 64) | def drop_table
method count (line 70) | def count
method table_exists? (line 81) | def table_exists?
method versions_of (line 85) | def versions_of(type)
FILE: spec/initialize.rb
type Torque (line 24) | module Torque
type PostgreSQL (line 25) | module PostgreSQL
FILE: spec/mocks/cache_query.rb
type Mocks (line 1) | module Mocks
type CacheQuery (line 2) | module CacheQuery
function get_last_executed_query (line 3) | def get_last_executed_query(&block)
function get_query_with_binds (line 18) | def get_query_with_binds(&block)
FILE: spec/mocks/create_table.rb
type Mocks (line 1) | module Mocks
type CreateTable (line 2) | module CreateTable
function mock_create_table (line 3) | def mock_create_table
FILE: spec/models/activity.rb
class Activity (line 1) | class Activity < ActiveRecord::Base
FILE: spec/models/activity_book.rb
class ActivityBook (line 3) | class ActivityBook < Activity
FILE: spec/models/activity_post.rb
class ActivityPost (line 3) | class ActivityPost < Activity
FILE: spec/models/activity_post/sample.rb
class ActivityPost (line 1) | class ActivityPost < Activity
class Sample (line 2) | class Sample < ActivityPost
FILE: spec/models/author.rb
class Author (line 1) | class Author < ActiveRecord::Base
FILE: spec/models/author_journalist.rb
class AuthorJournalist (line 3) | class AuthorJournalist < Author
FILE: spec/models/category.rb
class Category (line 1) | class Category< ActiveRecord::Base
FILE: spec/models/comment.rb
class Comment (line 1) | class Comment < ActiveRecord::Base
FILE: spec/models/course.rb
class Course (line 1) | class Course < ActiveRecord::Base
FILE: spec/models/geometry.rb
class Geometry (line 1) | class Geometry < ActiveRecord::Base
FILE: spec/models/guest_comment.rb
class GuestComment (line 3) | class GuestComment < Comment
FILE: spec/models/internal/user.rb
type Internal (line 1) | module Internal
class User (line 2) | class User < ActiveRecord::Base
FILE: spec/models/item.rb
class Item (line 1) | class Item < ActiveRecord::Base
FILE: spec/models/post.rb
class Post (line 1) | class Post < ActiveRecord::Base
FILE: spec/models/question.rb
class Question (line 1) | class Question < ActiveRecord::Base
FILE: spec/models/question_select.rb
class QuestionSelect (line 3) | class QuestionSelect < Question
FILE: spec/models/tag.rb
class Tag (line 1) | class Tag < ActiveRecord::Base
FILE: spec/models/text.rb
class Text (line 1) | class Text < ActiveRecord::Base
FILE: spec/models/time_keeper.rb
class TimeKeeper (line 1) | class TimeKeeper < ActiveRecord::Base
FILE: spec/models/user.rb
class User (line 1) | class User < ActiveRecord::Base
FILE: spec/models/video.rb
class Video (line 1) | class Video < ActiveRecord::Base
FILE: spec/tests/enum_set_spec.rb
function decorate (line 8) | def decorate(model, field, options = {})
FILE: spec/tests/enum_spec.rb
function decorate (line 8) | def decorate(model, field, options = {})
FILE: spec/tests/period_spec.rb
function decorate (line 22) | def decorate(model, field, options = {})
FILE: spec/tests/relation_spec.rb
function attribute (line 16) | def attribute(relation, name)
FILE: spec/tests/versioned_commands_spec.rb
function migration (line 432) | def migration(command)
Condensed preview — 173 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (564K chars).
[
{
"path": ".circleci/config.yml",
"chars": 1188,
"preview": "version: 2.1\norbs:\n ruby: circleci/ruby@1.4.0\n\njobs:\n test:\n parallelism: 3\n parameters:\n ruby-version:\n "
},
{
"path": ".github/FUNDING.yml",
"chars": 881,
"preview": "# These are supported funding model platforms\n\ngithub: ['crashtech']\n# patreon: # Replace with a single Patreon username"
},
{
"path": ".gitignore",
"chars": 256,
"preview": ".env\n*.gem\n*.rbc\n.bundle\n.config\n.yardoc\n.byebug_history\n.versions.conf\nGemfile.lock\ncoverage\ndoc/\n.config\ncoverage/\nIns"
},
{
"path": ".rspec",
"chars": 30,
"preview": "--color\n--require spec_helper\n"
},
{
"path": "Gemfile",
"chars": 579,
"preview": "source 'https://rubygems.org'\n\n# Declare your gem's dependencies in torque_postgresql.gemspec.\n# Bundler will treat runt"
},
{
"path": "MIT-LICENSE",
"chars": 1052,
"preview": "Copyright 2016 Carlos Silva\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this softwa"
},
{
"path": "README.md",
"chars": 4498,
"preview": "<a href=\"https://github.com/crashtech/torque-postgresql\">\n <img src=\"./docs/assets/images/github.png\" alt=\"Torque Postg"
},
{
"path": "README.rdoc",
"chars": 5542,
"preview": "= Torque PostgreSQL -- Add support to complex resources of PostgreSQL, like data\ntypes, user-defined types and auxiliary"
},
{
"path": "Rakefile",
"chars": 899,
"preview": "begin\n require 'bundler/setup'\nrescue LoadError\n puts 'You must `gem install bundler` and `bundle install` to run rake"
},
{
"path": "gemfiles/Gemfile.rails-8.0",
"chars": 104,
"preview": "source 'https://rubygems.org'\n\ngem 'rails', '~> 8.0', '< 8.1'\ngem 'pg', '~> 1.4.0'\n\ngemspec path: \"../\"\n"
},
{
"path": "lib/generators/torque/function_generator.rb",
"chars": 314,
"preview": "# frozen_string_literal: true\n\nrequire 'torque/postgresql/versioned_commands/generator'\n\nmodule Torque\n module Generato"
},
{
"path": "lib/generators/torque/templates/function.sql.erb",
"chars": 106,
"preview": "CREATE OR REPLACE FUNCTION <%= name %>()\nRETURNS void AS $$\n -- Function body goes here\n$$ LANGUAGE sql;\n"
},
{
"path": "lib/generators/torque/templates/type.sql.erb",
"chars": 58,
"preview": "DROP TYPE IF EXISTS <%= name %>;\nCREATE TYPE <%= name %>;\n"
},
{
"path": "lib/generators/torque/templates/view.sql.erb",
"chars": 197,
"preview": "<%= \"DROP MATERIALIZED VIEW IF EXISTS #{name};\\n\" if options[:materialized] %>CREATE <%= options[:materialized] ? 'MATER"
},
{
"path": "lib/generators/torque/type_generator.rb",
"chars": 306,
"preview": "# frozen_string_literal: true\n\nrequire 'torque/postgresql/versioned_commands/generator'\n\nmodule Torque\n module Generato"
},
{
"path": "lib/generators/torque/view_generator.rb",
"chars": 453,
"preview": "# frozen_string_literal: true\n\nrequire 'torque/postgresql/versioned_commands/generator'\n\nmodule Torque\n module Generato"
},
{
"path": "lib/torque/postgresql/adapter/database_statements.rb",
"chars": 8640,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module DatabaseStatements\n\n "
},
{
"path": "lib/torque/postgresql/adapter/oid/array.rb",
"chars": 384,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module OID\n module Arra"
},
{
"path": "lib/torque/postgresql/adapter/oid/box.rb",
"chars": 655,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class Box < Struct.new(:x1, :y1, :x2, :y2)\n de"
},
{
"path": "lib/torque/postgresql/adapter/oid/circle.rb",
"chars": 805,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class Circle < Struct.new(:x, :y, :r)\n alias r"
},
{
"path": "lib/torque/postgresql/adapter/oid/enum.rb",
"chars": 1780,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module OID\n class Enum "
},
{
"path": "lib/torque/postgresql/adapter/oid/enum_set.rb",
"chars": 1259,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module OID\n class EnumS"
},
{
"path": "lib/torque/postgresql/adapter/oid/interval.rb",
"chars": 3559,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module OID\n class Inter"
},
{
"path": "lib/torque/postgresql/adapter/oid/line.rb",
"chars": 1240,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class Line < Struct.new(:slope, :intercept)\n a"
},
{
"path": "lib/torque/postgresql/adapter/oid/range.rb",
"chars": 1824,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module OID\n class Range"
},
{
"path": "lib/torque/postgresql/adapter/oid/segment.rb",
"chars": 1499,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class Segment < Struct.new(:point0, :point1)\n "
},
{
"path": "lib/torque/postgresql/adapter/oid.rb",
"chars": 58,
"preview": "require_relative 'oid/array'\nrequire_relative 'oid/range'\n"
},
{
"path": "lib/torque/postgresql/adapter/quoting.rb",
"chars": 1691,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module Quoting\n QUOTED_"
},
{
"path": "lib/torque/postgresql/adapter/schema_creation.rb",
"chars": 690,
"preview": "module Torque\n module PostgreSQL\n module Adapter\n module SchemaCreation\n\n # Inherits are now setup via t"
},
{
"path": "lib/torque/postgresql/adapter/schema_definitions.rb",
"chars": 2618,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module ColumnMethods\n\n "
},
{
"path": "lib/torque/postgresql/adapter/schema_dumper.rb",
"chars": 7001,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module SchemaDumper\n SE"
},
{
"path": "lib/torque/postgresql/adapter/schema_overrides.rb",
"chars": 1569,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module SchemaOverrides\n "
},
{
"path": "lib/torque/postgresql/adapter/schema_statements.rb",
"chars": 8021,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Adapter\n module SchemaStatements\n "
},
{
"path": "lib/torque/postgresql/adapter.rb",
"chars": 1633,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'adapter/database_statements'\nrequire_relative 'adapter/oid'\nrequire_rel"
},
{
"path": "lib/torque/postgresql/arel/infix_operation.rb",
"chars": 1084,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n Math = Module.new\n\n def self"
},
{
"path": "lib/torque/postgresql/arel/join_source.rb",
"chars": 268,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n module JoinSource\n attr_ac"
},
{
"path": "lib/torque/postgresql/arel/nodes.rb",
"chars": 1211,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n module Nodes\n\n class Cast "
},
{
"path": "lib/torque/postgresql/arel/operations.rb",
"chars": 668,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n module Operations\n\n # Crea"
},
{
"path": "lib/torque/postgresql/arel/select_manager.rb",
"chars": 252,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n module SelectManager\n\n def"
},
{
"path": "lib/torque/postgresql/arel/visitors.rb",
"chars": 1439,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Arel\n module Visitors\n # Add ONL"
},
{
"path": "lib/torque/postgresql/arel.rb",
"chars": 213,
"preview": "require_relative 'arel/infix_operation'\nrequire_relative 'arel/join_source'\nrequire_relative 'arel/nodes'\nrequire_relati"
},
{
"path": "lib/torque/postgresql/associations/association_scope.rb",
"chars": 2503,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module AssociationScope\n "
},
{
"path": "lib/torque/postgresql/associations/belongs_to_many_association.rb",
"chars": 8319,
"preview": "# frozen_string_literal: true\n\nrequire 'active_record/associations/collection_association'\n\n# FIXME: build, create\nmodul"
},
{
"path": "lib/torque/postgresql/associations/builder/belongs_to_many.rb",
"chars": 4808,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module Builder\n cl"
},
{
"path": "lib/torque/postgresql/associations/builder/has_many.rb",
"chars": 325,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module Builder\n mo"
},
{
"path": "lib/torque/postgresql/associations/builder.rb",
"chars": 79,
"preview": "require_relative 'builder/belongs_to_many'\nrequire_relative 'builder/has_many'\n"
},
{
"path": "lib/torque/postgresql/associations/foreign_association.rb",
"chars": 1218,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module ForeignAssociation"
},
{
"path": "lib/torque/postgresql/associations/preloader/association.rb",
"chars": 4469,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module Preloader\n "
},
{
"path": "lib/torque/postgresql/associations/preloader/loader_query.rb",
"chars": 982,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Associations\n module Preloader\n "
},
{
"path": "lib/torque/postgresql/associations/preloader.rb",
"chars": 83,
"preview": "require_relative 'preloader/association'\nrequire_relative 'preloader/loader_query'\n"
},
{
"path": "lib/torque/postgresql/associations.rb",
"chars": 471,
"preview": "require_relative 'associations/association_scope'\nrequire_relative 'associations/belongs_to_many_association'\nrequire_re"
},
{
"path": "lib/torque/postgresql/attributes/builder/enum.rb",
"chars": 9449,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n module Builder\n clas"
},
{
"path": "lib/torque/postgresql/attributes/builder/full_text_search.rb",
"chars": 3889,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n module Builder\n clas"
},
{
"path": "lib/torque/postgresql/attributes/builder/period.rb",
"chars": 19934,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n module Builder\n clas"
},
{
"path": "lib/torque/postgresql/attributes/builder.rb",
"chars": 2357,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'builder/enum'\nrequire_relative 'builder/period'\nrequire_relative 'build"
},
{
"path": "lib/torque/postgresql/attributes/enum.rb",
"chars": 6979,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n class Enum < String\n "
},
{
"path": "lib/torque/postgresql/attributes/enum_set.rb",
"chars": 8031,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n class EnumSet < Set\n "
},
{
"path": "lib/torque/postgresql/attributes/full_text_search.rb",
"chars": 584,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n # For now, full text search"
},
{
"path": "lib/torque/postgresql/attributes/lazy.rb",
"chars": 559,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n class Lazy < BasicObject\n\n "
},
{
"path": "lib/torque/postgresql/attributes/period.rb",
"chars": 538,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Attributes\n # For now, period doesn't h"
},
{
"path": "lib/torque/postgresql/attributes.rb",
"chars": 73,
"preview": "require_relative 'attributes/lazy'\nrequire_relative 'attributes/builder'\n"
},
{
"path": "lib/torque/postgresql/autosave_association.rb",
"chars": 1558,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module AutosaveAssociation\n module ClassMethod"
},
{
"path": "lib/torque/postgresql/auxiliary_statement/recursive.rb",
"chars": 5639,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class AuxiliaryStatement\n class Recursive < Au"
},
{
"path": "lib/torque/postgresql/auxiliary_statement/settings.rb",
"chars": 3694,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class AuxiliaryStatement\n class Settings < Col"
},
{
"path": "lib/torque/postgresql/auxiliary_statement.rb",
"chars": 11070,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'auxiliary_statement/settings'\nrequire_relative 'auxiliary_statement/rec"
},
{
"path": "lib/torque/postgresql/base.rb",
"chars": 14120,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Base\n extend ActiveSupport::Concern\n\n "
},
{
"path": "lib/torque/postgresql/collector.rb",
"chars": 824,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Collector\n\n # This class helps to colle"
},
{
"path": "lib/torque/postgresql/config.rb",
"chars": 13410,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n include ActiveSupport::Configurable\n\n # Use the "
},
{
"path": "lib/torque/postgresql/function.rb",
"chars": 3333,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n # Simplified module for creating arel functions. Th"
},
{
"path": "lib/torque/postgresql/geometry_builder.rb",
"chars": 2394,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class GeometryBuilder < ActiveModel::Type::Value\n\n "
},
{
"path": "lib/torque/postgresql/i18n.rb",
"chars": 452,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module I18n\n\n # Adds extra suport to localize "
},
{
"path": "lib/torque/postgresql/inheritance.rb",
"chars": 7657,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n InheritanceError = Class.new(ArgumentError)\n\n mo"
},
{
"path": "lib/torque/postgresql/insert_all.rb",
"chars": 490,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module InsertAll\n attr_reader :where\n\n de"
},
{
"path": "lib/torque/postgresql/migration/command_recorder.rb",
"chars": 773,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Migration\n module CommandRecorder\n\n "
},
{
"path": "lib/torque/postgresql/migration.rb",
"chars": 46,
"preview": "require_relative 'migration/command_recorder'\n"
},
{
"path": "lib/torque/postgresql/predicate_builder/arel_attribute_handler.rb",
"chars": 848,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module PredicateBuilder\n class ArelAttributeHa"
},
{
"path": "lib/torque/postgresql/predicate_builder/array_handler.rb",
"chars": 1300,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module PredicateBuilder\n module ArrayHandler\n "
},
{
"path": "lib/torque/postgresql/predicate_builder/enumerator_lazy_handler.rb",
"chars": 917,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module PredicateBuilder\n class EnumeratorLazyH"
},
{
"path": "lib/torque/postgresql/predicate_builder/regexp_handler.rb",
"chars": 487,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module PredicateBuilder\n class RegexpHandler\n "
},
{
"path": "lib/torque/postgresql/predicate_builder.rb",
"chars": 977,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'predicate_builder/array_handler'\n\nrequire_relative 'predicate_builder/r"
},
{
"path": "lib/torque/postgresql/railtie.rb",
"chars": 6331,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n # = Torque PostgreSQL Railtie\n class Railtie < R"
},
{
"path": "lib/torque/postgresql/reflection/abstract_reflection.rb",
"chars": 1896,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n module AbstractReflection\n "
},
{
"path": "lib/torque/postgresql/reflection/association_reflection.rb",
"chars": 1805,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n module AssociationReflectio"
},
{
"path": "lib/torque/postgresql/reflection/belongs_to_many_reflection.rb",
"chars": 1632,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n class BelongsToManyReflecti"
},
{
"path": "lib/torque/postgresql/reflection/has_many_reflection.rb",
"chars": 382,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n module HasManyReflection\n "
},
{
"path": "lib/torque/postgresql/reflection/runtime_reflection.rb",
"chars": 354,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n module RuntimeReflection\n "
},
{
"path": "lib/torque/postgresql/reflection/through_reflection.rb",
"chars": 315,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Reflection\n module ThroughReflection\n "
},
{
"path": "lib/torque/postgresql/reflection.rb",
"chars": 663,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'reflection/abstract_reflection'\nrequire_relative 'reflection/associatio"
},
{
"path": "lib/torque/postgresql/relation/auxiliary_statement.rb",
"chars": 3065,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module AuxiliaryStatement\n\n "
},
{
"path": "lib/torque/postgresql/relation/buckets.rb",
"chars": 4104,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module Buckets\n\n # :no"
},
{
"path": "lib/torque/postgresql/relation/distinct_on.rb",
"chars": 1332,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module DistinctOn\n\n # "
},
{
"path": "lib/torque/postgresql/relation/inheritance.rb",
"chars": 4247,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module Inheritance\n\n #"
},
{
"path": "lib/torque/postgresql/relation/join_series.rb",
"chars": 4319,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module JoinSeries\n\n # "
},
{
"path": "lib/torque/postgresql/relation/merger.rb",
"chars": 2250,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module Relation\n module Merger\n\n def me"
},
{
"path": "lib/torque/postgresql/relation.rb",
"chars": 5237,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'relation/distinct_on'\nrequire_relative 'relation/inheritance'\n\nrequire_"
},
{
"path": "lib/torque/postgresql/schema_cache/bound_schema_reflection.rb",
"chars": 901,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module BoundSchemaReflection\n def add_model_na"
},
{
"path": "lib/torque/postgresql/schema_cache/inheritance.rb",
"chars": 4371,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module SchemaCache\n module Inheritance\n\n "
},
{
"path": "lib/torque/postgresql/schema_cache/schema_reflection.rb",
"chars": 665,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module SchemaReflection\n def add_model_name(so"
},
{
"path": "lib/torque/postgresql/schema_cache.rb",
"chars": 5110,
"preview": "# frozen_string_literal: true\n\nrequire 'torque/postgresql/schema_cache/inheritance'\nrequire 'torque/postgresql/schema_ca"
},
{
"path": "lib/torque/postgresql/table_name.rb",
"chars": 911,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class TableName < Delegator\n def initialize(kl"
},
{
"path": "lib/torque/postgresql/version.rb",
"chars": 97,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n VERSION = '4.0.1'\n end\nend\n"
},
{
"path": "lib/torque/postgresql/versioned_commands/command_migration.rb",
"chars": 4465,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module VersionedCommands\n module Migration\n "
},
{
"path": "lib/torque/postgresql/versioned_commands/generator.rb",
"chars": 1766,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/base'\nrequire 'rails/generators/active_record/migration'\n\nmodul"
},
{
"path": "lib/torque/postgresql/versioned_commands/migration_context.rb",
"chars": 3102,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n class IllegalCommandTypeError < ActiveRecord::Migra"
},
{
"path": "lib/torque/postgresql/versioned_commands/migrator.rb",
"chars": 1162,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module VersionedCommands\n module Migrator\n "
},
{
"path": "lib/torque/postgresql/versioned_commands/schema_table.rb",
"chars": 2894,
"preview": "# frozen_string_literal: true\n\nmodule Torque\n module PostgreSQL\n module VersionedCommands\n class SchemaTable\n "
},
{
"path": "lib/torque/postgresql/versioned_commands.rb",
"chars": 6017,
"preview": "# frozen_string_literal: true\n\nrequire_relative 'versioned_commands/command_migration'\nrequire_relative 'versioned_comma"
},
{
"path": "lib/torque/postgresql.rb",
"chars": 1127,
"preview": "require 'i18n'\nrequire 'ostruct'\nrequire 'active_model'\nrequire 'active_record'\nrequire 'active_support'\n\nrequire 'activ"
},
{
"path": "lib/torque-postgresql.rb",
"chars": 28,
"preview": "require 'torque/postgresql'\n"
},
{
"path": "spec/en.yml",
"chars": 399,
"preview": "en:\n torque: 'Torque Rocks!'\n activerecord:\n attributes:\n user:\n role:\n visitor: 'A simple Vis"
},
{
"path": "spec/factories/authors.rb",
"chars": 137,
"preview": "FactoryBot.define do\n factory :author do\n name { Faker::Name.name }\n specialty { Enum::Specialties.values.sa"
},
{
"path": "spec/factories/comments.rb",
"chars": 276,
"preview": "FactoryBot.define do\n factory :comment do\n content { Faker::Lorem.paragraph }\n\n factory :comment_recursive do\n "
},
{
"path": "spec/factories/item.rb",
"chars": 85,
"preview": "FactoryBot.define do\n factory :item do\n name { Faker::Lorem.sentence }\n end\nend\n"
},
{
"path": "spec/factories/posts.rb",
"chars": 127,
"preview": "FactoryBot.define do\n factory :post do\n title { Faker::Lorem.sentence }\n content { Faker::Lorem.paragraph }\n e"
},
{
"path": "spec/factories/tags.rb",
"chars": 84,
"preview": "FactoryBot.define do\n factory :tag do\n name { Faker::Lorem.sentence }\n end\nend\n"
},
{
"path": "spec/factories/texts.rb",
"chars": 88,
"preview": "FactoryBot.define do\n factory :text do\n content { Faker::Lorem.sentence }\n end\nend\n"
},
{
"path": "spec/factories/users.rb",
"chars": 103,
"preview": "FactoryBot.define do\n factory :user do\n name { Faker::Name.name }\n role { 'visitor' }\n end\nend\n"
},
{
"path": "spec/factories/videos.rb",
"chars": 87,
"preview": "FactoryBot.define do\n factory :video do\n title { Faker::Lorem.sentence }\n end\nend\n"
},
{
"path": "spec/fixtures/migrations/20250101000001_create_users.rb",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000002_create_function_count_users_v1.sql",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000003_create_internal_users.rb",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000004_update_function_count_users_v2.sql",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000005_create_view_all_users_v1.sql",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000006_create_type_user_id_v1.sql",
"chars": 0,
"preview": ""
},
{
"path": "spec/fixtures/migrations/20250101000007_remove_function_count_users_v2.sql",
"chars": 0,
"preview": ""
},
{
"path": "spec/initialize.rb",
"chars": 2824,
"preview": "require_relative '../lib/torque/postgresql/auxiliary_statement'\n\nrequire_relative '../lib/torque/postgresql/adapter/sche"
},
{
"path": "spec/mocks/cache_query.rb",
"chars": 843,
"preview": "module Mocks\n module CacheQuery\n def get_last_executed_query(&block)\n cache = ActiveRecord::Base.connection.que"
},
{
"path": "spec/mocks/create_table.rb",
"chars": 406,
"preview": "module Mocks\n module CreateTable\n def mock_create_table\n around do |example|\n original_method = ActiveRe"
},
{
"path": "spec/models/activity.rb",
"chars": 61,
"preview": "class Activity < ActiveRecord::Base\n belongs_to :author\nend\n"
},
{
"path": "spec/models/activity_book.rb",
"chars": 63,
"preview": "require_relative 'activity'\n\nclass ActivityBook < Activity\nend\n"
},
{
"path": "spec/models/activity_post/sample.rb",
"chars": 70,
"preview": "class ActivityPost < Activity\n class Sample < ActivityPost\n end\nend\n"
},
{
"path": "spec/models/activity_post.rb",
"chars": 123,
"preview": "require_relative 'activity'\n\nclass ActivityPost < Activity\n belongs_to :post\nend\n\nrequire_relative 'activity_post/sampl"
},
{
"path": "spec/models/author.rb",
"chars": 100,
"preview": "class Author < ActiveRecord::Base\n has_many :activities, -> { cast_records }\n has_many :posts\nend\n"
},
{
"path": "spec/models/author_journalist.rb",
"chars": 63,
"preview": "require_relative 'author'\n\nclass AuthorJournalist < Author\nend\n"
},
{
"path": "spec/models/category.rb",
"chars": 39,
"preview": "class Category< ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/comment.rb",
"chars": 58,
"preview": "class Comment < ActiveRecord::Base\n belongs_to :user\nend\n"
},
{
"path": "spec/models/course.rb",
"chars": 38,
"preview": "class Course < ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/geometry.rb",
"chars": 40,
"preview": "class Geometry < ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/guest_comment.rb",
"chars": 61,
"preview": "require_relative 'comment'\n\nclass GuestComment < Comment\nend\n"
},
{
"path": "spec/models/internal/user.rb",
"chars": 89,
"preview": "module Internal\n class User < ActiveRecord::Base\n self.schema = 'internal'\n end\nend\n"
},
{
"path": "spec/models/item.rb",
"chars": 60,
"preview": "class Item < ActiveRecord::Base\n belongs_to_many :tags\nend\n"
},
{
"path": "spec/models/post.rb",
"chars": 122,
"preview": "class Post < ActiveRecord::Base\n belongs_to :author\n belongs_to :activity\n\n scope :test_scope, -> { where('1=1') }\nen"
},
{
"path": "spec/models/question.rb",
"chars": 84,
"preview": "class Question < ActiveRecord::Base\n self.implicit_order_column = 'created_at'\nend\n"
},
{
"path": "spec/models/question_select.rb",
"chars": 65,
"preview": "require_relative 'question'\n\nclass QuestionSelect < Question\nend\n"
},
{
"path": "spec/models/tag.rb",
"chars": 35,
"preview": "class Tag < ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/text.rb",
"chars": 36,
"preview": "class Text < ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/time_keeper.rb",
"chars": 42,
"preview": "class TimeKeeper < ActiveRecord::Base\nend\n"
},
{
"path": "spec/models/user.rb",
"chars": 242,
"preview": "class User < ActiveRecord::Base\n has_many :comments\n\n auxiliary_statement :last_comment do |cte|\n cte.query Comment"
},
{
"path": "spec/models/video.rb",
"chars": 37,
"preview": "class Video < ActiveRecord::Base\nend\n"
},
{
"path": "spec/schema.rb",
"chars": 6127,
"preview": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the mig"
},
{
"path": "spec/spec_helper.rb",
"chars": 1678,
"preview": "require 'torque-postgresql'\nrequire 'database_cleaner'\nrequire 'factory_bot'\nrequire 'dotenv'\nrequire 'faker'\nrequire 'r"
},
{
"path": "spec/tests/arel_spec.rb",
"chars": 6392,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Arel' do\n context 'on inflix operation' do\n let(:collector) { ::Arel::Collect"
},
{
"path": "spec/tests/auxiliary_statement_spec.rb",
"chars": 40968,
"preview": "require 'spec_helper'\n\nRSpec.describe 'AuxiliaryStatement' do\n before :each do\n User.auxiliary_statements_list = {}\n"
},
{
"path": "spec/tests/belongs_to_many_spec.rb",
"chars": 17593,
"preview": "require 'spec_helper'\n\nRSpec.describe 'BelongsToMany' do\n context 'on model' do\n let(:model) { Video }\n let(:key)"
},
{
"path": "spec/tests/collector_spec.rb",
"chars": 1376,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Data collector', type: :helper do\n let(:methods_list) { [:foo, :bar] }\n subject"
},
{
"path": "spec/tests/distinct_on_spec.rb",
"chars": 2016,
"preview": "require 'spec_helper'\n\nRSpec.describe 'DistinctOn' do\n\n context 'on relation' do\n subject { Post.unscoped }\n\n it "
},
{
"path": "spec/tests/enum_set_spec.rb",
"chars": 9886,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Enum' do\n let(:connection) { ActiveRecord::Base.connection }\n let(:attribute_kl"
},
{
"path": "spec/tests/enum_spec.rb",
"chars": 18368,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Enum' do\n let(:connection) { ActiveRecord::Base.connection }\n let(:attribute_kl"
},
{
"path": "spec/tests/full_text_seach_test.rb",
"chars": 10391,
"preview": "require 'spec_helper'\n\nRSpec.describe 'FullTextSearch' do\n context 'on builder' do\n let(:builder) { Torque::PostgreS"
},
{
"path": "spec/tests/function_spec.rb",
"chars": 1493,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Function' do\n let(:helper) { Torque::PostgreSQL::FN }\n let(:conn) { ActiveRecor"
},
{
"path": "spec/tests/geometric_builder_spec.rb",
"chars": 7759,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Geometries' do\n context 'on build' do\n let(:klass) do\n klass = Class.new"
},
{
"path": "spec/tests/has_many_spec.rb",
"chars": 16680,
"preview": "require 'spec_helper'\n\nRSpec.describe 'HasMany' do\n context 'on builder' do\n let(:builder) { ActiveRecord::Associati"
},
{
"path": "spec/tests/insert_all_spec.rb",
"chars": 3144,
"preview": "require 'spec_helper'\n\nRSpec.describe 'InsertAll' do\n context 'on executing' do\n before do\n ActiveRecord::Inser"
},
{
"path": "spec/tests/interval_spec.rb",
"chars": 5307,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Interval' do\n let(:table_definition) { ActiveRecord::ConnectionAdapters::Postgre"
},
{
"path": "spec/tests/lazy_spec.rb",
"chars": 663,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Lazy', type: :helper do\n subject { Torque::PostgreSQL::Attributes::Lazy }\n\n it "
},
{
"path": "spec/tests/period_spec.rb",
"chars": 35628,
"preview": "require 'spec_helper'\n\n# TODO: Convert to shared examples\nRSpec.describe 'Period' do\n let(:model) { Class.new(TimeKeepe"
},
{
"path": "spec/tests/predicate_builder_spec.rb",
"chars": 4643,
"preview": "require 'spec_helper'\n\nRSpec.describe 'PredicateBuilder' do\n describe 'on enumerator lazy' do\n let(:timed_out_error)"
},
{
"path": "spec/tests/quoting_spec.rb",
"chars": 705,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Quoting', type: :helper do\n let(:connection) { ActiveRecord::Base.connection }\n\n"
},
{
"path": "spec/tests/relation_spec.rb",
"chars": 10480,
"preview": "require 'spec_helper'\n\nRSpec::Matchers.define :be_attributes_as do |list|\n match do |other|\n other.each_with_index.m"
},
{
"path": "spec/tests/schema_spec.rb",
"chars": 4787,
"preview": "require 'spec_helper'\n\nRSpec.describe 'Schema' do\n let(:connection) { ActiveRecord::Base.connection }\n let(:source) { "
},
{
"path": "spec/tests/table_inheritance_spec.rb",
"chars": 18094,
"preview": "require 'spec_helper'\n\nRSpec.describe 'TableInheritance' do\n let(:connection) { ActiveRecord::Base.connection }\n\n cont"
},
{
"path": "spec/tests/versioned_commands_spec.rb",
"chars": 17761,
"preview": "require 'spec_helper'\n\nRSpec.describe 'VersionedCommands' do\n let(:connection) { ActiveRecord::Base.connection }\n\n con"
},
{
"path": "torque_postgresql.gemspec",
"chars": 1732,
"preview": "$:.push File.expand_path('../lib', __FILE__)\n\n# Maintain your gem's version:\nrequire 'torque/postgresql/version'\nrequire"
}
]
About this extraction
This page contains the full source code of the crashtech/torque-postgresql GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 173 files (520.9 KB), approximately 131.9k tokens, and a symbol index with 1018 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.