upgrow 0.0.2 → 0.0.3

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/upgrow.rb +2 -8
  4. data/lib/upgrow/action.rb +66 -16
  5. data/lib/upgrow/actions.rb +31 -0
  6. data/lib/upgrow/active_record_adapter.rb +24 -15
  7. data/lib/upgrow/active_record_schema.rb +63 -0
  8. data/lib/upgrow/basic_model.rb +64 -0
  9. data/lib/upgrow/basic_repository.rb +49 -22
  10. data/lib/upgrow/error.rb +19 -0
  11. data/lib/upgrow/immutable_object.rb +26 -21
  12. data/lib/upgrow/input.rb +7 -0
  13. data/lib/upgrow/model.rb +12 -12
  14. data/lib/upgrow/model_schema.rb +31 -0
  15. data/lib/upgrow/repository.rb +3 -0
  16. data/lib/upgrow/result.rb +18 -55
  17. data/lib/upgrow/schema.rb +33 -0
  18. data/test/application_system_test_case.rb +11 -0
  19. data/test/dummy/app/actions/application_action.rb +10 -0
  20. data/test/dummy/app/actions/articles/create_action.rb +15 -0
  21. data/test/dummy/app/actions/articles/destroy_action.rb +9 -0
  22. data/test/dummy/app/actions/articles/edit_action.rb +12 -0
  23. data/test/dummy/app/actions/articles/index_action.rb +11 -0
  24. data/test/dummy/app/actions/articles/new_action.rb +8 -0
  25. data/test/dummy/app/actions/articles/show_action.rb +11 -0
  26. data/test/dummy/app/actions/articles/update_action.rb +15 -0
  27. data/test/dummy/app/actions/comments/create_action.rb +15 -0
  28. data/test/dummy/app/actions/comments/destroy_action.rb +9 -0
  29. data/test/dummy/app/actions/comments/new_action.rb +8 -0
  30. data/test/dummy/app/actions/sessions/create_action.rb +23 -0
  31. data/test/dummy/app/actions/sessions/destroy_action.rb +6 -0
  32. data/test/dummy/app/actions/sessions/new_action.rb +8 -0
  33. data/test/dummy/app/actions/user_action.rb +10 -0
  34. data/test/dummy/app/actions/users/create_action.rb +13 -0
  35. data/test/dummy/app/actions/users/new_action.rb +8 -0
  36. data/test/dummy/app/controllers/application_controller.rb +10 -0
  37. data/test/dummy/app/controllers/articles_controller.rb +32 -28
  38. data/test/dummy/app/controllers/comments_controller.rb +41 -0
  39. data/test/dummy/app/controllers/sessions_controller.rb +34 -0
  40. data/test/dummy/app/controllers/users_controller.rb +29 -0
  41. data/test/dummy/app/helpers/application_helper.rb +27 -3
  42. data/test/dummy/app/helpers/users_helper.rb +15 -0
  43. data/test/dummy/app/inputs/article_input.rb +3 -0
  44. data/test/dummy/app/inputs/comment_input.rb +11 -0
  45. data/test/dummy/app/inputs/session_input.rb +9 -0
  46. data/test/dummy/app/inputs/user_input.rb +9 -0
  47. data/test/dummy/app/models/article.rb +0 -2
  48. data/test/dummy/app/models/comment.rb +4 -0
  49. data/test/dummy/app/models/user.rb +4 -0
  50. data/test/dummy/app/records/article_record.rb +2 -0
  51. data/test/dummy/app/records/comment_record.rb +7 -0
  52. data/test/dummy/app/records/user_record.rb +9 -0
  53. data/test/dummy/app/repositories/article_repository.rb +26 -0
  54. data/test/dummy/app/repositories/comment_repository.rb +3 -0
  55. data/test/dummy/app/repositories/user_repository.rb +12 -0
  56. data/test/dummy/config/routes.rb +6 -1
  57. data/test/dummy/db/migrate/20210320140432_create_comments.rb +12 -0
  58. data/test/dummy/db/migrate/20210409164927_create_users.rb +22 -0
  59. data/test/dummy/db/schema.rb +24 -1
  60. data/test/system/articles_test.rb +87 -29
  61. data/test/system/comments_test.rb +81 -0
  62. data/test/system/guest_user_test.rb +14 -0
  63. data/test/system/sign_in_test.rb +57 -0
  64. data/test/system/sign_out_test.rb +19 -0
  65. data/test/system/sign_up_test.rb +38 -0
  66. data/test/test_helper.rb +6 -1
  67. data/test/upgrow/action_test.rb +101 -9
  68. data/test/upgrow/actions_test.rb +24 -0
  69. data/test/upgrow/active_record_adapter_test.rb +12 -17
  70. data/test/upgrow/active_record_schema_test.rb +92 -0
  71. data/test/upgrow/basic_model_test.rb +95 -0
  72. data/test/upgrow/basic_repository_test.rb +48 -27
  73. data/test/upgrow/immutable_object_test.rb +43 -7
  74. data/test/upgrow/input_test.rb +19 -1
  75. data/test/upgrow/model_schema_test.rb +44 -0
  76. data/test/upgrow/model_test.rb +48 -11
  77. data/test/upgrow/result_test.rb +19 -64
  78. data/test/upgrow/schema_test.rb +44 -0
  79. metadata +128 -50
  80. data/test/dummy/app/actions/create_article_action.rb +0 -13
  81. data/test/dummy/app/actions/delete_article_action.rb +0 -7
  82. data/test/dummy/app/actions/edit_article_action.rb +0 -10
  83. data/test/dummy/app/actions/list_articles_action.rb +0 -8
  84. data/test/dummy/app/actions/show_article_action.rb +0 -10
  85. data/test/dummy/app/actions/update_article_action.rb +0 -13
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Article < Upgrow::Model
4
- attribute :title
5
- attribute :body
6
4
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Comment < Upgrow::Model
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class User < Upgrow::Model
4
+ end
@@ -2,4 +2,6 @@
2
2
 
