Skip to content

Commit

Permalink
Explicitly define allowed template attributes for query sets and quer…
Browse files Browse the repository at this point in the history
…y pages
  • Loading branch information
ellmetha committed Jan 6, 2024
1 parent 79bbd4c commit 1c9f0f2
Show file tree
Hide file tree
Showing 5 changed files with 371 additions and 2 deletions.
149 changes: 149 additions & 0 deletions spec/marten/template/ext/db/query/page_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
require "./spec_helper"

describe Marten::DB::Query::Page do
describe "#resolve_template_attribute" do
it "returns the expected result when requesting the 'all?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)
page = Marten::DB::Query::Page(Tag).new([tag], 2, paginator)

page.resolve_template_attribute("all?").should be_true
end

it "returns the expected result when requesting the 'any?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("any?").should be_true
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("any?").should be_false
end

it "returns the expected result when requesting the 'count' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("count").should eq 1
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("count").should eq 0
end

it "returns the expected result when requesting the 'empty?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("empty?").should be_false
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("empty?").should be_true
end

it "returns the expected result when requesting the 'first?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("first?").should eq tag
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("first?").should be_nil
end

it "returns the expected result when requesting the 'next_page?' attribute" do
tag_1 = Tag.create!(name: "a_tag", is_active: true)
tag_2 = Tag.create!(name: "b_tag", is_active: true)
tag_3 = Tag.create!(name: "c_tag", is_active: true)
tag_4 = Tag.create!(name: "d_tag", is_active: true)
Tag.create!(name: "e_tag", is_active: true)

paginator = Tag.all.order(:name).paginator(2)

page_1 = Marten::DB::Query::Page(Tag).new([tag_1, tag_2], 1, paginator)
page_1.resolve_template_attribute("next_page?").should be_true

page_2 = Marten::DB::Query::Page(Tag).new([tag_3, tag_4], 3, paginator)
page_2.resolve_template_attribute("next_page?").should be_false
end

it "returns the expected result when requesting the 'next_page_number' attribute" do
tag_1 = Tag.create!(name: "a_tag", is_active: true)
tag_2 = Tag.create!(name: "b_tag", is_active: true)
tag_3 = Tag.create!(name: "c_tag", is_active: true)
tag_4 = Tag.create!(name: "d_tag", is_active: true)
Tag.create!(name: "e_tag", is_active: true)

paginator = Tag.all.order(:name).paginator(2)

page_1 = Marten::DB::Query::Page(Tag).new([tag_1, tag_2], 1, paginator)
page_1.resolve_template_attribute("next_page_number").should eq 2

page_2 = Marten::DB::Query::Page(Tag).new([tag_3, tag_4], 3, paginator)
page_2.resolve_template_attribute("next_page_number").should be_nil
end

it "returns the expected result when requesting the 'none?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("none?").should be_false
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("none?").should be_true
end

it "returns the expected result when requesting the 'number' attribute" do
tag_1 = Tag.create!(name: "a_tag", is_active: true)
tag_2 = Tag.create!(name: "b_tag", is_active: true)
tag_3 = Tag.create!(name: "c_tag", is_active: true)
tag_4 = Tag.create!(name: "d_tag", is_active: true)
Tag.create!(name: "e_tag", is_active: true)

paginator = Tag.all.order(:name).paginator(2)

page_1 = Marten::DB::Query::Page(Tag).new([tag_1, tag_2], 1, paginator)
page_1.resolve_template_attribute("number").should eq 1

page_2 = Marten::DB::Query::Page(Tag).new([tag_3, tag_4], 3, paginator)
page_2.resolve_template_attribute("number").should eq 3
end

it "returns the expected result when requesting the 'one?' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("any?").should be_true
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("any?").should be_false
end

it "returns the expected result when requesting the 'previous_page?' attribute" do
tag_1 = Tag.create!(name: "a_tag", is_active: true)
tag_2 = Tag.create!(name: "b_tag", is_active: true)
tag_3 = Tag.create!(name: "c_tag", is_active: true)
tag_4 = Tag.create!(name: "d_tag", is_active: true)
Tag.create!(name: "e_tag", is_active: true)

