Skip to content

Commit

Permalink
with dumper and loader
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkasyanchuk committed Feb 10, 2022
1 parent 2f02384 commit 6f1f5cb
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 57 deletions.
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ gemspec
gem "pg"
gem "pry"
gem "wrapped_print"
gem "scenic"

# Start debugger with binding.b [https://github.com/ruby/debug]
# gem "debug", ">= 1.0.0"
1 change: 0 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ PATH
specs:
sql_view (0.1.0)
rails
scenic

GEM
remote: https://rubygems.org/
Expand Down
20 changes: 8 additions & 12 deletions lib/generators/sql_view/view/USAGE
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
Description:
Create a new database view for your application. This will create a new
view definition file and the accompanying migration.

If a view of the given name already exists, create a new version of the view
and a migration to replace the old version with the new.
Create a new database view in your application.

To create a materialized view, pass the '--materialized' option.
To create a materialized view with NO DATA, pass '--no-data' option.

Examples:
rails generate scenic:view searches
rails generate sql_view:view ActiveUser 'User.where(active: true)'

create: db/views/searches_v01.sql
create: db/migrate/20140803191158_create_searches.rb
create: app/sql_views/search_view.rb
create: db/migrate/20140803191158_create_active_users_views.rb

rails generate scenic:view searches
Examples:
rails generate sql_view:view ArchivedAccount Account.archived --materialized --view-name=inactive_accounts

create: db/views/searches_v02.sql
create: db/migrate/20140804191158_update_searches_to_version_2.rb
create: app/sql_views/search_view.rb
create: db/migrate/20140803191158_create_search_views.rb

This file was deleted.

83 changes: 48 additions & 35 deletions lib/generators/sql_view/view/view_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,67 @@

module SqlView
module Generators
# @api private
class ViewGenerator < Rails::Generators::NamedBase
include Rails::Generators::Migration
source_root File.expand_path("templates", __dir__)

def create_views_directory
unless views_directory_path.exist?
empty_directory(views_directory_path)
end
end
class_option :"view-name", type: :string, default: nil
class_option :materialized, type: :boolean, default: false