3
3
  class ArticleRecord < ApplicationRecord
4
4
  self.table_name = 'articles'
5
+ has_many :comment_records, foreign_key: :article_id, dependent: :destroy
6
+ belongs_to :user_record, foreign_key: :user_id
5
7
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentRecord < ApplicationRecord
4
+ self.table_name = 'comments'
5
+ belongs_to :user_record, foreign_key: :user_id
6
+ belongs_to :article_record, foreign_key: :article_id
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ class UserRecord < ApplicationRecord
3
+ self.table_name = 'users'
4
+
5
+ has_secure_password
6
+
7
+ has_many :article_records, foreign_key: :user_id, dependent: :destroy
8
+ has_many :comment_records, foreign_key: :user_id, dependent: :destroy
9
+ end
@@ -1,4 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ArticleRepository < Upgrow::Repository
4
+ def all
5
+ base.all.includes(:user_record).map do |record|
6
+ user = to_model(User, record.user_record.attributes)
7
+ to_model(record.attributes.merge(user: user))
8
+ end
9
+ end
10
+
11
+ def find_with_comments(id)
12
+ record = ArticleRecord.find(id)
13
+
14
+ comment_records = record.comment_records.includes(:user_record)
15
+
16
+ comments = comment_records.map do |comment_record|
17
+ user = to_model(User, comment_record.user_record.attributes)
18
+ to_model(Comment, comment_record.attributes.merge(user: user))
19
+ end
20
+
21
+ user = to_model(User, record.user_record.attributes)
22
+
23
+ to_model(record.attributes.merge(comments: comments, user: user))
24
+ end
25
+
26
+ def find_for_user(id, user:)
27
+ record = base.find_by(id: id, user_id: user.id)
28
+ to_model(record.attributes) if record
29
+ end
4
30
  end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ class CommentRepository < Upgrow::Repository
