Skip to content

Commit

Permalink
Merge pull request #159 from anykeyh/v0.9
Browse files Browse the repository at this point in the history
v0.9
  • Loading branch information
anykeyh authored Nov 22, 2020
2 parents b3d4e87 + 3178c7f commit 7460874
Show file tree
Hide file tree
Showing 170 changed files with 4,965 additions and 2,474 deletions.
3 changes: 3 additions & 0 deletions .ameba.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Style/ConstantNames:
Excluded:
- "**/*.cr"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
/bin/ameba
/bin/clear-cli

# I use this file to test some complex Crystal syntax sometime
/test.cr

# will migrate to github action one day
/.github
/.git-stats

# deps of some tools
/node_modules
yarn.lock
Expand Down
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: crystal
script:
- crystal spec -Dquiet
- bin/ameba
- make test
- crystal docs
services:
- postgresql
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
CRYSTAL_BIN ?= $(shell which crystal)
SHARDS_BIN ?= $(shell which shards)
AMEBA_BIN ?= bin/ameba

test:
build: bin/clear-cli

bin/clear-cli:
$(SHARDS_BIN) build

spec: build
$(CRYSTAL_BIN) spec -Dquiet --warnings=all

ameba:
$(AMEBA_BIN) src spec

test: build spec ameba
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,11 +405,11 @@ One thing very important for a good ORM is to offer vision of the SQL
called under the hood.
Clear is offering SQL logging tools, with SQL syntax colorizing in your terminal.

For activation, simply setup the logger to `DEBUG` level !
For activation, simply setup the log to `:debug` level


```
Clear.logger.level = ::Logger::DEBUG
::Log.builder.bind "clear.*", Log::Severity::Debug, Log::IOBackend.new
```

### Save & validation
Expand Down
14 changes: 14 additions & 0 deletions bin/install_cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

CRYSTAL_BIN=$(which crystal)
CURR_PWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
SRC_DIR=CURR_PWD/../src

compile() {
mkdir -t /tmp/.drop-cli
$CRYSTAL_BIN build --release SRC_DIR/clear/cli.cr -o /tmp/.drop-cli/drop-cli
}

clean() {
test -d /tmp/.drop-cli && rm -r /tmp/.drop-cli
}
161 changes: 154 additions & 7 deletions manual/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,150 @@
# v0.9

I'm pleased to announce the version 0.9 of Crystal Clear ORM !
This version is probably the biggest version released since Clear is born.

Under the hood, it simplifies a lot of code, push testing to another level with
a great amount of new specs.

On the feature part, it add full support for serializing to and from json, with mass assignment secure check, big decimal
type, PostgreSQL view management at migration, new callbacks methods, support for postgres interval object and so on...

Finally, the code has been tweaked to be compatible with release of Crystal 1.0.

With that in mind, Clear starts to mature, with only CLI, polymorphic relations and model inheritance still lacking.

_Note of warning_: some changes will break your code. However everything can be fixed in matter of minutes (hopefully)

Special thanks to all contributors of this version:

@007lva @anykeyh @GabFitzgerald @dukeraphaelng @mamantoha @watzon @yujiri8

(hopefully I did not forget someone)

## Breaking changes

