hanami-model 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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