paginator = Tag.all.order(:name).paginator(2)

page_1 = Marten::DB::Query::Page(Tag).new([tag_1, tag_2], 1, paginator)
page_1.resolve_template_attribute("previous_page?").should be_false

page_2 = Marten::DB::Query::Page(Tag).new([tag_3, tag_4], 3, paginator)
page_2.resolve_template_attribute("previous_page?").should be_true
end

it "returns the expected result when requesting the 'previous_page_number' attribute" do
tag_1 = Tag.create!(name: "a_tag", is_active: true)
tag_2 = Tag.create!(name: "b_tag", is_active: true)
tag_3 = Tag.create!(name: "c_tag", is_active: true)
tag_4 = Tag.create!(name: "d_tag", is_active: true)
Tag.create!(name: "e_tag", is_active: true)

paginator = Tag.all.order(:name).paginator(2)

page_1 = Marten::DB::Query::Page(Tag).new([tag_1, tag_2], 1, paginator)
page_1.resolve_template_attribute("previous_page_number").should be_nil

page_2 = Marten::DB::Query::Page(Tag).new([tag_3, tag_4], 3, paginator)
page_2.resolve_template_attribute("previous_page_number").should eq 2
end

it "returns the expected result when requesting the 'size' attribute" do
tag = Tag.create!(name: "a_tag", is_active: true)
paginator = Tag.all.order(:name).paginator(2)

Marten::DB::Query::Page(Tag).new([tag], 2, paginator).resolve_template_attribute("size").should eq 1
Marten::DB::Query::Page(Tag).new([] of Tag, 2, paginator).resolve_template_attribute("size").should eq 0
end
end
end
149 changes: 149 additions & 0 deletions spec/marten/template/ext/db/query/set_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
require "./spec_helper"

describe Marten::DB::Query::Set do
describe "#resolve_template_attribute" do
it "returns the expected result when requesting the 'all' attribute" do
tag_1 = Tag.create!(name: "tag_1", is_active: true)
tag_2 = Tag.create!(name: "tag_2", is_active: true)

result = Tag.all.resolve_template_attribute("all")
result.should be_a Marten::DB::Query::Set(Tag)
result = result.as(Marten::DB::Query::Set(Tag))
result.to_set.should eq([tag_1, tag_2].to_set)
end

it "returns the expected result when requesting the 'all?' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("all?").should be_true
end

it "returns the expected result when requesting the 'any?' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("any?").should be_true
Tag.filter(name: "unknown").resolve_template_attribute("any?").should be_false
end

it "returns the expected result when requesting the 'count' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("count").should eq 2
Tag.filter(name: "unknown").resolve_template_attribute("count").should eq 0
end

it "returns the expected result when requesting the 'distinct' attribute" do
user_1 = TestUser.create!(username: "jd1", email: "[email protected]", first_name: "John", last_name: "Doe")
user_2 = TestUser.create!(username: "jd2", email: "[email protected]", first_name: "John", last_name: "Doe")

Post.create!(author: user_1, title: "Post 1", published: true)
Post.create!(author: user_1, title: "Post 2", published: true)
Post.create!(author: user_2, title: "Post 3", published: true)
Post.create!(author: user_1, title: "Post 4", published: false)

result = TestUser.filter(posts__published: true).resolve_template_attribute("distinct")
result.should be_a Marten::DB::Query::Set(TestUser)
result = result.as(Marten::DB::Query::Set(TestUser))
result.to_set.should eq [user_1, user_2].to_set
end

it "returns the expected result when requesting the 'empty?' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("empty?").should be_false
Tag.filter(name: "unknown").resolve_template_attribute("empty?").should be_true
end

it "returns the expected result when requesting the 'exists?' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("exists?").should be_true
Tag.filter(name: "unknown").resolve_template_attribute("exists?").should be_false
end

