Skip to content

Commit 7460874

Browse files
authored
Merge pull request #159 from anykeyh/v0.9
v0.9
2 parents b3d4e87 + 3178c7f commit 7460874

File tree

170 files changed

+4965
-2474
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+4965
-2474
lines changed

.ameba.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Style/ConstantNames:
2+
Excluded:
3+
- "**/*.cr"

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
/bin/ameba
1313
/bin/clear-cli
1414

15+
# I use this file to test some complex Crystal syntax sometime
16+
/test.cr
17+
18+
# will migrate to github action one day
19+
/.github
20+
/.git-stats
21+
1522
# deps of some tools
1623
/node_modules
1724
yarn.lock

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
language: crystal
22
script:
3-
- crystal spec -Dquiet
4-
- bin/ameba
3+
- make test
54
- crystal docs
65
services:
76
- postgresql

Makefile

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
CRYSTAL_BIN ?= $(shell which crystal)
2+
SHARDS_BIN ?= $(shell which shards)
3+
AMEBA_BIN ?= bin/ameba
24

3-
test:
5+
build: bin/clear-cli
6+
7+
bin/clear-cli:
8+
$(SHARDS_BIN) build
9+
10+
spec: build
411
$(CRYSTAL_BIN) spec -Dquiet --warnings=all
512

13+
ameba:
14+
$(AMEBA_BIN) src spec
15+
16+
test: build spec ameba

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,11 @@ One thing very important for a good ORM is to offer vision of the SQL
405405
called under the hood.
406406
Clear is offering SQL logging tools, with SQL syntax colorizing in your terminal.
407407

408-
For activation, simply setup the logger to `DEBUG` level !
408+
For activation, simply setup the log to `:debug` level
409409

410410

411411
```
412-
Clear.logger.level = ::Logger::DEBUG
412+
::Log.builder.bind "clear.*", Log::Severity::Debug, Log::IOBackend.new
413413
```
414414

415415
### Save & validation

bin/install_cli.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
3+
CRYSTAL_BIN=$(which crystal)
4+
CURR_PWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
5+
SRC_DIR=CURR_PWD/../src
6+
7+
compile() {
8+
mkdir -t /tmp/.drop-cli
9+
$CRYSTAL_BIN build --release SRC_DIR/clear/cli.cr -o /tmp/.drop-cli/drop-cli
10+
}
11+
12+
clean() {
13+
test -d /tmp/.drop-cli && rm -r /tmp/.drop-cli
14+
}

manual/CHANGELOG.md