def create_view_definition
create_file definition.path
end
def create_everything
create_file "app/sql_views/#{file_name}_view.rb", <<-FILE
class #{class_name}View < SqlView::Model
#{top_code}
schema -> {#{schema_code} }
extend_model_with do
# sample how you can extend it, similar to regular AR model
#
# belongs_to :user
# has_many :posts
#
# scope :ordered, -> { order(:created_at) }
# scope :by_role, ->(role) { where(role: role) }
end
end
FILE

def create_migration_file
migration_template(
"db/migrate/create_view.erb",
"db/migrate/create_#{plural_file_name}.rb",
)
create_file "db/migrate/#{self.class.next_migration_number("db/migrate")}_create_#{file_name}s_view.rb", <<-FILE
class #{migration_class_name} < #{activerecord_migration_class}
def up
#{class_name}View.sql_view.up
end
def down
#{class_name}View.sql_view.down
end
end
FILE
end

def self.next_migration_number(dir)
::ActiveRecord::Generators::Base.next_migration_number(dir)
end

no_tasks do
def top_code
[view_name_code, materialized_code].compact.join("\n\n")
end

def view_name_code
options["view-name"] ? " self.view_name = '#{options["view-name"]}'" : nil
end

def materialized_code
options[:materialized] ? " materialized" : nil
end

def schema_code
" #{args[0].presence || "\n # ActiveRecord::Relation or SQL\n # for example: User.where(active: true)\n " }"
end

def migration_class_name
"Create#{class_name.tr('.', '').pluralize}"
"Create#{class_name.tr('.', '').pluralize}View"
end

def activerecord_migration_class
Expand All @@ -51,25 +83,6 @@ def file_name
super.tr(".", "_")
end

def views_directory_path
@views_directory_path ||= Rails.root.join("db", "views")
end

def formatted_plural_name
if plural_name.include?(".")
"\"#{plural_name}\""
else
":#{plural_name}"
end
end

def create_view_options
if materialized?
", materialized: #{no_data? ? '{ no_data: true }' : true}"
else
""
end
end
end
end
end
14 changes: 12 additions & 2 deletions lib/sql_view.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
require 'singleton'
require "singleton"
require_relative "./sql_view/schema_dumper.rb"
require_relative "./sql_view/statements.rb"
require "sql_view/version"
require "sql_view/railtie"

module SqlView
# mattr_accessor :klasses
# @@klasses = {}

class Model
class_attribute :view, :sql_view_options

class << self
delegate_missing_to :model
end

def self.inherited(subclass)
# puts subclass
subclass.sql_view_options = {}
# SqlView.klasses[subclass] = subclass.sql_view
end

def self.view_name=(name)
Expand Down Expand Up @@ -39,7 +50,6 @@ def self.extend_model_with(&block)
end
end


class Migration
attr_reader :parent

Expand Down
6 changes: 6 additions & 0 deletions lib/sql_view/railtie.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
module SqlView
class Railtie < ::Rails::Railtie
initializer "sql_view.load" do
ActiveSupport.on_load :active_record do
ActiveRecord::ConnectionAdapters::AbstractAdapter.include SqlView::Statements
ActiveRecord::SchemaDumper.prepend SqlView::SchemaDumper
end
end
end
end
94 changes: 94 additions & 0 deletions lib/sql_view/schema_dumper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
require "rails"

# Copy-pasted from scenic game. Scenic is a very nice gem

module SqlView
# @api private
module SchemaDumper
class DBView < OpenStruct

def materialized?
self.kind == "m"
end

def materialized_or_not
materialized? ? " MATERIALIZED " : nil
end

def to_schema
<<-DEFINITION
create_sql_view "#{self.viewname}", sql: <<-\SQL
CREATE #{materialized_or_not} VIEW "#{self.viewname}" AS
#{escaped_definition.indent(2)}
SQL
DEFINITION
end

def escaped_definition
definition.gsub("\\", "\\\\\\")
end
end

def tables(stream)
super
views(stream)
end

def views(stream)
if dumpable_views_in_database.any?
stream.puts
end

dumpable_views_in_database.each do |viewname|
view = DBView.new(get_view_info(viewname))
#puts view.to_schema
stream.puts(view.to_schema)
#indexes(view.name, stream)
end
end

private

def dumpable_views_in_database
@dumpable_views_in_database ||= ActiveRecord::Base.connection.views.reject do |viewname|
ignored?(viewname)
end
end

def get_view_info(viewname)
views_schema.detect{|e| e['viewname'] == viewname}
end

def views_schema
@views_schema ||= ActiveRecord::Base.connection.execute(<<-SQL)
SELECT
c.relname as viewname,
pg_get_viewdef(c.oid) AS definition,
c.relkind AS kind,
n.nspname AS namespace
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE
c.relkind IN ('m', 'v')
AND c.relname NOT IN (SELECT extname FROM pg_extension)
AND n.nspname = ANY (current_schemas(false))
ORDER BY c.oid
SQL
.to_a
end

unless ActiveRecord::SchemaDumper.private_instance_methods(false).include?(:ignored?)
# This method will be present in Rails 4.2.0 and can be removed then.
def ignored?(table_name)
["schema_migrations", ignore_tables].flatten.any? do |ignored|
case ignored
when String then remove_prefix_and_suffix(table_name) == ignored
when Regexp then remove_prefix_and_suffix(table_name) =~ ignored
else
raise StandardError, "ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values."
end
end
end
end
end
end
7 changes: 7 additions & 0 deletions lib/sql_view/statements.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module SqlView
module Statements
def create_sql_view(viewname, sql:)
ActiveRecord::Base.connection.execute(sql)
end
end
end
1 change: 0 additions & 1 deletion sql_view.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Gem::Specification.new do |spec|
end

spec.add_dependency "rails"
spec.add_dependency "scenic"

spec.add_development_dependency "pg"
spec.add_development_dependency "pry"
Expand Down

0 comments on commit 6f1f5cb

Please sign in to comment.