3
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserRepository < Upgrow::Repository
4
+ def find_for_authentication(input)
5
+ record = UserRecord.find_by(email: input.email)
6
+ to_model(record.attributes) if record&.authenticate(input.password)
7
+ end
8
+
9
+ def find_from_context(id)
10
+ UserRecord.find_by(id: id)
11
+ end
12
+ end
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Rails.application.routes.draw do
4
- resources :articles
4
+ resources :articles do
5
+ resources :comments, only: [:new, :create, :destroy]
6
+ end
7
+
8
+ resource :session, only: [:new, :create, :destroy]
9
+ resource :user, only: [:new, :create]
5
10
 
6
11
  root 'articles#index'
7
12
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ class CreateComments < ActiveRecord::Migration[6.1]
3
+ def change
4
+ create_table(:comments) do |t|
5
+ t.references(:article, null: false, foreign_key: true)
6
+ t.string(:author, null: false)
7
+ t.text(:body, null: false)
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ class CreateUsers < ActiveRecord::Migration[6.1]
3
+ def change
4
+ create_table(:users) do |t|
5
+ t.string(:email, null: false)
6
+ t.string(:password_digest, null: false)
7
+
8
+ t.timestamps
9
+
10
+ t.index(:email, unique: true)
11
+ end
12
+
13
+ change_table(:articles) do |t|
14
+ t.references(:user, null: false, foreign_key: true)
15
+ end
16
+
17
+ change_table(:comments) do |t|
18
+ t.remove(:author, type: :string, null: false)
19
+ t.references(:user, null: false, foreign_key: true)
20
+ end
21
+ end
22
+ end
@@ -10,13 +10,36 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2021_02_19_211631) do
13
+ ActiveRecord::Schema.define(version: 2021_04_09_164927) do
14
14
 
15
15
  create_table "articles", force: :cascade do |t|
16
16
  t.string "title", null: false
17
17
  t.text "body", null: false
18
18
  t.datetime "created_at", precision: 6, null: false
19
19
  t.datetime "updated_at", precision: 6, null: false
20
+ t.integer "user_id", null: false
21
+ t.index ["user_id"], name: "index_articles_on_user_id"
20
22
  end
21
23
 
24
+ create_table "comments", force: :cascade do |t|
25
+ t.integer "article_id", null: false
26
+ t.text "body", null: false
27
+ t.datetime "created_at", precision: 6, null: false
28
+ t.datetime "updated_at", precision: 6, null: false
29
+ t.integer "user_id", null: false
30
+ t.index ["article_id"], name: "index_comments_on_article_id"
31
+ t.index ["user_id"], name: "index_comments_on_user_id"
32
+ end
33
+
34
+ create_table "users", force: :cascade do |t|
35
+ t.string "email", null: false
36
+ t.string "password_digest", null: false
37
+ t.datetime "created_at", precision: 6, null: false
38
+ t.datetime "updated_at", precision: 6, null: false
39
+ t.index ["email"], name: "index_users_on_email", unique: true
40
+ end
41
+
42
+ add_foreign_key "articles", "users"
43
+ add_foreign_key "comments", "articles"
44
+ add_foreign_key "comments", "users"
22
45
  end
@@ -3,15 +3,28 @@
3
3
  require 'application_system_test_case'
4
4
 
5
5
  class ArticlesTest < ApplicationSystemTestCase
6
- test 'a message is shown when there are no Articles' do
6
+ setup do
7
7
  visit root_path
8
- assert_title 'Articles'
9
- assert_text 'There are no Articles just yet.'
8
+ end
9
+
10
+ test 'a guest User cannot see the new Article link' do
11
+ assert_no_link 'New Article'
12
+ end
13
+
14
+ test 'a guest User cannot see the new Article page' do
15
+ visit new_article_path
16
+ assert_title 'Sign In'
17
+ end
18
+
19
+ test 'signed in User can see the new Article link' do
20
+ sign_in
21
+ assert_link 'New Article'
10
22
  end
11
23
 
12
24
  test 'Article can be created' do
13
- visit root_path
14
- click_on 'New Article'
25
+ sign_in
26
+
27
+ click_link 'New Article'
15
28
  assert_title 'New Article'
16
29
 
