Skip to content

Commit

Permalink
Update spec tests and add ghaction (#474)
Browse files Browse the repository at this point in the history
* Add a check to ensure created_at and updated_at are Time

If a column is named `created_at` or `updated_at` is not a type `Time?`, then the following occurs:

```There was a problem expanding macro 'macro_4801706624'

Code in lib/granite/src/granite/transactions.cr:82:5

 82 | {% if @type.instance_vars.select { |ivar| ivar.annotation(Granite::Column) }.map(&.name.stringify).includes? "created_at" %}
      ^
Called macro defined in lib/granite/src/granite/transactions.cr:82:5

 82 | {% if @type.instance_vars.select { |ivar| ivar.annotation(Granite::Column) }.map(&.name.stringify).includes? "created_at" %}

Which expanded to:

 > 1 |
 > 2 |       if mode == :create
 > 3 |         @created_at = time.at_beginning_of_second
                                  ^---------------------
```

this simply adds a type check.

* fix allowing enum columns

* ameba fixes

* fix build_find_by_clause for bool values

* minor update

* Fix issue where primary key can be pushed twice on create

* fix infinate recusion when searching with enum

* add retry to adapter base

* add retry to adapters

* minor update

* add support for querying with Array(UUID)

* format docs

* FIX: add converter to read_attribute

* Fix for type declaration in has_one

* Fix callback runs on #import

* more has_one fixes; fixes for through associations

* small formatting fixes

* fix passing primary_key to has_one

* Add to docs (#446)

* Quote fields in PG query assembler

* Created converter for PG Enums that are returned as bytes

* Quote table names in adapter methods only if not already quoted

* Check if table/column string has already been quoted

* Quote foreign key

* Quote fields in query assemblers

* added some docs

* Created converter for Postgres enum arrays

* Incorrect variable name

* Added target key to association collection for many relations type

* Added truncate function for postgres adapter

* Removed unrequired parameter

* Rogue value in log for truncate

* Added truncate method for models

* Add JsonString converter

* Must use chars to check string index equality

* add note for custom select macro

* removed some other commits

* removed changes from other pr

* removed work from other pr

* removed work from other pr

* removed commits from other pr

---------

Co-authored-by: ionica21 <[email protected]>

* add support for foreign key converters (#438)

Co-authored-by: Joakim Repomaa <[email protected]>

* fix build_find_by_clause for bool values (#455)

* Add context to RecordNotSaved/RecordNotDestroyed error messages (#452)

* Add a check to ensure created_at and updated_at are Time (#454)

If a column is named `created_at` or `updated_at` is not a type `Time?`, then the following occurs:

```There was a problem expanding macro 'macro_4801706624'

Code in lib/granite/src/granite/transactions.cr:82:5

 82 | {% if @type.instance_vars.select { |ivar| ivar.annotation(Granite::Column) }.map(&.name.stringify).includes? "created_at" %}
      ^
Called macro defined in lib/granite/src/granite/transactions.cr:82:5

 82 | {% if @type.instance_vars.select { |ivar| ivar.annotation(Granite::Column) }.map(&.name.stringify).includes? "created_at" %}

Which expanded to:

 > 1 |
 > 2 |       if mode == :create
 > 3 |         @created_at = time.at_beginning_of_second
                                  ^---------------------
```

this simply adds a type check.

* small formatting fixes

* fix passing primary_key to has_one

* fix spec: Granite no longer escapes strings, but passes them to the underlying adapter

* Fix yaml spec to ignore whitespaces

* working mysql spec tests

* spec updates

* add github workflows (#1)

* update docker to use crystal 1.8 and added github action
* fix workflow if statements
* split workflow into separate jobs for each database
* workflow: fix missing envs
* workflow: add psql db var
* attempt to use workflow services
* split tests by database to speed things up

* fix sql test

* comment out workflow schedule

* re-enable ameba

---------

Co-authored-by: Seth T <[email protected]>
Co-authored-by: Richard Howell-Peak <[email protected]>
Co-authored-by: ionica21 <[email protected]>
Co-authored-by: Joakim Repomaa <[email protected]>
Co-authored-by: Joakim Repomaa <[email protected]>
Co-authored-by: Aurélien Delogu <[email protected]>
  • Loading branch information
7 people authored May 3, 2023
1 parent 5c37572 commit 5afa787
Show file tree
Hide file tree
Showing 22 changed files with 213 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PG_DATABASE_URL=postgres://granite:password@localhost:5432/granite_db
MYSQL_DATABASE_URL=mysql://granite:password@localhost:3306/granite_db
SQLITE_DATABASE_URL=sqlite3:./granite.db
CURRENT_ADAPTER=pg
PG_VERSION=10.4
PG_VERSION=15.2
MYSQL_VERSION=5.7
SQLITE_VERSION=3110000
SQLITE_VERSION_YEAR=2016
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dotenv_if_exists
121 changes: 121 additions & 0 deletions .github/workflows/spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: spec
on:
push:
pull_request:
branches: [main, master]
# schedule:
# - cron: "0 6 * * 6" # Every Saturday 6 AM
jobs:
formatting:
runs-on: ubuntu-latest
steps:
- name: Download source
uses: actions/checkout@v2
- name: Install Crystal
uses: oprypin/[email protected]
with:
crystal: latest
- name: Check formatting
run: crystal tool format --check
sqlite-spec:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1
matrix:
crystal: [1.6.2, 1.7.2, 1.8.1, latest]
steps:
- name: Download source
uses: actions/checkout@v2
- name: Install Crystal
uses: oprypin/[email protected]
with:
crystal: ${{ matrix.crystal }}
- name: Install shards
run: shards update --ignore-crystal-version
- name: Run tests
timeout-minutes: 2
run: crystal spec
env:
CURRENT_ADAPTER: sqlite
SQLITE_DATABASE_URL: sqlite3:./granite.db
MYSQL_DATABASE_URL: mysql://granite:password@localhost:3306/granite_db
PG_DATABASE_URL: postgres://granite:password@localhost:5432/granite_db
mysql-spec:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1
matrix:
crystal: [1.6.2, 1.7.2, 1.8.1, latest]
services:
mysql:
image: mysql:5.7
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: granite_db
MYSQL_USER: granite
MYSQL_PASSWORD: password
ports:
- 3306:3306
steps:
- name: Download source
uses: actions/checkout@v2
- name: Install Crystal
uses: oprypin/[email protected]
with:
crystal: ${{ matrix.crystal }}
- name: Install shards
run: shards update --ignore-crystal-version
- name: Run tests
timeout-minutes: 2
run: crystal spec
env:
CURRENT_ADAPTER: mysql
SQLITE_DATABASE_URL: sqlite3:./granite.db
MYSQL_DATABASE_URL: mysql://granite:password@localhost:3306/granite_db
PG_DATABASE_URL: postgres://granite:password@localhost:5432/granite_db
psql-spec:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 1
matrix:
crystal: [1.6.2, 1.7.2, 1.8.1, latest]
services:
postgres:
image: postgres:15.2
env:
POSTGRES_USER: granite
POSTGRES_PASSWORD: password
POSTGRES_DB: granite_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- name: Download source
uses: actions/checkout@v2
- name: Install Crystal
uses: oprypin/[email protected]
with:
crystal: ${{ matrix.crystal }}
- name: Install shards
run: shards update --ignore-crystal-version
- name: Run tests
timeout-minutes: 2
run: crystal spec
env:
CURRENT_ADAPTER: pg
SQLITE_DATABASE_URL: sqlite3:./granite.db
MYSQL_DATABASE_URL: mysql://granite:password@localhost:3306/granite_db
PG_DATABASE_URL: postgres://granite:password@localhost:5432/granite_db
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM crystallang/crystal:1.6.0
FROM crystallang/crystal:1.8.0

ARG sqlite_version=3110000
ARG sqlite_version_year=2016
Expand Down
3 changes: 0 additions & 3 deletions shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ development_dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.14.0

sqlite3:
github: crystal-lang/crystal-sqlite3
version: ~> 0.19.0

pg:
github: will/crystal-pg
version: ~> 0.26.0

ameba:
github: crystal-ameba/ameba
version: ~> 1.3.1
12 changes: 9 additions & 3 deletions spec/granite/associations/has_one_spec.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
require "../../spec_helper"

describe "has_one" do
before_each do
User.clear
Profile.clear
Courier.clear
Character.clear
end

it "provides a setter to set childrens's foriegn_key from parent" do
profile = Profile.new
profile.name = "Test Profile"
Expand Down Expand Up @@ -34,9 +41,8 @@ describe "has_one" do
it "provides a method to retrieve associated object that will raise if record is not found" do
user = User.new
user.email = "[email protected]"
user.save

expect_raises Granite::Querying::NotFound, "No Profile found where user_id = 3" { user.profile! }
user.save!
expect_raises Granite::Querying::NotFound, "No Profile found where user_id = #{user.id}" { user.profile! }
end

it "provides the ability to use a custom primary key" do
Expand Down
4 changes: 4 additions & 0 deletions spec/granite/callbacks/abort_spec.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require "../../spec_helper"

describe "#abort!" do
before_each do
CallbackWithAbort.clear
end

context "when create" do
it "doesn't run other callbacks if abort at before_save" do
cwa = CallbackWithAbort.new(abort_at: "before_save", do_abort: true)
Expand Down
4 changes: 2 additions & 2 deletions spec/granite/query/assemblers/mysql_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ require "../spec_helper"
end

it "property defines IN query" do
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN ('outstanding','in_progress') ORDER BY id DESC"
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN (?,?) ORDER BY id DESC"
query = builder.where(date_completed: nil, status: ["outstanding", "in_progress"])
query.raw_sql.should match ignore_whitespace sql

assembler = query.assembler
assembler.where
assembler.numbered_parameters.should eq [] of Granite::Columns::Type
assembler.numbered_parameters.should eq ["outstanding", "in_progress"]
end

it "property defines IN query with numbers" do
Expand Down
4 changes: 2 additions & 2 deletions spec/granite/query/assemblers/pg_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ require "../spec_helper"
end

it "property defines IN query" do
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN ('outstanding','in_progress') ORDER BY id DESC"
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN ($1,$2) ORDER BY id DESC"
query = builder.where(date_completed: nil, status: ["outstanding", "in_progress"])
query.raw_sql.should match ignore_whitespace sql

assembler = query.assembler
assembler.where
assembler.numbered_parameters.should eq [] of Granite::Columns::Type
assembler.numbered_parameters.should eq ["outstanding", "in_progress"]
end

it "property defines IN query with numbers" do
Expand Down
4 changes: 2 additions & 2 deletions spec/granite/query/assemblers/sqlite_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ require "../spec_helper"
end

it "property defines IN query" do
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN ('outstanding','in_progress') ORDER BY id DESC"
sql = "SELECT #{query_fields} FROM table WHERE date_completed IS NULL AND status IN (?,?) ORDER BY id DESC"
query = builder.where(date_completed: nil, status: ["outstanding", "in_progress"])
query.raw_sql.should match ignore_whitespace sql

assembler = query.assembler
assembler.where
assembler.numbered_parameters.should eq [] of Granite::Columns::Type
assembler.numbered_parameters.should eq ["outstanding", "in_progress"]
end

it "property defines IN query with numbers" do
Expand Down
2 changes: 1 addition & 1 deletion spec/granite/query/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def builder
end

def ignore_whitespace(expected : String)
whitespace = "\\s+"
whitespace = "\\s+?"
compiled = expected.split(/\s/).map { |s| Regex.escape s }.join(whitespace)
Regex.new "^\\s*#{compiled}\\s*$", Regex::Options::IGNORE_CASE ^ Regex::Options::MULTILINE
end
4 changes: 4 additions & 0 deletions spec/granite/querying/exists_spec.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require "../../spec_helper"

describe ".exists?" do
before_each do
Parent.clear
end

describe "when there is a record with that ID" do
describe "with a numeric PK" do
it "should return true" do
Expand Down
10 changes: 5 additions & 5 deletions spec/granite/querying/from_rs_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ macro build_review_emitter
[
8_i64,
"name",
nil, # downvotes
nil, # upvotes
nil, # sentiment
nil, # interest
true, # published
nil, # downvotes
nil, # upvotes
nil, # sentiment
nil, # interest
true, # published
Time.local, # created_at
]
)
Expand Down
10 changes: 8 additions & 2 deletions spec/granite/select/select_spec.cr
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
require "../../spec_helper"

describe "custom select" do
before_each do
Article.clear
Comment.clear
EventCon.clear
end

it "generates custom SQL with the query macro" do
ArticleViewModel.select.should eq "SELECT articles.id, articles.articlebody, comments.commentbody FROM articles JOIN comments ON comments.articleid = articles.id"
end

it "uses custom SQL to populate a view model - #all" do
first = Article.new.tap do |model|
model.articlebody = "The Article Body"
model.save
model.save!
end

Comment.new.tap do |model|
model.commentbody = "The Comment Body"
model.articleid = first.id
model.save
model.save!
end

viewmodel = ArticleViewModel.all
Expand Down
16 changes: 0 additions & 16 deletions spec/granite/transactions/create_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,6 @@ describe "#create" do
parent.persisted?.should be_false
end

it "doesn't have a race condition on IDs" do
n = 1000
ids = Array(Int64).new(n)
channel = Channel(Int64).new

n.times do
spawn do
parent = Parent.new(name: "Test Parent")
parent.save
(id = parent.id) && channel.send(id)
end
end
n.times { ids << channel.receive }
ids.uniq!.size.should eq n
end

describe "with a custom primary key" do
it "creates a new object" do
school = School.create(name: "Test School")
Expand Down
2 changes: 1 addition & 1 deletion spec/granite/validation_helpers/uniqueness_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require "../../spec_helper"

describe Granite::ValidationHelpers do
context "Uniqueness" do
Spec.before_each do
before_each do
Validators::PersonUniqueness.migrator.drop_and_create
end

Expand Down
7 changes: 5 additions & 2 deletions spec/granite_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,11 @@ describe Granite::Base do
describe "#to_yaml" do
it "emits nil values when told" do
t = TodoEmitNull.new(name: "test todo", priority: 20)
result = %(---\nid: \nname: test todo\npriority: 20\ncreated_at: \nupdated_at: \n)

result = {% if flag?(:darwin) %}
%(---\nid:\nname: test todo\npriority: 20\ncreated_at:\nupdated_at:\n)
{% else %}
%(---\nid: \nname: test todo\npriority: 20\ncreated_at: \nupdated_at: \n)
{% end %}
t.to_yaml.should eq result
end

Expand Down
2 changes: 1 addition & 1 deletion spec/run_all_specs.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#! /bin/bash

source ../.env
source .env

echo "Testing PG"

Expand Down
19 changes: 19 additions & 0 deletions spec/run_test_dbs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

MYSQL_VERSION=${MYSQL_VERSION:-5.7}
PG_VERSION=${PG_VERSION:-15.2}

docker run --name mysql -d \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=granite_db \
-e MYSQL_USER=granite \
-e MYSQL_PASSWORD=password \
-p 3306:3306 \
mysql:%{MYSQL_VERSION}

docker run --name psql -d \
-e POSTGRES_USER=granite \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=granite_db \
-p 5432:5432 \
postgres:${PG_VERSION}
Loading

0 comments on commit 5afa787

Please sign in to comment.