hanami-model 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +54 -420
  4. data/hanami-model.gemspec +9 -6
  5. data/lib/hanami/entity.rb +107 -191
  6. data/lib/hanami/entity/schema.rb +236 -0
  7. data/lib/hanami/model.rb +52 -138
  8. data/lib/hanami/model/association.rb +37 -0
  9. data/lib/hanami/model/associations/belongs_to.rb +19 -0
  10. data/lib/hanami/model/associations/dsl.rb +29 -0
  11. data/lib/hanami/model/associations/has_many.rb +200 -0
  12. data/lib/hanami/model/configuration.rb +52 -224
  13. data/lib/hanami/model/configurator.rb +62 -0
  14. data/lib/hanami/model/entity_name.rb +35 -0
  15. data/lib/hanami/model/error.rb +37 -24
  16. data/lib/hanami/model/mapping.rb +29 -35
  17. data/lib/hanami/model/migration.rb +31 -0
  18. data/lib/hanami/model/migrator.rb +111 -88
  19. data/lib/hanami/model/migrator/adapter.rb +39 -16
  20. data/lib/hanami/model/migrator/connection.rb +23 -11
  21. data/lib/hanami/model/migrator/mysql_adapter.rb +38 -17
  22. data/lib/hanami/model/migrator/postgres_adapter.rb +20 -19
  23. data/lib/hanami/model/migrator/sqlite_adapter.rb +9 -8
  24. data/lib/hanami/model/plugins.rb +25 -0
  25. data/lib/hanami/model/plugins/mapping.rb +55 -0
  26. data/lib/hanami/model/plugins/schema.rb +55 -0
  27. data/lib/hanami/model/plugins/timestamps.rb +118 -0
  28. data/lib/hanami/model/relation_name.rb +24 -0
  29. data/lib/hanami/model/sql.rb +161 -0
  30. data/lib/hanami/model/sql/console.rb +41 -0
  31. data/lib/hanami/model/sql/consoles/abstract.rb +33 -0
  32. data/lib/hanami/model/sql/consoles/mysql.rb +63 -0
  33. data/lib/hanami/model/sql/consoles/postgresql.rb +68 -0
  34. data/lib/hanami/model/sql/consoles/sqlite.rb +46 -0
  35. data/lib/hanami/model/sql/entity/schema.rb +125 -0
  36. data/lib/hanami/model/sql/types.rb +95 -0
  37. data/lib/hanami/model/sql/types/schema/coercions.rb +198 -0
  38. data/lib/hanami/model/types.rb +99 -0
  39. data/lib/hanami/model/version.rb +1 -1
  40. data/lib/hanami/repository.rb +287 -723
  41. metadata +77 -40
  42. data/EXAMPLE.md +0 -213
  43. data/lib/hanami/entity/dirty_tracking.rb +0 -74
  44. data/lib/hanami/model/adapters/abstract.rb +0 -281
  45. data/lib/hanami/model/adapters/file_system_adapter.rb +0 -288
  46. data/lib/hanami/model/adapters/implementation.rb +0 -111
  47. data/lib/hanami/model/adapters/memory/collection.rb +0 -132
  48. data/lib/hanami/model/adapters/memory/command.rb +0 -113
  49. data/lib/hanami/model/adapters/memory/query.rb +0 -653
  50. data/lib/hanami/model/adapters/memory_adapter.rb +0 -179
  51. data/lib/hanami/model/adapters/null_adapter.rb +0 -24
  52. data/lib/hanami/model/adapters/sql/collection.rb +0 -287
  53. data/lib/hanami/model/adapters/sql/command.rb +0 -88
  54. data/lib/hanami/model/adapters/sql/console.rb +0 -33
  55. data/lib/hanami/model/adapters/sql/consoles/mysql.rb +0 -49
  56. data/lib/hanami/model/adapters/sql/consoles/postgresql.rb +0 -48
  57. data/lib/hanami/model/adapters/sql/consoles/sqlite.rb +0 -26
  58. data/lib/hanami/model/adapters/sql/query.rb +0 -788
  59. data/lib/hanami/model/adapters/sql_adapter.rb +0 -296
  60. data/lib/hanami/model/coercer.rb +0 -74
  61. data/lib/hanami/model/config/adapter.rb +0 -116
  62. data/lib/hanami/model/config/mapper.rb +0 -45
  63. data/lib/hanami/model/mapper.rb +0 -124
  64. data/lib/hanami/model/mapping/attribute.rb +0 -85
  65. data/lib/hanami/model/mapping/coercers.rb +0 -314
  66. data/lib/hanami/model/mapping/collection.rb +0 -490
  67. data/lib/hanami/model/mapping/collection_coercer.rb +0 -79
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-02-05 00:00:00.000000000 Z
13
+ date: 2016-11-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hanami-utils
@@ -18,28 +18,70 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '0.7'
21
+ version: '0.8'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '0.7'
28
+ version: '0.8'
29
29
  - !ruby/object:Gem::Dependency
