Skip to content

Commit

Permalink
Merge pull request #4 from igorkasyanchuk/better_rails_integration
Browse files Browse the repository at this point in the history
now you can use in your models
  • Loading branch information
igorkasyanchuk authored Jun 18, 2023
2 parents 43ee2ab + b873cf6 commit 2b8d517
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 22 deletions.
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
sql_view (0.0.5)
sql_view (0.0.6)
rails

GEM
Expand Down Expand Up @@ -95,7 +95,7 @@ GEM
mini_mime (1.1.2)
mini_portile2 (2.8.2)
minitest (5.15.0)
net-imap (0.3.4)
net-imap (0.3.6)
date
net-protocol
net-pop (0.1.2)
Expand All @@ -114,7 +114,7 @@ GEM
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
racc (1.6.2)
racc (1.7.1)
rack (2.2.7)
rack-test (2.1.0)
rack (>= 1.3)
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ ActiveUserView.model.includes(:profile)

If you need to refresh materialized view - `ActiveUserView.sql_view.refresh` (if you need to do it concerrently - `.refresh(concurrently: false)`.

It can also be used with your other models:

```ruby
class Account < ApplicationRecord
has_many :users

has_one :account_stat_view, class_name: AccountStatViewView.model.to_s, foreign_key: :account_id
has_many :active_users, join_table: :active_users_views, class_name: ActiveUserView.model.to_s, foreign_key: :account_id
end
```


More examples in this file: `./test/sql_view_test.rb`

## Installation
Expand Down
12 changes: 7 additions & 5 deletions lib/sql_view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def refresh(concurrently: false)
sql = <<-SQL
REFRESH#{materialized_or_not}VIEW#{concurrently_or_not}#{parent.view_name};
SQL
execute(sql)
execute(sql, log: false)
end

def up
Expand All @@ -88,8 +88,8 @@ def down
execute(sql)
end

def execute(sql)
SqlView.log sql
def execute(sql, log: true)
SqlView.log(sql) if log
ActiveRecord::Base.connection.execute sql#.wp
end

Expand All @@ -103,6 +103,7 @@ def materialized_or_not

class ClassBuilder
def ClassBuilder.create_model(parent)
class_name = "#{parent}Model"
klass = Class.new(ActiveRecord::Base) do
def self.model_name
ActiveModel::Name.new(self, nil, parent.view_name)
Expand All @@ -120,10 +121,11 @@ def readonly?
# because of the error undefined scan for nil class
klass.class_eval %Q{
def self.name
"#{parent.class}"
"#{class_name}"
end
}
klass
Object.const_set(class_name, klass) unless const_defined?(class_name)
Object.const_get(class_name)
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/sql_view/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module SqlView
VERSION = "0.0.5"
VERSION = "0.0.6"
end
4 changes: 4 additions & 0 deletions test/dummy/app/models/account.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
class Account < ApplicationRecord
has_many :users

has_one :account_stat_view, class_name: AccountStatViewView.model.to_s, foreign_key: :account_id
has_many :active_users, join_table: :active_users_views, class_name: ActiveUserView.model.to_s, foreign_key: :account_id
end
1 change: 1 addition & 0 deletions test/dummy/app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
class User < ApplicationRecord
belongs_to :account, optional: true
end
18 changes: 18 additions & 0 deletions test/dummy/app/sql_views/account_stat_view_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class AccountStatViewView < SQLView::Model

schema -> {
"SELECT accounts.id as account_id, RANDOM() as factor from accounts"
}

extend_model_with do
# sample how you can extend it, similar to regular AR model
#
# include SomeConcern
#
# belongs_to :user
# has_many :posts
#
# scope :ordered, -> { order(:created_at) }
# scope :by_role, ->(role) { where(role: role) }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddAccountIdToUser < ActiveRecord::Migration[7.0]
def change
add_column :users, :account_id, :integer
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class CreateAccountStatViewView < ActiveRecord::Migration[7.0]
def up
AccountStatViewView.sql_view.up
end

def down
AccountStatViewView.sql_view.down
end
end
6 changes: 6 additions & 0 deletions test/dummy/db/migrate/20230618104439_refresh_active_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class RefreshActiveUsers < ActiveRecord::Migration[7.0]
def change
ActiveUserView.sql_view.down
ActiveUserView.sql_view.up
end
end
35 changes: 22 additions & 13 deletions test/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2023_06_07_072750) do
ActiveRecord::Schema.define(version: 2023_06_18_104439) do

# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
Expand All @@ -36,6 +36,7 @@
t.integer "age"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "account_id"
end

create_table "workers", force: :cascade do |t|
Expand All @@ -47,17 +48,6 @@
end


create_sql_view "active_account_views", sql: <<-SQL
CREATE VIEW "active_account_views" AS
SELECT accounts.id,
accounts.name,
accounts.active,
accounts.created_at,
accounts.updated_at
FROM accounts
WHERE (accounts.active = true);
SQL

create_sql_view "deleted_account_views", sql: <<-SQL
CREATE MATERIALIZED VIEW "deleted_account_views" AS
SELECT accounts.id,
Expand Down Expand Up @@ -102,14 +92,33 @@
FROM workers;
SQL

create_sql_view "account_stat_view_views", sql: <<-SQL
CREATE VIEW "account_stat_view_views" AS
SELECT accounts.id AS account_id,
random() AS factor
FROM accounts;
SQL

create_sql_view "active_account_views", sql: <<-SQL
CREATE VIEW "active_account_views" AS
SELECT accounts.id,
accounts.name,
accounts.active,
accounts.created_at,
accounts.updated_at
FROM accounts
WHERE (accounts.active = true);
SQL

create_sql_view "active_user_views", sql: <<-SQL
CREATE MATERIALIZED VIEW "active_user_views" AS
SELECT users.id,
users.name,
users.country,
users.age,
users.created_at,
users.updated_at
users.updated_at,
users.account_id
FROM users
WHERE ((users.age >= 18) AND (users.age <= 60));
SQL
Expand Down
19 changes: 19 additions & 0 deletions test/sql_view_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,25 @@ class SqlViewTest < ActiveSupport::TestCase
assert anna, ActiveWorkerView.model.first.jobable
end

test 'association 1' do
account = Account.create
user = User.create(account: account)
assert account.account_stat_view.present?
end

test 'association 2' do
account = Account.create
user = User.create(account: account)
assert_equal account, Account.joins(:account_stat_view).where(id: account.id).first
assert_equal account, Account.joins(:account_stat_view).where(id: account.id).where("account_stat_view_views.factor > 0").first
assert_equal 0, account.active_users.count
end

test 'association 3' do
account = Account.create
assert_equal "ActiveUserViewModel", account.active_users.build.class.to_s
end

# test 'migration' do
# a = User.create(age: 20)
# a = User.create(age: 30)
Expand Down

0 comments on commit 2b8d517

Please sign in to comment.