Lines changed: 154 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,150 @@
1+
# v0.9
2+
3+
I'm pleased to announce the version 0.9 of Crystal Clear ORM !
4+
This version is probably the biggest version released since Clear is born.
5+
6+
Under the hood, it simplifies a lot of code, push testing to another level with
7+
a great amount of new specs.
8+
9+
On the feature part, it add full support for serializing to and from json, with mass assignment secure check, big decimal
10+
type, PostgreSQL view management at migration, new callbacks methods, support for postgres interval object and so on...
11+
12+
Finally, the code has been tweaked to be compatible with release of Crystal 1.0.
13+
14+
With that in mind, Clear starts to mature, with only CLI, polymorphic relations and model inheritance still lacking.
15+
16+
_Note of warning_: some changes will break your code. However everything can be fixed in matter of minutes (hopefully)
17+
18+
Special thanks to all contributors of this version:
19+
20+
@007lva @anykeyh @GabFitzgerald @dukeraphaelng @mamantoha @watzon @yujiri8
21+
22+
(hopefully I did not forget someone)
23+
24+
## Breaking changes
25+
26+
- `Clear::SQL::ConnectionPool` now returns DB::Connection instead of DB::Database (fix #177)
27+
- `Clear::Migration::Direction` is now an enum instead of a struct.
28+
- where and having clauses use splat and named tuple always. This is breaking change.
29+
- Before you had to do:
30+
31+
```crystal
32+
where("a = ?", [1])
33+
```
34+
35+
Now you can do much more easy:
36+
37+
```crystal
38+
where("a = ?", 1)
39+
```
40+
41+
Same apply for the named parameters version:
42+
43+
```crystal
44+
# Instead of
45+
where("a = :a", { a: 1 } )
46+
# Do
47+
where("a = :a", a: 1)
48+
```
49+
50+
51+
## Features
52+
53+
- PR #187 Add methods to import from and to `json`, with mass_assignment security
54+
(thanks @dukeraphaelng and Caspian Baska for this awesome work!)
55+
- PR #191 Add Big Decimal support (@dukeraphaelng)
56+
- `Collection#add_operation` has been renamed to `Collection#append_operation`
57+
- Add `Clear::SQL.after_commit` method
58+
59+
Register a callback function which will be fired once when SQL `COMMIT`
60+
operation is called
61+
62+
This can be used for example to send email, or perform others tasks
63+
when you want to be sure the data is secured in the database.
64+
65+
```crystal
66+
transaction do
67+
@user = User.find(1)
68+
@user.subscribe!
69+
Clear::SQL.after_commit{ Email.deliver(ConfirmationMail.new(@user)) }
70+
end
71+
```
72+
73+
In case the transaction fail and eventually rollback, the code won't be called.
74+
75+
Same method exists now on the model level, using before and after hooks:
76+
77+
```crystal
78+
class User
79+
include Clear::Model
80+
81+
after(:commit){ |mdl| WelcomeEmail.new(mdl.as(User)).deliver_now }
82+
end
83+
```
84+
85+
Note: `before(:commit)` and `after(:commit)` are both called after the transaction has been commited.
86+
Before hook always call before after hook.
87+
88+
- Add possibility to name and rollback to a specific savepoint:
89+
90+
```crystal
91+
Clear::SQL.with_savepoint("a") do
92+
Clear::SQL.with_savepoint("b") do
93+
Clear::SQL.rollback("a") # < Exit to "a"
94+
end
95+
puts "This won't be called"
96+
end
97+
puts "This will be called"
98+
```
99+
100+
- Add `Clear.json_serializable_converter(CustomType)`
101+
102+
This macro help setting a converter transparently for any `CustomType`.
103+
Your `CustomType` must be `JSON::Serializable`, and the database column
104+
must be of type `jsonb`, `json` or `text`.
105+
106+
```crystal
107+
class Color
108+
include JSON::Serializable
109+
110+
@[JSON::Field]; property r: Int8
111+
@[JSON::Field]; property g: Int8
112+
@[JSON::Field]; property b: Int8
113+
@[JSON::Field]; property a: Int8
114+
end
115+
116+
Clear.json_serializable_converter(Color)
117+
118+
# Now you can use Color in your models:
119+
120+
class MyModel
121+
include Clear::Model
122+
123+
column color : Color
124+
end
125+
```
126+
127+
- Add `jsonb().contains?(...)` method
128+
129+
This allow usage of Postgres `?` operator over `jsonb` fields:
130+
131+
```crystal
132+
# SELECT * FROM actors WHERE "jsonb_column"->'movies' ? 'Top Gun' LIMIT 1;
133+
Actor.query.where{ var("jsonb_column").jsonb("movies").contains?("Top Gun") }.first!.name # << Tom Cruise
134+
```
135+
136+
- Add `SelectQuery#reverse_order_by` method
137+
138+
A convenient method to reverse all the order by clauses,
139+
turning each `ASC` to `DESC` direction, and each `NULLS FIRST` to `NULLS LAST`
140+
141+
142+
## Bugfixes
143+
144+
- Prepare the code to make it compatible with crystal 1.0. Change `Void` to `Nil`
145+
- `first` and `last` on collection object does not change the collection anymore (previously would add limit/offset and change order_by clauses)
146+
- Dozen of other bugs not tracked here have been fixed, by usage or new test sets.
147+
1148
# v0.8
2149

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

30177
## Features
31178

32-
- Add `Clear::Interval` type
179+
- Add support for `PG::Interval` type
33180

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

37184
### Examples:
38185

39186
Usage in Expression engine:
40187

41188
```crystal
42-
interval = Clear::Interval.new(months: 1, days: 1)
189+
interval = PG::Interval.new(months: 1, days: 1)
43190
44191
MyModel.query.where{ created_at - interval > updated_at }.each do |model|
45192
# ...
46193
end
47194
```
48195

49-
It might be used as column definition, and added / removed to crystal `Time` object
196+
It might be used as column definition as well.
50197

51198
```crystal
52199
class MyModel
53200
include Clear::Model
54201
55-
column i : Clear::Interval
202+
column i : PG::Interval
56203
end
57204
58205
puts "Expected time: #{Time.local + MyModel.first!.i}"
@@ -257,7 +404,7 @@ Basically a transition version, to support Crystal 0.27. Some of the features of
257404
258405
## Breaking changes
259406
- `Model#save` on read only model do not throw exception anymore but return false (save! still throw error)
260-
- `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.
407+
- `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.
261408
262409
# v0.2
263410
@@ -300,7 +447,7 @@ Basically a transition version, to support Crystal 0.27. Some of the features of
300447

301448
## Bugfixes
302449

303-
- Patching segfault caused by weird architecture choice of mine over the `pkey` method.
450+
- Patching segfault caused by weird architecture choice of mine over the `__pkey__` method.
304451
- Fix issue with delete if the primary key is not `id`
305452
- Add watchdog to disallow inclusion of `Clear::Model` on struct objects, which
306453
is not intended to work.

manual/model/associations/has_many.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Let's see the example used in the chapter [`belongs_to`](belongs_to.md):
66

77
```sql
88
CREATE TABLE categories (
9-
id bigserial NOT NULL PRIMARY KEY,
9+
id bigserial NOT NULL PRIMARY KEY,
1010
name text NOT NULL
1111
)
1212

@@ -54,7 +54,7 @@ end
5454
Note: The relation can be refined after fetching:
5555

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

6767
```ruby
68-
has_many relation_name : RelationType,
68+
has_many relation_name : RelationType,
6969
foreign_key: "column_name", own_key: "column_name", no_cache: true|false
7070
```
7171

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

7878
## Adding to relation

manual/querying/the-collection-object/filter-the-query-1/filter-the-query.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Thankfully, the expression engine will reject any "static code" and throw an exc
7575
User.query.where{ var("id") == id } # WHERE "id" = ?
7676
User.query.where{ raw("id") == id } # WHERE id = ?
7777
User.query.where{ raw("users.id") == id } # WHERE users.id = ?
78-
User.query.where{var("users", "id") == id} # WHERE "users"."id" = ?
78+
User.query.where{ var("users", "id") == id } # WHERE "users"."id" = ?
7979
```
8080

8181
{% hint style="danger" %}

manual_old/BasicExample.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ require "clear"
1919
# Initialize the connection
2020
Clear::SQL.init("postgres://postgres@localhost/sample_for_wiki")
2121
# Setting log level to DEBUG will allow you to see the requests made by the system
22-
Clear.logger.level = ::Logger::DEBUG
22+
23+
::Log.builder.bind "clear.*", Log::Severity::Debug, Log::IOBackend.new
2324
2425
# Because it's a step by step tutorial
2526
def pause

0 commit comments

Comments
 (0)