it "returns the expected result when requesting the 'first' attribute" do
tag_1 = Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.order(:id).resolve_template_attribute("first").should eq tag_1
Tag.filter(name: "unknown").resolve_template_attribute("first").should be_nil
end

it "returns the expected result when requesting the 'first!' attribute" do
tag_1 = Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.order(:id).resolve_template_attribute("first!").should eq tag_1
end

it "returns the expected result when requesting the 'first?' attribute" do
tag_1 = Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.order(:id).resolve_template_attribute("first?").should eq tag_1
Tag.filter(name: "unknown").resolve_template_attribute("first?").should be_nil
end

it "returns the expected result when requesting the 'last' attribute" do
Tag.create!(name: "tag_1", is_active: true)
tag_2 = Tag.create!(name: "tag_2", is_active: true)

Tag.all.order(:id).resolve_template_attribute("last").should eq tag_2
Tag.filter(name: "unknown").resolve_template_attribute("last").should be_nil
end

it "returns the expected result when requesting the 'last!' attribute" do
Tag.create!(name: "tag_1", is_active: true)
tag_2 = Tag.create!(name: "tag_2", is_active: true)

Tag.all.order(:id).resolve_template_attribute("last!").should eq tag_2
end

it "returns the expected result when requesting the 'none' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

result = Tag.all.resolve_template_attribute("none")
result.should be_a Marten::DB::Query::Set(Tag)
result = result.as(Marten::DB::Query::Set(Tag))
result.exists?.should be_false
end

it "returns the expected result when requesting the 'none?' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("none?").should be_false
Tag.filter(name: "unknown").resolve_template_attribute("none?").should be_true
end

it "returns the expected result when requesting the 'one?' attribute" do
Tag.create!(name: "tag_1", is_active: true)

Tag.all.resolve_template_attribute("one?").should be_true
Tag.filter(name: "unknown").resolve_template_attribute("one?").should be_false
end

it "returns the expected result when requesting the 'reverse' attribute" do
tag_1 = Tag.create!(name: "tag_1", is_active: true)
tag_2 = Tag.create!(name: "tag_2", is_active: true)

result = Tag.all.order(:id).resolve_template_attribute("reverse")
result.should be_a Marten::DB::Query::Set(Tag)
result = result.as(Marten::DB::Query::Set(Tag))
result.to_a.should eq [tag_2, tag_1]
end

it "returns the expected result when requesting the 'size' attribute" do
Tag.create!(name: "tag_1", is_active: true)
Tag.create!(name: "tag_2", is_active: true)

Tag.all.resolve_template_attribute("size").should eq 2
end
end
end
1 change: 1 addition & 0 deletions spec/marten/template/ext/db/query/spec_helper.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "../spec_helper"
33 changes: 32 additions & 1 deletion src/marten/template/ext/db/query/page.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
class Marten::DB::Query::Page(M)
include Marten::Template::Object::Auto
include Marten::Template::Object

def resolve_template_attribute(key : String)
case key
when "all?"
all?
when "any?"
any?
when "count"
count
when "empty?"
empty?
when "first?"
first?
when "next_page?"
next_page?
when "next_page_number"
next_page_number
when "none?"
none?
when "number"
number
when "one?"
one?
when "previous_page?"
previous_page?
when "previous_page_number"
previous_page_number
when "size"
size
end
end
end
41 changes: 40 additions & 1 deletion src/marten/template/ext/db/query/set.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
class Marten::DB::Query::Set(M)
include Marten::Template::Object::Auto
include Marten::Template::Object

def resolve_template_attribute(key : String)
case key
when "all"
all
when "all?"
all?
when "any?"
any?
when "count"
count
when "distinct"
distinct
when "empty?"
empty?
when "exists?"
exists?
when "first"
first
when "first!"
first!
when "first?"
first?
when "last"
last
when "last!"
last!
when "none"
none
when "none?"
none?
when "one?"
one?
when "reverse"
reverse
when "size"
size
end
end
end

0 comments on commit 1c9f0f2

Please sign in to comment.