ru.Bee 1.1.32 → 1.2.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.
- checksums.yaml +4 -4
- data/bin/rubee +30 -12
- data/lib/app/views/welcome_show.erb +2 -0
- data/lib/db/create_accounts.rb +14 -0
- data/lib/db/create_comments.rb +13 -0
- data/lib/db/create_posts.rb +14 -0
- data/lib/db/structure.rb +92 -0
- data/lib/rubee/async/asyncable.rb +1 -1
- data/lib/rubee/models/database_objectable.rb +52 -0
- data/lib/rubee/models/sequel_object.rb +103 -15
- data/lib/rubee.rb +13 -2
- data/lib/tests/account_model_test.rb +19 -0
- data/lib/tests/comment_model_test.rb +35 -0
- data/lib/tests/example_models/account.rb +4 -0
- data/lib/tests/example_models/comment.rb +4 -0
- data/lib/tests/example_models/post.rb +5 -0
- data/lib/tests/example_models/user.rb +4 -0
- data/lib/{db → tests}/test.db +0 -0
- data/lib/tests/test_helper.rb +1 -1
- data/lib/tests/user_model_test.rb +172 -2
- data/readme.md +19 -1
- metadata +13 -4
- data/lib/rubee/models/database_object.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 173d9793c002668ec637f531604481515d4a48b4482280248dfdb9c43e5d6684
|
4
|
+
data.tar.gz: d45bd460ef9db6c347f5b9bca7028fe403d2fb4d35b5ae8649efb2f1528f27f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2bb73fb7408c9261c3fb8f56d4b629805a9a0d04313ca81a6f68f3e19a5faff9c3901010e27dbce8d717161854a36e355dbdb26e81f56cee0c45f9490d43bf6
|
7
|
+
data.tar.gz: 1e241e252e183a725c1152d5ed9b81ef2a7d8fa1593de66361cd7164eaaab5a22678ddd8bc57957cfa5fd4a494bb135925d8c08c4a7835e6028489b1d2b2694f
|
data/bin/rubee
CHANGED
@@ -160,7 +160,7 @@ elsif command == "test"
|
|
160
160
|
color_puts "Running all tests ...", color: :yellow
|
161
161
|
exec("ruby -Itest -e \"Dir.glob('.#{lib}/tests/**/*_test.rb').each { |file| require file }\"")
|
162
162
|
end
|
163
|
-
elsif ['generate', '
|
163
|
+
elsif ['generate', 'gen'].include? command
|
164
164
|
method, path = ARGV[1..2]
|
165
165
|
ENV['RACK_ENV'] ||= 'development'
|
166
166
|
|
@@ -181,9 +181,9 @@ elsif command == "db"
|
|
181
181
|
command, file_name = ARGV[1]&.split(':')
|
182
182
|
if Rubee::PROJECT_NAME == 'rubee'
|
183
183
|
Rubee::Configuration.setup(env=:test) do |config|
|
184
|
-
config.database_url = { url: "sqlite://test.db", env: }
|
184
|
+
config.database_url = { url: "sqlite://lib/tests/test.db", env: }
|
185
185
|
end
|
186
|
-
Rubee::SequelObject.reconnect!
|
186
|
+
Rubee::SequelObject.reconnect! unless command == 'init'
|
187
187
|
end
|
188
188
|
|
189
189
|
def ensure_database_exists(db_url)
|
@@ -193,7 +193,7 @@ elsif command == "db"
|
|
193
193
|
begin
|
194
194
|
Sequel.connect(db_url)
|
195
195
|
color_puts "Database #{ENV['RACK_ENV']} exists", color: :cyan
|
196
|
-
rescue =>
|
196
|
+
rescue Exception => e
|
197
197
|
if File.exist?(db_path = db_url.sub(/^sqlite:\/\//, ''))
|
198
198
|
color_puts "Database #{ENV['RACK_ENV']} exists", color: :cyan
|
199
199
|
else
|
@@ -237,14 +237,22 @@ elsif command == "db"
|
|
237
237
|
end
|
238
238
|
|
239
239
|
|
240
|
-
|
240
|
+
if command == 'run'
|
241
241
|
Rubee::Autoload.call
|
242
|
+
file_names = if file_name == 'all'
|
243
|
+
lib = Rubee::PROJECT_NAME == 'rubee' ? '/lib' : ''
|
244
|
+
Dir.glob(".#{lib}/db/*.rb").map { |file| File.basename(file, '.rb') }.select { |file| file != 'structure' }
|
245
|
+
else
|
246
|
+
[file_name]
|
247
|
+
end
|
242
248
|
Rubee::Configuration.envs.each do |env|
|
243
249
|
ENV['RACK_ENV'] = env.to_s
|
244
|
-
|
245
|
-
|
250
|
+
file_names.each do |file_name|
|
251
|
+
color_puts "Run #{file_name} file for #{env} env", color: :cyan
|
252
|
+
Object.const_get(file_name.split('_').map(&:capitalize).join).new.call
|
253
|
+
end
|
246
254
|
end
|
247
|
-
color_puts "Migration #{file_name} completed", color: :green
|
255
|
+
color_puts "Migration for #{file_name} completed", color: :green
|
248
256
|
unless Rubee::PROJECT_NAME == 'rubee'
|
249
257
|
color_puts "Regenerate schema file", color: :cyan
|
250
258
|
generate_structure
|
@@ -261,15 +269,25 @@ elsif ['console'].include? command
|
|
261
269
|
ENV['RACK_ENV'] ||= 'development'
|
262
270
|
|
263
271
|
Rubee::Autoload.call
|
272
|
+
if Rubee::PROJECT_NAME == 'rubee'
|
273
|
+
Rubee::Configuration.setup(env=:test) do |config|
|
274
|
+
config.database_url = { url: "sqlite://lib/tests/test.db", env: }
|
275
|
+
end
|
276
|
+
Rubee::Autoload.call
|
277
|
+
Rubee::SequelObject.reconnect!
|
278
|
+
end
|
264
279
|
|
265
280
|
def reload
|
266
|
-
app_files = Dir["./#{APP_ROOT}/**/*.rb"]
|
281
|
+
app_files = Dir["./#{Rubee::APP_ROOT}/**/*.rb"]
|
267
282
|
app_files.each { |file| load file }
|
268
283
|
color_puts "Reloaded ..", color: :green
|
269
284
|
end
|
270
|
-
|
271
|
-
|
272
|
-
|
285
|
+
begin
|
286
|
+
# Start IRB
|
287
|
+
IRB.start
|
288
|
+
rescue Exception => e
|
289
|
+
IRB.start
|
290
|
+
end
|
273
291
|
else
|
274
292
|
color_puts "Unknown command: #{command}", color: :red
|
275
293
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateAccounts
|
2
|
+
def call
|
3
|
+
unless Rubee::SequelObject::DB.tables.include?(:accounts)
|
4
|
+
Rubee::SequelObject::DB.create_table :accounts do
|
5
|
+
primary_key :id
|
6
|
+
String :addres
|
7
|
+
foreign_key :user_id, :users
|
8
|
+
end
|
9
|
+
|
10
|
+
Account.create(addres: "13th Ave, NY", user_id: User.all.first.id)
|
11
|
+
Account.create(addres: "14th Ave, NY", user_id: User.all.last.id)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateComments
|
2
|
+
def call
|
3
|
+
unless Rubee::SequelObject::DB.tables.include?(:comments)
|
4
|
+
Rubee::SequelObject::DB.create_table :comments do
|
5
|
+
primary_key :id
|
6
|
+
String :text
|
7
|
+
Integer :user_id
|
8
|
+
end
|
9
|
+
|
10
|
+
User.create(email: "ok@ok.com", password: "password")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreatePosts
|
2
|
+
def call
|
3
|
+
unless Rubee::SequelObject::DB.tables.include?(:posts)
|
4
|
+
Rubee::SequelObject::DB.create_table :posts do
|
5
|
+
primary_key :id
|
6
|
+
foreign_key :user_id, :users
|
7
|
+
foreign_key :comment_id, :comments
|
8
|
+
end
|
9
|
+
|
10
|
+
Post.create(user_id: User.all.first.id, comment_id: Comment.all.first.id)
|
11
|
+
Post.create(user_id: User.all.last.id, comment_id: Comment.all.last.id)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/db/structure.rb
CHANGED
@@ -30,5 +30,97 @@ STRUCTURE = {
|
|
30
30
|
ruby_default: nil,
|
31
31
|
max_length: 255
|
32
32
|
}
|
33
|
+
},
|
34
|
+
accounts: {
|
35
|
+
id: {
|
36
|
+
generated: false,
|
37
|
+
allow_null: false,
|
38
|
+
default: nil,
|
39
|
+
db_type: "INTEGER",
|
40
|
+
primary_key: true,
|
41
|
+
auto_increment: true,
|
42
|
+
type: "integer",
|
43
|
+
ruby_default: nil
|
44
|
+
},
|
45
|
+
addres: {
|
46
|
+
generated: false,
|
47
|
+
allow_null: true,
|
48
|
+
default: nil,
|
49
|
+
db_type: "varchar(255)",
|
50
|
+
primary_key: false,
|
51
|
+
type: "string",
|
52
|
+
ruby_default: nil,
|
53
|
+
max_length: 255
|
54
|
+
},
|
55
|
+
user_id: {
|
56
|
+
generated: false,
|
57
|
+
allow_null: true,
|
58
|
+
default: nil,
|
59
|
+
db_type: "INTEGER",
|
60
|
+
primary_key: false,
|
61
|
+
type: "integer",
|
62
|
+
ruby_default: nil
|
63
|
+
}
|
64
|
+
},
|
65
|
+
posts: {
|
66
|
+
id: {
|
67
|
+
generated: false,
|
68
|
+
allow_null: false,
|
69
|
+
default: nil,
|
70
|
+
db_type: "INTEGER",
|
71
|
+
primary_key: true,
|
72
|
+
auto_increment: true,
|
73
|
+
type: "integer",
|
74
|
+
ruby_default: nil
|
75
|
+
},
|
76
|
+
user_id: {
|
77
|
+
generated: false,
|
78
|
+
allow_null: true,
|
79
|
+
default: nil,
|
80
|
+
db_type: "INTEGER",
|
81
|
+
primary_key: false,
|
82
|
+
type: "integer",
|
83
|
+
ruby_default: nil
|
84
|
+
},
|
85
|
+
comment_id: {
|
86
|
+
generated: false,
|
87
|
+
allow_null: true,
|
88
|
+
default: nil,
|
89
|
+
db_type: "INTEGER",
|
90
|
+
primary_key: false,
|
91
|
+
type: "integer",
|
92
|
+
ruby_default: nil
|
93
|
+
}
|
94
|
+
},
|
95
|
+
comments: {
|
96
|
+
id: {
|
97
|
+
generated: false,
|
98
|
+
allow_null: false,
|
99
|
+
default: nil,
|
100
|
+
db_type: "INTEGER",
|
101
|
+
primary_key: true,
|
102
|
+
auto_increment: true,
|
103
|
+
type: "integer",
|
104
|
+
ruby_default: nil
|
105
|
+
},
|
106
|
+
text: {
|
107
|
+
generated: false,
|
108
|
+
allow_null: true,
|
109
|
+
default: nil,
|
110
|
+
db_type: "varchar(255)",
|
111
|
+
primary_key: false,
|
112
|
+
type: "string",
|
113
|
+
ruby_default: nil,
|
114
|
+
max_length: 255
|
115
|
+
},
|
116
|
+
user_id: {
|
117
|
+
generated: false,
|
118
|
+
allow_null: true,
|
119
|
+
default: nil,
|
120
|
+
db_type: "INTEGER",
|
121
|
+
primary_key: false,
|
122
|
+
type: "integer",
|
123
|
+
ruby_default: nil
|
124
|
+
}
|
33
125
|
}
|
34
126
|
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rubee
|
2
|
+
module DatabaseObjectable
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.include InstanceMethods
|
6
|
+
base.prepend Initializer
|
7
|
+
|
8
|
+
base.include Rubee::Hookable
|
9
|
+
base.include Rubee::Serializable
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def pluralize_class_name
|
14
|
+
pluralize(self.name.downcase)
|
15
|
+
end
|
16
|
+
|
17
|
+
def pluralize(word)
|
18
|
+
if word.end_with?('y') && !%w[a e i o u].include?(word[-2])
|
19
|
+
word[0..-2] + 'ies' # Replace "y" with "ies"
|
20
|
+
elsif word.end_with?('s', 'x', 'z', 'ch', 'sh')
|
21
|
+
word + 'es' # Add "es" for certain endings
|
22
|
+
else
|
23
|
+
word + 's' # Default to adding "s"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def singularize(word)
|
28
|
+
if word.end_with?('ies') && word.length > 3
|
29
|
+
word[0..-4] + 'y' # Convert "ies" to "y"
|
30
|
+
elsif word.end_with?('es') && %w[s x z ch sh].any? { |ending| word[-(ending.length + 2)..-3] == ending }
|
31
|
+
word[0..-3] # Remove "es" for words like "foxes", "buses"
|
32
|
+
elsif word.end_with?('s') && word.length > 1
|
33
|
+
word[0..-2] # Remove "s" for regular plurals
|
34
|
+
else
|
35
|
+
word # Return as-is if no plural form is detected
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def accessor_names
|
40
|
+
instance_methods(false)
|
41
|
+
.select { |m| method_defined?("#{m}=") } # Check if setter exists
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceMethods
|
46
|
+
end
|
47
|
+
|
48
|
+
module Initializer
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -1,9 +1,21 @@
|
|
1
1
|
module Rubee
|
2
|
-
class SequelObject
|
3
|
-
|
4
|
-
|
5
|
-
def destroy
|
6
|
-
|
2
|
+
class SequelObject
|
3
|
+
include Rubee::DatabaseObjectable
|
4
|
+
|
5
|
+
def destroy(cascade: false, **options)
|
6
|
+
if cascade
|
7
|
+
# find all tables with foreign key
|
8
|
+
tables_with_fk = DB.tables.select do |table|
|
9
|
+
DB.foreign_key_list(table).any? { |fk| fk[:table] == self.class.pluralize_class_name.to_sym }
|
10
|
+
end
|
11
|
+
# destroy related records
|
12
|
+
tables_with_fk.each do |table|
|
13
|
+
fk_name ||= "#{self.class.name.to_s.downcase}_id".to_sym
|
14
|
+
target_klass = Object.const_get(self.class.singularize(table.to_s).capitalize)
|
15
|
+
target_klass.where(fk_name => id).map(&:destroy)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
self.class.dataset.where(id:).delete
|
7
19
|
end
|
8
20
|
|
9
21
|
def save
|
@@ -28,7 +40,7 @@ module Rubee
|
|
28
40
|
|
29
41
|
def update(args = {})
|
30
42
|
assign_attributes(args)
|
31
|
-
found_hash = self.class.
|
43
|
+
found_hash = self.class.dataset.where(id:)
|
32
44
|
return self.class.find(id) if found_hash&.update(**args)
|
33
45
|
|
34
46
|
false
|
@@ -44,46 +56,122 @@ module Rubee
|
|
44
56
|
|
45
57
|
class << self
|
46
58
|
def last
|
47
|
-
found_hash =
|
59
|
+
found_hash = dataset.order(:id).last
|
60
|
+
return self.new(**found_hash) if found_hash
|
61
|
+
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def first
|
66
|
+
found_hash = dataset.order(:id).first
|
48
67
|
return self.new(**found_hash) if found_hash
|
49
68
|
|
50
69
|
nil
|
51
70
|
end
|
52
71
|
|
72
|
+
# ## User
|
73
|
+
# owns_many :comments
|
74
|
+
# > user.comments
|
75
|
+
# > [<comment1>, <comment2>]
|
76
|
+
def owns_many(assoc, fk_name: nil, over: nil, **options)
|
77
|
+
singularized_assoc_name = singularize(assoc.to_s)
|
78
|
+
fk_name ||= "#{self.name.to_s.downcase}_id"
|
79
|
+
|
80
|
+
define_method(assoc) do
|
81
|
+
klass = Object.const_get(singularized_assoc_name.capitalize)
|
82
|
+
if over
|
83
|
+
sequel_dataset = klass
|
84
|
+
.join(over.to_sym, "#{singularized_assoc_name}_id".to_sym => :id)
|
85
|
+
.where(fk_name.to_sym => id)
|
86
|
+
self.class.serialize(sequel_dataset, klass)
|
87
|
+
else
|
88
|
+
klass.where(fk_name.to_sym => id)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# ## Comment
|
94
|
+
# owns_one :user
|
95
|
+
# > comment.user
|
96
|
+
# > <user>
|
97
|
+
def owns_one(assoc, options={})
|
98
|
+
Sequel::Model.one_to_one(assoc, **options)
|
99
|
+
fk_name ||= "#{self.name.to_s.downcase}_id"
|
100
|
+
define_method(assoc) do
|
101
|
+
Object.const_get(assoc.capitalize).where(fk_name.to_sym => id)&.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# ## Account
|
106
|
+
# holds :user
|
107
|
+
# > account.user
|
108
|
+
# > <user>
|
109
|
+
def holds(assoc, fk_name: nil, **options)
|
110
|
+
fk_name ||= "#{assoc.to_s.downcase}_id"
|
111
|
+
define_method(assoc) do
|
112
|
+
target_klass = Object.const_get(assoc.capitalize)
|
113
|
+
target_klass.find(self.send(fk_name))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
53
117
|
def reconnect!
|
118
|
+
return if defined?(DB) && !DB.nil?
|
119
|
+
|
54
120
|
const_set(:DB, Sequel.connect(Rubee::Configuration.get_database_url))
|
55
121
|
end
|
56
122
|
|
57
|
-
def
|
58
|
-
@
|
123
|
+
def dataset
|
124
|
+
@dataset ||= DB[pluralize_class_name.to_sym]
|
125
|
+
rescue Exception => _
|
126
|
+
reconnect!
|
127
|
+
retry
|
59
128
|
end
|
60
129
|
|
61
130
|
def all
|
62
|
-
|
131
|
+
dataset.map do |record_hash|
|
63
132
|
self.new(**record_hash)
|
64
133
|
end
|
65
134
|
end
|
66
135
|
|
67
136
|
def find(id)
|
68
|
-
found_hash =
|
137
|
+
found_hash = dataset.where(id:)&.first
|
69
138
|
return self.new(**found_hash) if found_hash
|
70
139
|
|
71
140
|
nil
|
72
141
|
end
|
73
142
|
|
74
143
|
def where(args)
|
75
|
-
|
144
|
+
dataset.where(**args).map do |record_hash|
|
145
|
+
self.new(**record_hash)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def order(*args)
|
150
|
+
dataset.order(*args).map do |record_hash|
|
76
151
|
self.new(**record_hash)
|
77
152
|
end
|
78
153
|
end
|
79
154
|
|
155
|
+
def join(assoc, args)
|
156
|
+
dataset.join(assoc, **args)
|
157
|
+
end
|
158
|
+
|
80
159
|
def create(attrs)
|
81
|
-
out_id =
|
160
|
+
out_id = dataset.insert(**attrs)
|
82
161
|
self.new(**(attrs.merge(id: out_id)))
|
83
162
|
end
|
84
163
|
|
85
|
-
def destroy_all
|
86
|
-
all.each(
|
164
|
+
def destroy_all(cascade: false)
|
165
|
+
all.each{ |record| record.destroy(cascade:) }
|
166
|
+
end
|
167
|
+
|
168
|
+
def serialize(suquel_dataset, klass = nil)
|
169
|
+
klass ||= self
|
170
|
+
suquel_dataset.map do |record_hash|
|
171
|
+
target_klass_fields = DB[pluralize(klass.name.downcase).to_sym].columns
|
172
|
+
klass_attributes = record_hash.filter{ target_klass_fields.include? _1 }
|
173
|
+
klass.new(**klass_attributes)
|
174
|
+
end
|
87
175
|
end
|
88
176
|
end
|
89
177
|
end
|
data/lib/rubee.rb
CHANGED
@@ -8,7 +8,7 @@ module Rubee
|
|
8
8
|
APP_ROOT = File.expand_path(Dir.pwd) unless defined?(APP_ROOT)
|
9
9
|
IMAGE_DIR = File.join(APP_ROOT, 'images') unless defined?(IMAGE_DIR)
|
10
10
|
PROJECT_NAME = File.basename(APP_ROOT) unless defined?(PROJECT_NAME)
|
11
|
-
VERSION = '1.
|
11
|
+
VERSION = '1.2.0'
|
12
12
|
|
13
13
|
class Application
|
14
14
|
include Singleton
|
@@ -123,6 +123,8 @@ module Rubee
|
|
123
123
|
# autoload all rbs
|
124
124
|
root_directory = File.dirname(__FILE__)
|
125
125
|
priority_order_require(root_directory, black_list)
|
126
|
+
# ensure sequel object is connected
|
127
|
+
Rubee::SequelObject.reconnect!
|
126
128
|
|
127
129
|
Dir.glob(File.join(APP_ROOT, '**', '*.rb')).sort.each do |file|
|
128
130
|
base_name = File.basename(file)
|
@@ -149,6 +151,15 @@ module Rubee
|
|
149
151
|
# app config and routes
|
150
152
|
lib = PROJECT_NAME == 'rubee' ? 'lib/' : ''
|
151
153
|
require_relative File.join(APP_ROOT, lib, "config/base_configuration") unless black_list.include?('base_configuration.rb')
|
154
|
+
# This is necessary prerequisitedb init step
|
155
|
+
unless defined?(Rubee::SequelObject::DB)
|
156
|
+
if PROJECT_NAME == 'rubee'
|
157
|
+
Rubee::Configuration.setup(env=:test) do |config|
|
158
|
+
config.database_url = { url: "sqlite://lib/tests/test.db", env: }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
152
163
|
require_relative File.join(APP_ROOT, lib, "config/routes") unless black_list.include?('routes.rb')
|
153
164
|
# rubee extensions
|
154
165
|
Dir[File.join(root_directory, "rubee/extensions/**", '*.rb')].each do |file|
|
@@ -163,7 +174,7 @@ module Rubee
|
|
163
174
|
end
|
164
175
|
require_relative File.join(root_directory, "rubee/controllers/base_controller") unless black_list.include?('base_controller.rb')
|
165
176
|
# rubee models
|
166
|
-
require_relative File.join(root_directory, "rubee/models/
|
177
|
+
require_relative File.join(root_directory, "rubee/models/database_objectable") unless black_list.include?('database_objectable.rb')
|
167
178
|
require_relative File.join(root_directory, "rubee/models/sequel_object") unless black_list.include?('sequel_object.rb')
|
168
179
|
end
|
169
180
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe 'Account model' do
|
4
|
+
describe 'holds :user' do
|
5
|
+
after do
|
6
|
+
Account.destroy_all cascade: true
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'when it holds user_id' do
|
10
|
+
it 'returns associated User record' do
|
11
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
12
|
+
user.save
|
13
|
+
account = Account.new(user_id: user.id, addres: "test")
|
14
|
+
account.save
|
15
|
+
_(account.user.id).must_equal user.id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe 'Comment model' do
|
4
|
+
describe 'owns_many :users, over: :posts' do
|
5
|
+
before do
|
6
|
+
comment = Comment.new(text: "test")
|
7
|
+
comment.save
|
8
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
9
|
+
user.save
|
10
|
+
post = Post.new(user_id: user.id, comment_id: comment.id)
|
11
|
+
post.save
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
Comment.destroy_all cascade: true
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'when there are associated comment records' do
|
19
|
+
it 'returns all records' do
|
20
|
+
_(Comment.where(text: "test").last.users.count).must_equal 1
|
21
|
+
_(Comment.where(text: "test").last.users.first.email).must_equal "ok-test@test.com"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'sequel dataset query' do
|
26
|
+
it 'returns all records' do
|
27
|
+
result = Comment.dataset.join(:posts, comment_id: :id)
|
28
|
+
.where(comment_id: Comment.where(text: "test").last.id)
|
29
|
+
.then { |dataset| Comment.serialize(dataset) }
|
30
|
+
|
31
|
+
_(result.first.text).must_equal "test"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/{db → tests}/test.db
RENAMED
Binary file
|
data/lib/tests/test_helper.rb
CHANGED
@@ -7,7 +7,7 @@ require_relative '../../lib/rubee'
|
|
7
7
|
|
8
8
|
Rubee::Autoload.call
|
9
9
|
Rubee::Configuration.setup(env=:test) do |config|
|
10
|
-
config.database_url = { url: "sqlite://test.db", env: }
|
10
|
+
config.database_url = { url: "sqlite://lib/tests/test.db", env: }
|
11
11
|
end
|
12
12
|
Rubee::SequelObject.reconnect!
|
13
13
|
|
@@ -3,7 +3,7 @@ require_relative 'test_helper'
|
|
3
3
|
describe 'User model' do
|
4
4
|
describe ".create" do
|
5
5
|
after do
|
6
|
-
User.destroy_all
|
6
|
+
User.destroy_all cascade: true
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'when data is valid' do
|
@@ -26,7 +26,7 @@ describe 'User model' do
|
|
26
26
|
|
27
27
|
describe '.save' do
|
28
28
|
after do
|
29
|
-
User.destroy_all
|
29
|
+
User.destroy_all cascade: true
|
30
30
|
end
|
31
31
|
|
32
32
|
describe 'when data is valid' do
|
@@ -57,4 +57,174 @@ describe 'User model' do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
describe '.update' do
|
62
|
+
after do
|
63
|
+
User.destroy_all cascade: true
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'when data is valid' do
|
67
|
+
it 'persists to db' do
|
68
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
69
|
+
user.save
|
70
|
+
user.update(password: "1234")
|
71
|
+
|
72
|
+
_(user.reload.password).must_equal "1234"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '.destroy' do
|
78
|
+
after do
|
79
|
+
User.destroy_all cascade: true
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'when there is no related recrods' do
|
83
|
+
it 'delete the record' do
|
84
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
85
|
+
user.save
|
86
|
+
user.destroy
|
87
|
+
|
88
|
+
assert_nil user.reload
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'when there are related recrods' do
|
93
|
+
it 'does not delete the record' do
|
94
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
95
|
+
user.save
|
96
|
+
Account.new(user_id: user.id, addres: "test").save
|
97
|
+
user.destroy rescue nil
|
98
|
+
|
99
|
+
_(user.reload.id).must_equal user.id
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'when there are related recrods but passed cascade=true' do
|
104
|
+
it 'deletes the record' do
|
105
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
106
|
+
user.save
|
107
|
+
Account.new(user_id: user.id, addres: "test").save
|
108
|
+
user.destroy cascade: true
|
109
|
+
|
110
|
+
assert_nil user.reload
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '.find' do
|
116
|
+
after do
|
117
|
+
User.destroy_all cascade: true
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'when trhere is a record' do
|
121
|
+
it 'returns a record' do
|
122
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
123
|
+
user.save
|
124
|
+
_(User.find(user.id).email).must_equal user.email
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'when there is no record' do
|
129
|
+
it 'returns nil' do
|
130
|
+
assert_nil User.find(1)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '.all' do
|
136
|
+
after do
|
137
|
+
User.destroy_all cascade: true
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'when there are records' do
|
141
|
+
it 'returns all records' do
|
142
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
143
|
+
user2 = User.new(email: "ok-test2@test.com", password: "123")
|
144
|
+
user.save
|
145
|
+
user2.save
|
146
|
+
_(User.all.count).must_equal 2
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '.where' do
|
152
|
+
after do
|
153
|
+
User.destroy_all cascade: true
|
154
|
+
end
|
155
|
+
|
156
|
+
describe 'when there are records' do
|
157
|
+
it 'returns all records' do
|
158
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
159
|
+
user2 = User.new(email: "ok-test2@test.com", password: "123")
|
160
|
+
user.save
|
161
|
+
user2.save
|
162
|
+
_(User.where(email: "ok-test2@test.com").count).must_equal 1
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe '.first' do
|
168
|
+
after do
|
169
|
+
User.destroy_all cascade: true
|
170
|
+
end
|
171
|
+
|
172
|
+
describe 'when there are records' do
|
173
|
+
it 'returns first record' do
|
174
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
175
|
+
user2 = User.new(email: "ok-test2@test.com", password: "123")
|
176
|
+
user.save
|
177
|
+
user2.save
|
178
|
+
_(User.first.email).must_equal user.email
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '.last' do
|
184
|
+
after do
|
185
|
+
User.destroy_all cascade: true
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'when there are records' do
|
189
|
+
it 'returns last record' do
|
190
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
191
|
+
user2 = User.new(email: "ok-test2@test.com", password: "123")
|
192
|
+
user.save
|
193
|
+
user2.save
|
194
|
+
_(User.last.email).must_equal user2.email
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe '.order' do
|
200
|
+
after do
|
201
|
+
User.destroy_all cascade: true
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'when there are records' do
|
205
|
+
it 'returns ordered records' do
|
206
|
+
user = User.new(email: "abc@test.com", password: "123")
|
207
|
+
user2 = User.new(email: "defg@test.com", password: "123")
|
208
|
+
user.save
|
209
|
+
user2.save
|
210
|
+
_(User.order(:email).first.email).must_equal user.email
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe 'owns_many' do
|
216
|
+
after do
|
217
|
+
User.destroy_all cascade: true
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'when there are associated account records' do
|
221
|
+
it 'returns all records' do
|
222
|
+
user = User.new(email: "ok-test@test.com", password: "123")
|
223
|
+
user.save
|
224
|
+
account = Account.new(user_id: user.id, addres: "test")
|
225
|
+
account.save
|
226
|
+
_(user.accounts.count).must_equal 1
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
60
230
|
end
|
data/readme.md
CHANGED
@@ -107,7 +107,7 @@ Here below is a simple example on how it can be used by rendering json from in m
|
|
107
107
|
|
108
108
|
def show
|
109
109
|
# in memory example
|
110
|
-
|
110
|
+
apples = [Apple.new(colour: 'red', weight: '1lb'), Apple.new(colour: 'green', weight: '1lb')]
|
111
111
|
apple = apples.find { |apple| apple.colour = params[:colour] }
|
112
112
|
|
113
113
|
response_with object: apple, type: :json
|
@@ -128,6 +128,24 @@ However, you can simply turn it to ORM object by extending database class.
|
|
128
128
|
attr_accessor :id, :colour, :weight
|
129
129
|
end
|
130
130
|
```
|
131
|
+
Rubee::SequelObject methods:
|
132
|
+
|
133
|
+
- `apple.save`
|
134
|
+
- `apple.destroy(cascade: true)` # default false
|
135
|
+
- `apple.destroy_all`
|
136
|
+
- `apple.update(colour: 'red')`
|
137
|
+
- `apple.persisted?`
|
138
|
+
- `apple.reload`
|
139
|
+
- `apple.assign_attributes(colour: 'red', weight: '1lb')`
|
140
|
+
- `Apple.last`
|
141
|
+
- `Apple.where(colour: 'red')`
|
142
|
+
- `Apple.last`
|
143
|
+
- `Apple.all`
|
144
|
+
- `Apple.create(colour: 'red', weight: '1lb')`
|
145
|
+
- `Apple.destroy_all`
|
146
|
+
- `Apple.serialize`
|
147
|
+
- `Apple.serialize(Apple.dataset.joins(:trees).where(tree: { colour: 'brown' }))`
|
148
|
+
...
|
131
149
|
|
132
150
|
So in the controller you would need to query your target object now.
|
133
151
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ru.Bee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Saltykov
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-31 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bundler
|
@@ -47,9 +47,11 @@ files:
|
|
47
47
|
- lib/config.ru
|
48
48
|
- lib/config/base_configuration.rb
|
49
49
|
- lib/config/routes.rb
|
50
|
+
- lib/db/create_accounts.rb
|
51
|
+
- lib/db/create_comments.rb
|
52
|
+
- lib/db/create_posts.rb
|
50
53
|
- lib/db/create_users.rb
|
51
54
|
- lib/db/structure.rb
|
52
|
-
- lib/db/test.db
|
53
55
|
- lib/images/rubee.svg
|
54
56
|
- lib/inits/print_colors.rb
|
55
57
|
- lib/rubee.rb
|
@@ -63,10 +65,17 @@ files:
|
|
63
65
|
- lib/rubee/controllers/middlewares/auth_token_middleware.rb
|
64
66
|
- lib/rubee/extensions/hookable.rb
|
65
67
|
- lib/rubee/extensions/serializable.rb
|
66
|
-
- lib/rubee/models/
|
68
|
+
- lib/rubee/models/database_objectable.rb
|
67
69
|
- lib/rubee/models/sequel_object.rb
|
70
|
+
- lib/tests/account_model_test.rb
|
68
71
|
- lib/tests/auth_tokenable_test.rb
|
72
|
+
- lib/tests/comment_model_test.rb
|
73
|
+
- lib/tests/example_models/account.rb
|
74
|
+
- lib/tests/example_models/comment.rb
|
75
|
+
- lib/tests/example_models/post.rb
|
76
|
+
- lib/tests/example_models/user.rb
|
69
77
|
- lib/tests/rubeeapp_test.rb
|
78
|
+
- lib/tests/test.db
|
70
79
|
- lib/tests/test_helper.rb
|
71
80
|
- lib/tests/user_model_test.rb
|
72
81
|
- readme.md
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Rubee
|
2
|
-
class DatabaseObject
|
3
|
-
include Serializable
|
4
|
-
include Hookable
|
5
|
-
|
6
|
-
def destroy
|
7
|
-
end
|
8
|
-
|
9
|
-
def save
|
10
|
-
end
|
11
|
-
|
12
|
-
def update(args = {})
|
13
|
-
end
|
14
|
-
|
15
|
-
def reload
|
16
|
-
end
|
17
|
-
|
18
|
-
class << self
|
19
|
-
def last
|
20
|
-
end
|
21
|
-
|
22
|
-
def connection
|
23
|
-
end
|
24
|
-
|
25
|
-
def all
|
26
|
-
end
|
27
|
-
|
28
|
-
def find(id)
|
29
|
-
end
|
30
|
-
|
31
|
-
def where(args)
|
32
|
-
end
|
33
|
-
|
34
|
-
def create(attrs)
|
35
|
-
end
|
36
|
-
|
37
|
-
def pluralize_class_name
|
38
|
-
word = self.name.downcase
|
39
|
-
# Basic pluralization rules
|
40
|
-
if word.end_with?('y') && !%w[a e i o u].include?(word[-2])
|
41
|
-
word[0..-2] + 'ies' # Replace "y" with "ies"
|
42
|
-
elsif word.end_with?('s', 'x', 'z', 'ch', 'sh')
|
43
|
-
word + 'es' # Add "es" for certain endings
|
44
|
-
else
|
45
|
-
word + 's' # Default to adding "s"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|