30
- name: sequel
30
+ name: rom-sql
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - "~>"
34
34
  - !ruby/object:Gem::Version
35
- version: '4.9'
35
+ version: '0.9'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: '4.9'
42
+ version: '0.9'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rom-repository
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.3'
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.3'
57
+ - !ruby/object:Gem::Dependency
58
+ name: dry-types
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '0.9'
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.9'
71
+ - !ruby/object:Gem::Dependency
72
+ name: concurrent-ruby
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '1.0'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '1.0'
43
85
  - !ruby/object:Gem::Dependency
44
86
  name: bundler
45
87
  requirement: !ruby/object:Gem::Requirement
@@ -74,16 +116,15 @@ dependencies:
74
116
  requirements:
75
117
  - - "~>"
76
118
  - !ruby/object:Gem::Version
77
- version: '10'
119
+ version: '11'
78
120
  type: :development
79
121
  prerelease: false
80
122
  version_requirements: !ruby/object:Gem::Requirement
81
123
  requirements:
82
124
  - - "~>"
83
125
  - !ruby/object:Gem::Version
84
- version: '10'
85
- description: A persistence framework with entities, repositories, data mapper and
86
- query objects
126
+ version: '11'
127
+ description: A persistence framework with entities and repositories
87
128
  email:
88
129
  - me@lucaguidi.com
89
130
  - trung.le@ruby-journal.com
@@ -93,47 +134,44 @@ extensions: []
93
134
  extra_rdoc_files: []
94
135
  files:
95
136
  - CHANGELOG.md
96
- - EXAMPLE.md
97
137
  - LICENSE.md
98
138
  - README.md
99
139
  - hanami-model.gemspec
100
140
  - lib/hanami-model.rb
101
141
  - lib/hanami/entity.rb
102
- - lib/hanami/entity/dirty_tracking.rb
142
+ - lib/hanami/entity/schema.rb
103
143
  - lib/hanami/model.rb
104
- - lib/hanami/model/adapters/abstract.rb
105
- - lib/hanami/model/adapters/file_system_adapter.rb
106
- - lib/hanami/model/adapters/implementation.rb
107
- - lib/hanami/model/adapters/memory/collection.rb
108
- - lib/hanami/model/adapters/memory/command.rb
109
- - lib/hanami/model/adapters/memory/query.rb
110
- - lib/hanami/model/adapters/memory_adapter.rb
111
- - lib/hanami/model/adapters/null_adapter.rb
112
- - lib/hanami/model/adapters/sql/collection.rb
113
- - lib/hanami/model/adapters/sql/command.rb
114
- - lib/hanami/model/adapters/sql/console.rb
115
- - lib/hanami/model/adapters/sql/consoles/mysql.rb
116
- - lib/hanami/model/adapters/sql/consoles/postgresql.rb
117
- - lib/hanami/model/adapters/sql/consoles/sqlite.rb
118
- - lib/hanami/model/adapters/sql/query.rb
119
- - lib/hanami/model/adapters/sql_adapter.rb
120
- - lib/hanami/model/coercer.rb
121
- - lib/hanami/model/config/adapter.rb
122
- - lib/hanami/model/config/mapper.rb
144
+ - lib/hanami/model/association.rb
145
+ - lib/hanami/model/associations/belongs_to.rb
146
+ - lib/hanami/model/associations/dsl.rb
147
+ - lib/hanami/model/associations/has_many.rb
123
148
  - lib/hanami/model/configuration.rb
