Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rely on global log level setup instead of waiting for custom logger to be assigned #447

Merged
merged 4 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions .github/run_integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ then
sudo apt-get install postgresql-client -y
fi

crystal spec spec/integration/sam_test.cr &&
# TODO: fix concurrency tests
# crystal spec spec/integration/concurrency_test.cr -Dpreview_mt &&
crystal spec spec/integration/micrate_test.cr
# === general tests ===

crystal spec spec/integration/sam_test.cr
# TODO: fix tests
# && crystal spec spec/integration/concurrency_test.cr -Dpreview_mt

# === micrate tests ===

cp ./.github/shard_micrate.yml ./shard.yml

shards

crystal spec spec/integration/micrate_test.cr
2 changes: 1 addition & 1 deletion .github/setup_mysql.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -exo pipefail

MYSQL="mysql:8.0.30"
MYSQL="mysql:8.0.35"
tries=0

sudo service mysql stop
Expand Down
File renamed without changes.
9 changes: 6 additions & 3 deletions .github/shard_1_3_2.yml → .github/shard_micrate.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# NOTE: the only difference from 1.4.1 is missing ameba
# Differences from a shard.yml:
# - missing ameba
# - uncommetned micrate
# - crystal-mysql and crystal-pg have lower versions to support micrate
name: jennifer
version: 0.13.0

Expand All @@ -21,10 +24,10 @@ development_dependencies:
version: "~> 0.1.5"
sam:
github: imdrasil/sam.cr
version: "~> 0.4.1"
version: "~> 0.5.0"
micrate:
github: "amberframework/micrate"
version: "= 0.12.0"
version: "= 0.15.1"
dependencies:
wordsmith:
github: luckyframework/wordsmith
Expand Down
37 changes: 37 additions & 0 deletions .github/shard_simple.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Differences from a shard.yml:
# - missing ameba
# - crystal-pg has a fixed version as older one isn't supported by older crystal
# - crystal-mysql has a fixed version
name: jennifer
version: 0.13.0

authors:
- Roman Kalnytskyi <moranibaca@gmail.com>

crystal: ">= 0.36.0"

license: MIT