- `Clear::SQL::ConnectionPool` now returns DB::Connection instead of DB::Database (fix #177)
- `Clear::Migration::Direction` is now an enum instead of a struct.
- where and having clauses use splat and named tuple always. This is breaking change.
- Before you had to do:

```crystal
where("a = ?", [1])
```

Now you can do much more easy:

```crystal
where("a = ?", 1)
```

Same apply for the named parameters version:

```crystal
# Instead of
where("a = :a", { a: 1 } )
# Do
where("a = :a", a: 1)
```


## Features

- PR #187 Add methods to import from and to `json`, with mass_assignment security
(thanks @dukeraphaelng and Caspian Baska for this awesome work!)
- PR #191 Add Big Decimal support (@dukeraphaelng)
- `Collection#add_operation` has been renamed to `Collection#append_operation`
- Add `Clear::SQL.after_commit` method

Register a callback function which will be fired once when SQL `COMMIT`
operation is called

This can be used for example to send email, or perform others tasks
when you want to be sure the data is secured in the database.

```crystal
transaction do
@user = User.find(1)
@user.subscribe!
Clear::SQL.after_commit{ Email.deliver(ConfirmationMail.new(@user)) }
end
```

In case the transaction fail and eventually rollback, the code won't be called.

Same method exists now on the model level, using before and after hooks:

```crystal
class User
include Clear::Model
after(:commit){ |mdl| WelcomeEmail.new(mdl.as(User)).deliver_now }
end
```

Note: `before(:commit)` and `after(:commit)` are both called after the transaction has been commited.
Before hook always call before after hook.

- Add possibility to name and rollback to a specific savepoint:

```crystal
Clear::SQL.with_savepoint("a") do
Clear::SQL.with_savepoint("b") do
Clear::SQL.rollback("a") # < Exit to "a"
end
puts "This won't be called"
end
puts "This will be called"
```

- Add `Clear.json_serializable_converter(CustomType)`

This macro help setting a converter transparently for any `CustomType`.
Your `CustomType` must be `JSON::Serializable`, and the database column
must be of type `jsonb`, `json` or `text`.

```crystal
class Color
include JSON::Serializable
@[JSON::Field]; property r: Int8
@[JSON::Field]; property g: Int8
@[JSON::Field]; property b: Int8
@[JSON::Field]; property a: Int8
end
Clear.json_serializable_converter(Color)
# Now you can use Color in your models:
class MyModel
include Clear::Model
column color : Color
end
```

- Add `jsonb().contains?(...)` method

This allow usage of Postgres `?` operator over `jsonb` fields:

```crystal
# SELECT * FROM actors WHERE "jsonb_column"->'movies' ? 'Top Gun' LIMIT 1;
Actor.query.where{ var("jsonb_column").jsonb("movies").contains?("Top Gun") }.first!.name # << Tom Cruise
```

- Add `SelectQuery#reverse_order_by` method

A convenient method to reverse all the order by clauses,
turning each `ASC` to `DESC` direction, and each `NULLS FIRST` to `NULLS LAST`


## Bugfixes

- Prepare the code to make it compatible with crystal 1.0. Change `Void` to `Nil`
- `first` and `last` on collection object does not change the collection anymore (previously would add limit/offset and change order_by clauses)
- Dozen of other bugs not tracked here have been fixed, by usage or new test sets.

# v0.8

## Features
Expand Down Expand Up @@ -29,30 +176,30 @@ query = Mode.query.select( Clear::SQL.raw("CASE WHEN x=? THEN 1 ELSE 0 END as ch

## Features

- Add `Clear::Interval` type
- Add support for `PG::Interval` type

This type is related to the type `Clear::Interval` of PostgreSQL. It stores `month`, `days` and `microseconds` and can be used
This type is related to the type `PG::Interval` of PostgreSQL. It stores `month`, `days` and `microseconds` and can be used
with `Time` (Postgres' `datetime`) by adding or substracting it.

### Examples:

Usage in Expression engine:

```crystal
interval = Clear::Interval.new(months: 1, days: 1)
interval = PG::Interval.new(months: 1, days: 1)
MyModel.query.where{ created_at - interval > updated_at }.each do |model|
# ...
end
```

It might be used as column definition, and added / removed to crystal `Time` object
It might be used as column definition as well.

```crystal
class MyModel
include Clear::Model
column i : Clear::Interval
column i : PG::Interval
end
puts "Expected time: #{Time.local + MyModel.first!.i}"
Expand Down Expand Up @@ -257,7 +404,7 @@ Basically a transition version, to support Crystal 0.27. Some of the features of
## Breaking changes
- `Model#save` on read only model do not throw exception anymore but return false (save! still throw error)
- `with_serial_pkey` use Int32 (type `:serial`) and Int64 (type `:longserial`) pkey instead of UInt32 and UInt64. This would prevent issue with default `belongs_to` behavior and simplify static number assignation.
- `with_serial_pkey` use Int32 (type `:serial`) and Int64 (type `:longserial`) primary key instead of `UInt32` and `UInt64`. This would prevent issue with default `belongs_to` behavior and simplify static number assignation.
# v0.2
Expand Down Expand Up @@ -300,7 +447,7 @@ Basically a transition version, to support Crystal 0.27. Some of the features of

## Bugfixes

- Patching segfault caused by weird architecture choice of mine over the `pkey` method.
- Patching segfault caused by weird architecture choice of mine over the `__pkey__` method.
- Fix issue with delete if the primary key is not `id`
- Add watchdog to disallow inclusion of `Clear::Model` on struct objects, which
is not intended to work.
Expand Down
8 changes: 4 additions & 4 deletions manual/model/associations/has_many.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Let's see the example used in the chapter [`belongs_to`](belongs_to.md):

```sql
CREATE TABLE categories (
id bigserial NOT NULL PRIMARY KEY,
id bigserial NOT NULL PRIMARY KEY,
name text NOT NULL
)

Expand Down Expand Up @@ -54,7 +54,7 @@ end
Note: The relation can be refined after fetching:

```ruby
# Fetch only the posts which starts by a digit:
# Fetch only the posts which starts by a digit:
c.posts.where{name =~ /^[0-9]/i}.each do |post|
puts "Post name: #{post.name}"
end
Expand All @@ -65,14 +65,14 @@ end
Clear uses naming convention to infer the name of the foreign key. You may want to override this behavior by adding some parameters:

```ruby
has_many relation_name : RelationType,
has_many relation_name : RelationType,
foreign_key: "column_name", own_key: "column_name", no_cache: true|false
```

| Argument | Description | Default value |
| :---: | :--- | :---: |
| `foreign_key` | The foreign key which is inside the relative model | `[underscore_model_name]_id` |
| `own_key` | The key against what the relation is tested, primary key by default | `self.class.pkey` |
| `own_key` | The key against what the relation is tested, primary key by default | `self.class.__pkey__` |
| `no_cache` | Never cache the relation \(note: planned feature\) | `false` |

## Adding to relation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Thankfully, the expression engine will reject any "static code" and throw an exc
User.query.where{ var("id") == id } # WHERE "id" = ?
User.query.where{ raw("id") == id } # WHERE id = ?
User.query.where{ raw("users.id") == id } # WHERE users.id = ?
User.query.where{var("users", "id") == id} # WHERE "users"."id" = ?
User.query.where{ var("users", "id") == id } # WHERE "users"."id" = ?
```

{% hint style="danger" %}
Expand Down
3 changes: 2 additions & 1 deletion manual_old/BasicExample.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ require "clear"
# Initialize the connection
Clear::SQL.init("postgres://postgres@localhost/sample_for_wiki")
# Setting log level to DEBUG will allow you to see the requests made by the system
Clear.logger.level = ::Logger::DEBUG
::Log.builder.bind "clear.*", Log::Severity::Debug, Log::IOBackend.new
# Because it's a step by step tutorial
def pause
Expand Down
4 changes: 2 additions & 2 deletions manual_old/Setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ By choice, Clear doesn't offers any configuration file (e.g. `database.yml`), so

# Logging

By default, logging of SQL output is disabled. To enable it, you need to change the logger verbosity level:
By default, logging of SQL output is disabled. To enable it, you need to change the log module verbosity level:

```crystal
Clear.logger.level = ::Logger::DEBUG
::Log.builder.bind "clear.*", Log::Severity::Debug, Log::IOBackend.new
```
6 changes: 3 additions & 3 deletions manual_old/model/DebuggingInfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ We've reimplemented `inspect` on models, to offer debugging insights:
In this case, the `*` means a column is changed and the object is dirty and must
be saved on the database.

#### SQL Logging
#### Log SQL queries

Clear is offering SQL logging tools, with SQL syntax colorizing in your terminal.
For activation, simply setup the logger to `DEBUG` level
For activation, simply setup the logger to `Debug` level

```
Clear.logger.level = ::Logger::DEBUG
::Log.builder.bind "clear.*", ::Log::Severity::Debug, ::Log::IOBackend.new
```

Also, Clear will log all query made, and when exception will show you the last query
Expand Down
2 changes: 0 additions & 2 deletions sample/benchmark/model.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ require "benchmark"
`echo "DROP DATABASE IF EXISTS benchmark_clear;" | psql -U postgres`
`echo "CREATE DATABASE benchmark_clear;" | psql -U postgres`
Clear::SQL.init("postgres://postgres@localhost/benchmark_clear")
# Setting log level to DEBUG will allow you to see the requests made by the system
# Clear.logger.level = ::Logger::DEBUG

init = <<-SQL
CREATE TABLE benchmark (id serial PRIMARY KEY NOT NULL, y int);
Expand Down
12 changes: 6 additions & 6 deletions sample/benchmark/sql.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ require "benchmark"

def complex_query
Clear::SQL.select.from(:users)
.join(:role_users) { role_users.user_id == users.id }
.join(:roles) { role_users.role_id == roles.id }
.where({role: ["admin", "superadmin"]})
.order_by({priority: :desc, name: :asc})
.limit(50)
.offset(50)
.join(:role_users) { role_users.user_id == users.id }
.join(:roles) { role_users.role_id == roles.id }
.where({role: ["admin", "superadmin"]})
.order_by({priority: :desc, name: :asc})
.limit(50)
.offset(50)
end

Benchmark.ips(warmup: 2, calculation: 3) do |x|
Expand Down
Loading

0 comments on commit 7460874

Please sign in to comment.