149
+ - lib/hanami/model/configurator.rb
150
+ - lib/hanami/model/entity_name.rb
124
151
  - lib/hanami/model/error.rb
125
- - lib/hanami/model/mapper.rb
126
152
  - lib/hanami/model/mapping.rb
127
- - lib/hanami/model/mapping/attribute.rb
128
- - lib/hanami/model/mapping/coercers.rb
129
- - lib/hanami/model/mapping/collection.rb
130
- - lib/hanami/model/mapping/collection_coercer.rb
153
+ - lib/hanami/model/migration.rb
131
154
  - lib/hanami/model/migrator.rb
132
155
  - lib/hanami/model/migrator/adapter.rb
133
156
  - lib/hanami/model/migrator/connection.rb
134
157
  - lib/hanami/model/migrator/mysql_adapter.rb
135
158
  - lib/hanami/model/migrator/postgres_adapter.rb
136
159
  - lib/hanami/model/migrator/sqlite_adapter.rb
160
+ - lib/hanami/model/plugins.rb
161
+ - lib/hanami/model/plugins/mapping.rb
162
+ - lib/hanami/model/plugins/schema.rb
163
+ - lib/hanami/model/plugins/timestamps.rb
164
+ - lib/hanami/model/relation_name.rb
165
+ - lib/hanami/model/sql.rb
166
+ - lib/hanami/model/sql/console.rb
167
+ - lib/hanami/model/sql/consoles/abstract.rb
168
+ - lib/hanami/model/sql/consoles/mysql.rb
169
+ - lib/hanami/model/sql/consoles/postgresql.rb
170
+ - lib/hanami/model/sql/consoles/sqlite.rb
171
+ - lib/hanami/model/sql/entity/schema.rb
172
+ - lib/hanami/model/sql/types.rb
173
+ - lib/hanami/model/sql/types/schema/coercions.rb
174
+ - lib/hanami/model/types.rb
137
175
  - lib/hanami/model/version.rb
138
176
  - lib/hanami/repository.rb
139
177
  homepage: http://hanamirb.org
@@ -148,7 +186,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
186
  requirements:
149
187
  - - ">="
150
188
  - !ruby/object:Gem::Version
151
- version: 2.0.0
189
+ version: 2.3.0
152
190
  required_rubygems_version: !ruby/object:Gem::Requirement
153
191
  requirements:
154
192
  - - ">="
@@ -156,9 +194,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
194
  version: '0'
157
195
  requirements: []
158
196
  rubyforge_project:
159
- rubygems_version: 2.5.1
197
+ rubygems_version: 2.6.4
160
198
  signing_key:
161
199
  specification_version: 4
162
200
  summary: A persistence layer for Hanami
163
201
  test_files: []