17
30
  fill_in 'Title', with: 'My title'
@@ -20,11 +33,13 @@ class ArticlesTest < ApplicationSystemTestCase
20
33
 
21
34
  assert_text 'Article was successfully created.'
22
35
  assert_title 'My title'
36
+ assert_text 'Author: existing@example.com'
23
37
  assert_text 'My long body'
24
38
  end
25
39
 
26
40
  test 'validation errors are shown' do
27
- visit root_path
41
+ sign_in
42
+
28
43
  click_on 'New Article'
29
44
  click_on 'Create'
30
45
 
@@ -34,8 +49,9 @@ class ArticlesTest < ApplicationSystemTestCase
34
49
  end
35
50
 
36
51
  test 'previously entered data is shown' do
37
- visit root_path
38
- click_on 'New Article'
52
+ sign_in
53
+
54
+ click_link 'New Article'
39
55
  fill_in 'Body', with: 'Short'
40
56
  click_on 'Create'
41
57
 
@@ -44,29 +60,31 @@ class ArticlesTest < ApplicationSystemTestCase
44
60
  end
45
61
 
46
62
  test 'new Article is listed in the index page' do
47
- visit root_path
48
- click_on 'New Article'
63
+ sign_in
64
+
65
+ click_link 'New Article'
49
66
  fill_in 'Title', with: 'My title'
50
67
  fill_in 'Body', with: 'My long body'
51
68
  click_on 'Create'
52
- click_on 'Back'
53
69
 
70
+ visit root_path
54
71
  assert_link 'My title'
72
+ assert_text 'Author: existing@example.com'
55
73
  assert_text 'My long body'
56
74
  end
57
75
 
58
76
  test 'Article can be edited' do
59
- visit root_path
60
- click_on 'New Article'
61
- fill_in 'Title', with: 'My title'
62
- fill_in 'Body', with: 'My long body'
63
- click_on 'Create'
77
+ sign_in
78
+
79
+ click_link 'Lorem Barnak'
64
80
  click_on 'Edit'
65
81
 
66
82
  assert_title 'Edit Article'
67
83
 
68
- assert_field 'Title', with: 'My title'
69
- assert_field 'Body', with: 'My long body'
84
+ assert_field 'Title', with: 'Lorem Barnak'
85
+ assert_field 'Body', with: 'Cimonaque de sacristi de colon de câlique de '\
86
+ "batèche de p'tit Jésus de charogne de marde de patente à gosse de " \
87
+ "sainte-viarge de bout d'crisse de cibouleau de bâtard."
70
88
 
71
89
  fill_in 'Title', with: 'Edited title'
72
90
  fill_in 'Body', with: 'Edited body'
@@ -74,15 +92,14 @@ class ArticlesTest < ApplicationSystemTestCase
74
92
 
75
93
  assert_text 'Article was successfully updated.'
76
94
  assert_title 'Edited title'
95
+ assert_text 'Author: existing@example.com'
77
96
  assert_text 'Edited body'
78
97
  end
79
98
 
80
99
  test 'validation errors are shown when editing Article' do
81
- visit root_path
82
- click_on 'New Article'
83
- fill_in 'Title', with: 'My title'
84
- fill_in 'Body', with: 'My long body'
85
- click_on 'Create'
100
+ sign_in
101
+
102
+ click_on 'Lorem Barnak'
86
103
  click_on 'Edit'
87
104
 
88
105
  fill_in 'Title', with: ''
@@ -95,15 +112,56 @@ class ArticlesTest < ApplicationSystemTestCase
95
112
  assert_field 'Body', with: 'Short'
96
113
  end
97
114
 
