Skip to content

Commit

Permalink
Add materialized view support helpers. Fixes #842 (#1004)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwoertink authored Mar 9, 2024
1 parent 0366d79 commit 68cc0c6
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
22 changes: 22 additions & 0 deletions db/migrations/20240210233828_create_materialized_view_names.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class CreateMaterializedViewNames::V20240210233828 < Avram::Migrator::Migration::V1
def migrate
execute <<-SQL
CREATE MATERIALIZED VIEW IF NOT EXISTS all_the_names AS
SELECT name FROM admins
UNION ALL
SELECT name FROM businesses
UNION ALL
SELECT name FROM customers
UNION ALL
SELECT name FROM employees
UNION ALL
SELECT name FROM users
SQL
end

def rollback
execute <<-SQL
DROP MATERIALIZED VIEW IF EXISTS all_the_names
SQL
end
end
12 changes: 12 additions & 0 deletions spec/avram/view_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,16 @@ describe "views" do
AdminUser.ensure_correct_column_mappings!
NicknameInfo.ensure_correct_column_mappings!
end

describe "materialized views" do
it "works" do
UserFactory.create(&.name("Yoozur"))
AdminFactory.create(&.name("Aadmyn"))
emp = EmployeeFactory.create(&.name("Hemploie"))
CustomerFactory.create(&.name("Kustoomur").employee_id(emp.id))
Name::BaseQuery.new.select_count.should eq(0)
Name::BaseQuery.refresh_view
Name::BaseQuery.new.select_count.should eq(4)
end
end
end
5 changes: 5 additions & 0 deletions spec/support/models/name.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Name < BaseModel
view :all_the_names, materialized: true do
column name : String
end
end
6 changes: 6 additions & 0 deletions src/avram/base_query_template.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class Avram::BaseQueryTemplate
end
end

{% if named_args[:materialized_view] %}
def self.refresh_view(*, concurrent : Bool = false)
{{ type }}.database.exec("REFRESH MATERIALIZED VIEW #{concurrent ? "CONCURRENTLY" : ""} #{{{ type }}.table_name}")
end
{% end %}

def update(
{% for column in columns %}
{{ column[:name] }} : {{ column[:type] }} | Avram::Nothing{% if column[:nilable] %} | Nil{% end %} = Avram::Nothing.new,
Expand Down
9 changes: 5 additions & 4 deletions src/avram/model.cr
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ abstract class Avram::Model
setup(Avram::SchemaEnforcer.setup)
end

macro view(view_name = nil)
macro view(view_name = nil, materialized = false)
{{ yield }}

validate_columns("view")
Expand All @@ -85,7 +85,7 @@ abstract class Avram::Model
setup(Avram::Model.setup_column_info_methods)
setup(Avram::Model.setup_association_queries)
setup(Avram::Model.setup_view_schema_enforcer_validations)
setup(Avram::BaseQueryTemplate.setup)
setup(Avram::BaseQueryTemplate.setup, materialized_view: {{ materialized }})
setup(Avram::SchemaEnforcer.setup)
end

Expand Down Expand Up @@ -141,11 +141,12 @@ abstract class Avram::Model
column updated_at : Time, autogenerated: true
end

macro setup(step)
macro setup(step, *args, **named_args)
{{ step.id }}(
type: {{ @type }},
columns: {{ COLUMNS }},
associations: {{ ASSOCIATIONS }}
associations: {{ ASSOCIATIONS }},
{{ named_args.double_splat }}
)
end

Expand Down

0 comments on commit 68cc0c6

Please sign in to comment.