164
- has_rdoc:
data/EXAMPLE.md DELETED
@@ -1,213 +0,0 @@
1
- # Hanami::Model
2
-
3
- This is a guide that helps you to get started with [**Hanami::Model**](https://github.com/hanami/model).
4
- You can find the full code source [here](https://gist.github.com/jodosha/11211048).
5
-
6
- ## Gems
7
-
8
- First of all, we need to setup a `Gemfile`.
9
-
10
- ```ruby
11
- source 'https://rubygems.org'
12
-
13
- gem 'sqlite3'
14
- gem 'hanami-model'
15
- ```
16
-
17
- Then we can fetch the dependencies with `bundle install`.
18
-
19
- ## Setup
20
-
21
- <a name="connection-url"></a>
22
-
23
- **Hanami::Model** doesn't have migrations.
24
- For this example we will use [Sequel](http://sequel.jeremyevans.net).
25
- We create the database first.
26
- Then we create two tables: `authors` and `articles`.
27
-
28
- ```ruby
29
- require 'bundler/setup'
30
- require 'sqlite3'
31
- require 'hanami/model'
32
- require 'hanami/model/adapters/sql_adapter'
33
-
34
- connection_uri = "sqlite://#{ __dir__ }/test.db"
35
-
36
- database = Sequel.connect(connection_uri)
37
-
38
- database.create_table! :authors do
39
- primary_key :id
40
- String :name
41
- end
42
-
43
- database.create_table! :articles do
44
- primary_key :id
45
- Integer :author_id, null: false
46
- String :title
47
- Integer :comments_count, default: 0
48
- Boolean :published, default: false
49
- end
50
- ```
51
-
52
- ## Entities
53
-
54
- We have two entities in our application: `Author` and `Article`.
55
- `Author` is a `Struct`, Hanami::Model can persist it.
56
- `Article` has a small API concerning its publishing process.
57
-
58
- ```ruby
59
- Author = Struct.new(:id, :name) do
60
- def initialize(attributes = {})
61
- self.id = attributes[:id]
62
- self.name = attributes[:name]
63
- end
64
- end
65
-
66
- class Article
67
- include Hanami::Entity
68
- attributes :author_id, :title, :comments_count, :published # id is implicit
69
-
70
- def published?
71
- !!published
72
- end
73
-
74
- def publish!
75
- @published = true
76
- end
77
- end
78
- ```
79
-
80
- ## Repositories
81
-
82
- In order to persist and query the entities above, we define two corresponding repositories:
83
-
84
- ```ruby
85
- class AuthorRepository
86
- include Hanami::Repository
87
- end
88
-
89
- class ArticleRepository
90
- include Hanami::Repository
91
-
92
- def self.most_recent_by_author(author, limit = 8)
93
- query do
94
- where(author_id: author.id).
95
- desc(:id).
96
- limit(limit)
97
- end
98
- end
99
-
100
- def self.most_recent_published_by_author(author, limit = 8)
101
- most_recent_by_author(author, limit).published
102
- end
103
-
104
- def self.published
105
- query do
106
- where(published: true)
107
- end
108
- end
109
-
110
- def self.drafts
111
- exclude published
112
- end
113
-
114
- def self.rank
115
- published.desc(:comments_count)
116
- end
117
-
118
- def self.best_article_ever
119
- rank.limit(1).first
120
- end
121
-
122
- def self.comments_average
123
- query.average(:comments_count)
124
- end
125
- end
126
- ```
127
-
128
- ## Loading
129
-
130
- ```ruby
131
- Hanami::Model.configure do
132
- adapter type: :sql, uri: connection_uri
133
-
134
- mapping do
135
- collection :authors do
136
- entity Author
137
- repository AuthorRepository
138
-
139
- attribute :id, Integer
140
- attribute :name, String
141
- end
142
-
143
- collection :articles do
144
- entity Article
145
- repository ArticleRepository
146
-
147
- attribute :id, Integer
148
- attribute :author_id, Integer
149
- attribute :title, String
150
- attribute :comments_count, Integer
151
- attribute :published, Boolean
152
- end
153
- end
154
- end.load!
155
- ```
156
-
157
- ## Persist
158
-
159
- We instantiate and persist an `Author` and a few `Articles` for our example:
160
-
161
- ```ruby
162
- author = Author.new(name: 'Luca')
163
- author = AuthorRepository.create(author)
164
-
165
- articles = [
166
- Article.new(title: 'Announcing Hanami', author_id: author.id, comments_count: 123, published: true),
167
- Article.new(title: 'Introducing Hanami::Router', author_id: author.id, comments_count: 63, published: true),
168
- Article.new(title: 'Introducing Hanami::Controller', author_id: author.id, comments_count: 82, published: true),
169
- Article.new(title: 'Introducing Hanami::Model', author_id: author.id)
170
- ]
171
-
172
- articles.each do |article|
173
- ArticleRepository.create(article)
174
- end
175
- ```
176
-
177
- ## Query
178
-
179
- We use the repositories to query the database and return the entities we're looking for:
180
-
181
- ```ruby
182
- ArticleRepository.first # => return the first article
183
- ArticleRepository.last # => return the last article
184
-
185
- ArticleRepository.published # => return all the published articles
186
- ArticleRepository.drafts # => return all the drafts
187
-
188
- ArticleRepository.rank # => all the published articles, sorted by popularity
189
-
190
- ArticleRepository.best_article_ever # => the most commented article
191
-
192
- ArticleRepository.comments_average # => calculates the average of comments across all the published articles.
193
-
194
- ArticleRepository.most_recent_by_author(author) # => most recent articles by an author (drafts and published).
195
- ArticleRepository.most_recent_published_by_author(author) # => most recent published articles by an author
196
- ```
197
-
198
- ## Business Logic
199
-
200
- As we've seen above, `Article` implements an API for publishing.
201
- We use that logic to alter the state of an article (from draft to published).
202
- We then use the repository to persist this new state.
203
-
204
- ```ruby
205
- article = ArticleRepository.drafts.first
206
-
207
- article.published? # => false
208
- article.publish!
209
-
210
- article.published? # => true
211
-
212
- ArticleRepository.update(article)
213
- ```
@@ -1,74 +0,0 @@
1
- module Hanami
2
- module Entity
3
- # Dirty tracking for entities
4
- #
5
- # @since 0.3.1
6
- #
7
- # @example Dirty tracking
8
- # require 'hanami/model'
9
- #
10
- # class User
11
- # include Hanami::Entity
12
- # include Hanami::Entity::DirtyTracking
13
- #
14
- # attributes :name
15
- # end
16
- #
17
- # article = Article.new(title: 'Generation P')
18
- # article.changed? # => false
19
- #
20
- # article.title = 'Master and Margarita'
21
- # article.changed? # => true
22
- #
23
- # article.changed_attributes # => {:title => "Generation P"}
24
- module DirtyTracking
25
- # Override initialize process.
26
- #
27
- # @param attributes [Hash] a set of attribute names and values
28
- #
29
- # @since 0.3.1
30
- #
31
- # @see Hanami::Entity#initialize
32
- def initialize(attributes = {})
33
- super
34
- @_initial_state = Utils::Hash.new(to_h).deep_dup
35
- end
36
-
37
- # Getter for hash of changed attributes.
38
- # Return empty hash, if there is no changes
39
- # Getter for hash of changed attributes. Value in it is the previous one.
40
- #
41
- # @return [::Hash] the changed attributes
42
- #
43
- # @since 0.3.1
44
- #
45
- # @example
46
- # require 'hanami/model'
47
- #
48
- # class Article
49
- # include Hanami::Entity
50
- # include Hanami::Entity::DirtyTracking
51
- #
52
- # attributes :title
53
- # end
54
- #
55
- # article = Article.new(title: 'The crime and punishment')
56
- # article.changed_attributes # => {}
57
- #
58
- # article.title = 'Master and Margarita'
59
- # article.changed_attributes # => {:title => "The crime and punishment"}
60
- def changed_attributes
61
- Hash[@_initial_state.to_a - to_h.to_a]
62
- end
63
-
64
- # Checks if the attributes were changed
65
- #
66
- # @return [TrueClass, FalseClass] the result of the check
67
- #
68
- # @since 0.3.1
69
- def changed?
70
- changed_attributes.any?
71
- end
72
- end
73
- end
74
- end