115
+ test 'guest User cannot see the edit link' do
116
+ click_link 'Lorem Barnak'
117
+ assert_no_link 'Edit'
118
+ end
119
+
120
+ test 'guest User cannot access the edit page directly' do
121
+ click_link 'Lorem Barnak'
122
+
123
+ visit current_path + '/edit'
124
+
125
+ assert_title 'Sign In'
126
+ end
127
+
128
+ test 'User who is not the author of the Article cannot see its edit link' do
129
+ sign_in
130
+
131
+ click_on 'The Hobbit'
132
+ assert_no_link 'Edit'
133
+ end
134
+
135
+ test 'User who is not the author of the Article cannot access the edit page directly' do
136
+ sign_in
137
+
138
+ click_link 'The Hobbit'
139
+
140
+ visit current_path + '/edit'
141
+
142
+ assert_title 'Sign In'
143
+ end
144
+
98
145
  test 'Article can be deleted' do
99
- visit root_path
100
- click_on 'New Article'
101
- fill_in 'Title', with: 'My title'
102
- fill_in 'Body', with: 'My long body'
103
- click_on 'Create'
146
+ sign_in
147
+
148
+ click_on 'Lorem Barnak'
104
149
  click_on 'Destroy'
105
150
 
151
+ assert_title 'Articles'
106
152
  assert_text 'Article was successfully destroyed'
107
- assert_text 'There are no Articles just yet.'
153
+ assert_no_link 'Lorem Barnak'
154
+ end
155
+
156
+ test 'guest User cannot see the delete button' do
157
+ click_on 'Lorem Barnak'
158
+ assert_no_button 'Destroy'
159
+ end
160
+
161
+ test 'User who is not the author of the Article cannot see its delete link' do
162
+ sign_in
163
+
164
+ click_on 'The Hobbit'
165
+ assert_no_button 'Destroy'
108
166
  end
109
167
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'application_system_test_case'
4
+
5
+ class CommentsTest < ApplicationSystemTestCase
6
+ setup do
7
+ visit root_path
8
+ end
9
+
10
+ test 'a message is shown when there are no Comments' do
11
+ click_on 'Lorem Barnak'
12
+ assert_text 'There are no Comments just yet.'
13
+ end
14
+
15
+ test 'guest can see existing Comment' do
16
+ click_on 'The Hobbit'
17
+ assert_text 'existing@example.com says:'
18
+ assert_text 'I hate everything about this article.'
19
+ end
20
+
21
+ test 'Comment can be created' do
22
+ sign_in
23
+ click_on 'The Hobbit'
24
+
25
+ click_on 'Create Comment'
26
+ fill_in 'Body', with: 'My long comment'
27
+ click_on 'Create'
28
+
29
+ assert_title 'The Hobbit'
30
+ assert_text 'existing@example.com says:'
31
+ assert_text 'My long comment'
32
+ end
33
+
34
+ test 'validation errors are shown' do
35
+ sign_in
36
+ click_on 'The Hobbit'
37
+
38
+ click_on 'Create Comment'
39
+ fill_in 'Body', with: 'Short'
40
+ click_on 'Create'
41
+
42
+ assert_title 'New Comment'
43
+ assert_field 'Body', with: 'Short'
44
+ assert_text 'Body is too short (minimum is 10 characters)'
45
+ end
46
+
47
+ test 'guest cannot see the Create Comment link' do
48
+ click_on 'The Hobbit'
49
+ assert_no_link 'Create Comment'
50
+ end
51
+
52
+ test 'Comment can be deleted' do
53
+ sign_in
54
+ click_on 'The Hobbit'
55
+
56
+ within('.comments') do
57
+ click_on 'Delete'
58
+ end
59
+
60
+ assert_title 'The Hobbit'
61
+ assert_text 'Comment was successfully destroyed'
62
+ assert_text 'There are no Comments just yet.'
63
+ end
64
+
65
+ test 'guest cannot see the delete button' do
66
+ click_on 'The Hobbit'
67
+
68
+ within('.comments') do
69
+ assert_no_button 'Delete'
70
+ end
71
+ end
72
+
73
+ test 'User who is not the author of the comment cannot see the delete button' do
74
+ sign_in(email: 'jrr_tolkien@example.com', password: 'abc345')
75
+ click_on 'The Hobbit'
76
+
77
+ within('.comments') do
78
+ assert_no_button 'Delete'
79
+ end
80
+ end
81
+ end