development_dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: "= 0.14.0"
pg:
github: will/crystal-pg
version: "= 0.26.0"
factory:
github: imdrasil/factory
version: "~> 0.1.5"
sam:
github: imdrasil/sam.cr
version: "~> 0.5.0"
dependencies:
wordsmith:
github: luckyframework/wordsmith
version: ">= 0.3.0"
ifrit:
github: imdrasil/ifrit
version: "= 0.1.3"
i18n:
github: crimson-knight/i18n.cr
version: "~> 0.4.1"
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ jobs:
run: |
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
if [ $(version '${{ matrix.crystal_version }}') -lt $(version '1.8.2') ]; then
cp .github/shard_1_3_2.yml shard.yml
cp .github/shard_simple.yml shard.yml
cp .github/shard.override.yml shard.override.yml
fi
shards install

Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ dependencies:
- you need to choose one of the existing drivers for your DB: [mysql](https://github.com/crystal-lang/crystal-mysql) or [postgres](https://github.com/will/crystal-pg); sqlite3 adapter automatically installs required driver for it;
- crystal `>= 1.0.0`.

> MySQL `8.0.36` and above isn't supported at the moment

## Usage

Jennifer allows you to maintain everything for your models - from DB migrations and field mapping to callbacks and building queries. For detailed information see the [docs](https://imdrasil.github.io/jennifer.cr/docs/) and [API documentation](https://imdrasil.github.io/jennifer.cr/versions).
Expand All @@ -33,7 +35,7 @@ Jennifer has built-in database migration management system. Migrations allow you
To start using Jennifer you'll first need to generate a migration:

```shell
$ crystal sam.cr -- generate:migration CreateContact
$ crystal sam.cr generate:migration CreateContact
```

then fill the created migration file with content:
Expand Down Expand Up @@ -62,7 +64,7 @@ end
and run

```shell
$ crystal sam.cr -- db:setup
$ crystal sam.cr db:setup
```

to create the database and run the newly created migration.
Expand Down Expand Up @@ -151,10 +153,6 @@ You can easily configure error message generated for certain validation violatio
Jennifer uses a [standard](https://crystal-lang.org/api/latest/Log.html) Crystal logging mechanism so you could specify your own logger, backend and formatter:

```crystal
# This is the default logger configuration
Jennifer::Config.configure do |conf|
conf.logger = Log.for("db", :debug)
end
Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter)
```

Expand Down
30 changes: 15 additions & 15 deletions docs/command_line.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ load_dependencies "jennifer"
Creates database described in the configuration.

```shell
$ crystal sam.cr -- db:create
$ crystal sam.cr db:create
```

> Will create only **one** database. This means that for test environment (and for any extra environment you want) this command should be invoked separately. This is common for all commands in this section.
Expand All @@ -30,60 +30,60 @@ If database is already exists - successfully finishes (returns code 0).
Drops database described in the configuration.

```shell
$ crystal sam.cr -- db:drop
$ crystal sam.cr db:drop
```

### db:setup

Creates database, invokes all pending migrations and populate database with seeds.

```shell
$ crystal sam.cr -- db:setup
$ crystal sam.cr db:setup
```

### db:migrate

Runs all pending migrations and stores them in the `versions` table. After execution of new migrations database schema is dumped to the `structure.sql` file.

```shell
$ crystal sam.cr -- db:migrate
$ crystal sam.cr db:migrate
```

### db:step

Runs exact count of migrations (1 by default).

```shell
$ crystal sam.cr -- db:step
$ crystal sam.cr -- db:step <count>
$ crystal sam.cr db:step
$ crystal sam.cr db:step <count>
```

### db:rollback

Rollbacks the last run migration

```shell
$ crystal sam.cr -- db:rollback
$ crystal sam.cr db:rollback
```

To rollbacks specific count of migrations:

```shell
$ crystal sam.cr -- db:rollback <count>
$ crystal sam.cr db:rollback <count>
```

To rollback to the specific version:

```shell
$ crystal sam.cr -- db:rollback -v <migration_version>
$ crystal sam.cr db:rollback -v <migration_version>
```

### db:version

Outputs current database version.

```shell
$ crystal sam.cr -- db:version
$ crystal sam.cr db:version
```

### db:seed
Expand All @@ -92,15 +92,15 @@ Populates database with seeds. By default this task is empty and should be defin
bases.

```shell
$ crystal sam.cr -- db:seed
$ crystal sam.cr db:seed
```

### db:schema:load

Creates database from the `structure.sql` file.

```shell
$ crystal sam.cr -- db:schema:load
$ crystal sam.cr db:schema:load
```

> Running migration after this may cause error messages because of missing any information about run migrations in scope of current schema generating.
Expand All @@ -112,13 +112,13 @@ $ crystal sam.cr -- db:schema:load
Generates model and related migration based on the given definition.

```shell
$ crystal sam.cr -- generate:model <ModelName> [field1:type] ... [fieldN:type?]
$ crystal sam.cr generate:model <ModelName> [field1:type] ... [fieldN:type?]
```

Example:

```shell
$ crystal sam.cr -- generate:model Article title:string text:text? author:reference
$ crystal sam.cr generate:model Article title:string text:text? author:reference
```

```crystal
Expand Down Expand Up @@ -182,5 +182,5 @@ The `?` symbol at the end of type name means that this field is nilable.
Generates simple migration template.

```shell
$ crystal sam.cr -- generate:migration CreateArticles
$ crystal sam.cr generate:migration CreateArticles
```
34 changes: 5 additions & 29 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,38 +67,17 @@ If your configurations aren't stored on the top level - you can manipulate which
Jennifer::Config.read("./spec/fixtures/database.yml", &.["database"]["development"])
```

Also configuration can be parsed directly from URI:
Also some configuration can be parsed directly from a URI:

```crystal
db_uri = "mysql://root@somehost/some_database?max_pool_size=111&initial_pool_size=222&max_idle_pool_size=333&retry_attempts=444&checkout_timeout=555&retry_delay=666"
Jennifer::Config.from_uri(db)
```

Take into account - some configs can't be initialized using URI or yaml file but all of them always can be initialized using `Jennifer::Config.configure`. Here is the list of such configs:

| Config | YAML | URI |
| --- | --- | --- |
| `logger` | ❌ | ❌ |
| `migration_files_path` | ✔ | ❌ |
| `verbose_migrations` | ✔ | ❌ |
| `model_files_path` | ✔ | ❌ |
| `local_time_zone_name` | ✔ | ❌ |
| `schema` | ✔ | ❌ |
| `structure_folder` | ✔ | ❌ |
| `skip_dumping_schema_sql` | ✔ | ❌ |
| `docker_container` | ✔ | ❌ |
| `docker_source_location` | ✔ | ❌ |
| `command_shell_sudo` | ✔ | ❌ |
| `migration_failure_handler_method` | ✔ | ❌ |
| `allow_outdated_pending_migration` | ✔ | ❌ |
| `max_bind_vars_count` | ✔ | ❌ |
| `time_zone_aware_attributes` | ✔ | ❌ |

## Supported configuration options

* `host` - database host; default: `"localhost"`
* `port` - database port; default: `-1` (`-1` value makes adapter to skip port in building connection URL, specify required port number)
* `logger` - logger instance; default: `Log.for("db", :debug)`
* `schema` - PostgreSQL database schema name; default: `"public"`
* `user` - database user name used to connect to the database
* `password` - database user password used to connect to the database (if not specified - connection URL will specify only user name)
Expand Down Expand Up @@ -136,15 +115,12 @@ Take into account - some configs can't be initialized using URI or yaml file but
Jennifer uses [standard](https://crystal-lang.org/api/latest/Log.html) Crystal logging mechanism so you could specify your own logger:

```crystal
# This is default logger configuration
Jennifer::Config.configure do |conf|
conf.logger = Log.for("db", :debug)
end
```
require "jennifer/adapter/db_colorized_formatter"

As a default formatter `Jennifer::Adapter::DBFormatter` could be used:
Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBColorizedFormatter)

# or colorless

```crystal
Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter)
```

Expand Down
34 changes: 31 additions & 3 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,20 @@ Create `./config` folder - it will contain all your configurations. Also create
require "jennifer"
require "jennifer/adapter/postgres" # for PostgreSQL
# require "jennifer/adapter/mysql" for MySQL
require "jennifer/adapter/db_colorized_formatter"

APP_ENV = ENV["APP_ENV"]? || "development"

Jennifer::Config.configure do |conf|
conf.read("config/database.yml", APP_ENV)
conf.from_uri(ENV["DATABASE_URI"]) if ENV.has_key?("DATABASE_URI")
conf.logger.level = APP_ENV == "development" ? Log::Severity::Debug : Log::Severity::Error
end

Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter)
if APP_ENV == "development"
Log.setup "db", :debug, Log::IOBackend.new(formatter: Jennifer::Adapter::DBColorizedFormatter)
else
Log.setup "db", :error, Log::IOBackend.new(formatter: Jennifer::Adapter::DBFormatter)
end
```

This allows you to put all database related configuration to structured yml file and override it with custom database connection URI passing it in `DATABASE_URI`.
Expand Down Expand Up @@ -115,7 +119,7 @@ require "sam"
load_dependencies "jennifer"
```

Now you can invoke `$ crystal sam.cr -- help` to get list of all available tasks. Also you can generate makefile shorthand for this - just invoke `$ crystal sam.cr -- generate:makefile`. Now you are able to invoke Sam tasks by `make` - `$make sam help`.
Now you can invoke `$ crystal sam.cr help` to get list of all available tasks. Also you can generate makefile shorthand for this - just invoke `$ crystal sam.cr generate:makefile`. Now you are able to invoke Sam tasks by `make` - `$make sam help`.

## Usage

Expand Down Expand Up @@ -189,3 +193,27 @@ Now we are able to use our model:
user = User.create({name: "New User", age: 100})
puts user.inspect
```

## Tests

To make you test cases isolated you need to wrap them in a transaction. To do so use `Jennifer::Adapter.default_adapter`:

```crystal
# spec_helper.cr

Spec.before_each do
Jennifer::Adapter.default_adapter.begin_transaction
end

Spec.after_each do
Jennifer::Adapter.default_adapter.rollback_transaction
end
```

To be sure that your test database has all latest migration ran add this to your `spec_helper.cr`:

```crystal
require "../db/migrations/*" # you need to load all your migrations

Jennifer::Migration::Runner.migrate
```
2 changes: 0 additions & 2 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ exec("ALTER TABLE addresses CHANGE street st VARCHAR(20)")

All changes are executed one by one so you also could add data changes here (in `#up` and/or `#down`).

To be sure that your db is up to date, add `Jennifer::Migration::Runner.migrate` in `spec_helper.cr`.

#### Enum

Now enums are supported as well but each adapter has own implementation. For mysql is enough just write down all values:
Expand Down
Loading
Loading