baza_models 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +35 -0
- data/Gemfile +9 -3
- data/Gemfile.lock +90 -51
- data/README.md +98 -3
- data/Rakefile +20 -17
- data/VERSION +1 -1
- data/baza_models.gemspec +149 -0
- data/config/best_project_practice_rubocop.yml +2 -0
- data/config/best_project_practice_rubocop_todo.yml +35 -0
- data/lib/baza_models.rb +15 -0
- data/lib/baza_models/autoloader.rb +135 -0
- data/lib/baza_models/baza_orm_adapter.rb +39 -0
- data/lib/baza_models/can_can_adapter.rb +9 -0
- data/lib/baza_models/class_translation.rb +44 -0
- data/lib/baza_models/errors.rb +24 -2
- data/lib/baza_models/model.rb +236 -115
- data/lib/baza_models/model/belongs_to_relations.rb +49 -0
- data/lib/baza_models/model/custom_validations.rb +24 -0
- data/lib/baza_models/model/delegation.rb +21 -0
- data/lib/baza_models/model/has_many_relations.rb +85 -0
- data/lib/baza_models/model/has_one_relations.rb +93 -0
- data/lib/baza_models/model/manipulation.rb +123 -0
- data/lib/baza_models/model/queries.rb +45 -0
- data/lib/baza_models/model/scopes.rb +19 -0
- data/lib/baza_models/model/translation_functionality.rb +30 -0
- data/lib/baza_models/model/validations.rb +95 -0
- data/lib/baza_models/query.rb +447 -0
- data/lib/baza_models/query/inspector.rb +74 -0
- data/lib/baza_models/query/not.rb +34 -0
- data/lib/baza_models/ransacker.rb +30 -0
- data/lib/baza_models/test_database_cleaner.rb +23 -0
- data/lib/baza_models/validators/base_validator.rb +14 -0
- data/lib/baza_models/validators/confirmation_validator.rb +12 -0
- data/lib/baza_models/validators/format_validator.rb +11 -0
- data/lib/baza_models/validators/length_validator.rb +16 -0
- data/lib/baza_models/validators/uniqueness_validator.rb +21 -0
- data/shippable.yml +3 -1
- data/spec/baza_models/autoloader_spec.rb +57 -0
- data/spec/baza_models/baza_orm_adapter_spec.rb +52 -0
- data/spec/baza_models/class_translation_spec.rb +25 -0
- data/spec/baza_models/factory_girl_spec.rb +13 -0
- data/spec/baza_models/model/belongs_to_relations_spec.rb +26 -0
- data/spec/baza_models/model/custom_validations_spec.rb +18 -0
- data/spec/baza_models/model/delgation_spec.rb +16 -0
- data/spec/baza_models/model/has_many_relations_spec.rb +68 -0
- data/spec/baza_models/model/has_one_relations_spec.rb +35 -0
- data/spec/baza_models/model/manipulation_spec.rb +25 -0
- data/spec/baza_models/model/queries_spec.rb +59 -0
- data/spec/baza_models/model/scopes_spec.rb +23 -0
- data/spec/baza_models/model/translate_functionality_spec.rb +13 -0
- data/spec/baza_models/model/validations_spec.rb +52 -0
- data/spec/baza_models/model_spec.rb +75 -98
- data/spec/baza_models/query/not_spec.rb +16 -0
- data/spec/baza_models/query_spec.rb +155 -0
- data/spec/baza_models/ransacker_spec.rb +15 -0
- data/spec/baza_models/validators/confirmation_validator_spec.rb +28 -0
- data/spec/baza_models/validators/format_validator_spec.rb +17 -0
- data/spec/baza_models/validators/length_validator_spec.rb +19 -0
- data/spec/baza_models/validators/uniqueness_validator_spec.rb +24 -0
- data/spec/factories/organization.rb +5 -0
- data/spec/factories/user.rb +7 -0
- data/spec/spec_helper.rb +17 -5
- data/spec/support/database_helper.rb +87 -0
- data/spec/test_classes/organization.rb +3 -0
- data/spec/test_classes/person.rb +3 -0
- data/spec/test_classes/role.rb +12 -0
- data/spec/test_classes/user.rb +40 -0
- data/spec/test_classes/user_passport.rb +3 -0
- metadata +146 -7
- data/spec/test_classes/user_test.rb +0 -17
@@ -0,0 +1,74 @@
|
|
1
|
+
class BazaModels::Query::Inspector
|
2
|
+
def initialize(args)
|
3
|
+
@query = args.fetch(:query)
|
4
|
+
@model = args.fetch(:model)
|
5
|
+
@argument = args.fetch(:argument)
|
6
|
+
@joins = args.fetch(:joins)
|
7
|
+
@joins_tracker = args.fetch(:joins_tracker)
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
inspect_argument(@argument)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def inspect_argument(argument)
|
17
|
+
if argument.is_a?(Hash)
|
18
|
+
inspect_hash(argument)
|
19
|
+
elsif argument.is_a?(Array)
|
20
|
+
argument.each do |argument_i|
|
21
|
+
inspect_argument(argument_i)
|
22
|
+
end
|
23
|
+
elsif argument.is_a?(Symbol)
|
24
|
+
inspect_symbol(argument)
|
25
|
+
elsif argument.is_a?(String)
|
26
|
+
inspect_string(argument)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect_string(argument)
|
31
|
+
@joins << argument
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect_symbol(argument)
|
35
|
+
return if @joins_tracker.include?(argument)
|
36
|
+
|
37
|
+
relationship_pair = @model.relationships.detect { |key, _value| key == argument }
|
38
|
+
raise "Could not find a relationship on #{@model.name} by that name: #{argument}" unless relationship_pair
|
39
|
+
relationship = relationship_pair[1]
|
40
|
+
|
41
|
+
table_name = relationship.fetch(:table_name)
|
42
|
+
|
43
|
+
if relationship.fetch(:type) == :belongs_to
|
44
|
+
column_left = :id
|
45
|
+
column_right = relationship.fetch(:foreign_key)
|
46
|
+
else
|
47
|
+
column_left = relationship.fetch(:foreign_key)
|
48
|
+
column_right = :id
|
49
|
+
end
|
50
|
+
|
51
|
+
orig_table = @model.table_name
|
52
|
+
|
53
|
+
@joins << "INNER JOIN `#{table_name}` ON `#{table_name}`.`#{column_left}` = `#{orig_table}`.`#{column_right}`"
|
54
|
+
@joins_tracker[argument] = {}
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect_hash(argument)
|
58
|
+
argument.each do |key, value|
|
59
|
+
inspect_symbol(key)
|
60
|
+
|
61
|
+
relationship_pair = @model.relationships.detect { |relationship_name, _relationship| relationship_name == key }
|
62
|
+
raise "Could not find a relationship on #{@model.name} by that name: #{value}" unless relationship_pair
|
63
|
+
relationship = relationship_pair[1]
|
64
|
+
|
65
|
+
BazaModels::Query::Inspector.new(
|
66
|
+
query: @query,
|
67
|
+
argument: value,
|
68
|
+
model: Object.const_get(relationship.fetch(:class_name)),
|
69
|
+
joins: @joins,
|
70
|
+
joins_tracker: @joins_tracker[key]
|
71
|
+
).execute
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class BazaModels::Query::Not
|
2
|
+
def initialize(args)
|
3
|
+
@query = args.fetch(:query)
|
4
|
+
@model = @query.instance_variable_get(:@model)
|
5
|
+
@db = @query.instance_variable_get(:@db)
|
6
|
+
@wheres = @query.instance_variable_get(:@wheres)
|
7
|
+
end
|
8
|
+
|
9
|
+
def not(args)
|
10
|
+
args.each do |key, value|
|
11
|
+
if value.is_a?(Hash)
|
12
|
+
value.each do |hash_key, hash_value|
|
13
|
+
if hash_value.is_a?(Array)
|
14
|
+
values = hash_value.map { |hash_value_i| "'#{@db.esc(hash_value_i)}'" }.join(",")
|
15
|
+
|
16
|
+
@wheres << "`#{key}`.`#{hash_key}` NOT IN (#{values})"
|
17
|
+
else
|
18
|
+
@wheres << "`#{key}`.`#{hash_key}` != '#{@db.esc(hash_value)}'"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
else
|
22
|
+
if value.is_a?(Array)
|
23
|
+
values = value.map { |value_i| "'#{@db.esc(value_i)}'" }.join(",")
|
24
|
+
|
25
|
+
@wheres << "`#{@model.table_name}`.`#{key}` NOT IN (#{values})"
|
26
|
+
else
|
27
|
+
@wheres << "`#{@model.table_name}`.`#{key}` != '#{@db.esc(value)}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@query
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class BazaModels::Ransacker
|
2
|
+
def initialize(args)
|
3
|
+
@klass = args.fetch(:class)
|
4
|
+
@params = args.fetch(:params)
|
5
|
+
@query = @klass
|
6
|
+
end
|
7
|
+
|
8
|
+
def result
|
9
|
+
add_filters_to_query
|
10
|
+
@query
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def add_filters_to_query
|
16
|
+
return unless @params
|
17
|
+
|
18
|
+
@params.each do |key, value|
|
19
|
+
if (match = key.to_s.match(/\A(.+?)_eq\Z/))
|
20
|
+
column_name = match[1]
|
21
|
+
@query = @query.where("`#{@klass.table_name}`.`#{@klass.db.escape_column(column_name)}` = '#{@klass.db.esc(value)}'")
|
22
|
+
elsif (match = key.to_s.match(/\A(.+?)_cont\Z/))
|
23
|
+
column_name = match[1]
|
24
|
+
@query = @query.where("`#{@klass.table_name}`.`#{@klass.db.escape_column(column_name)}` LIKE '%#{@klass.db.esc(value)}%'")
|
25
|
+
else
|
26
|
+
raise "Unknown modifier: #{key}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class BazaModels::TestDatabaseCleaner
|
2
|
+
def self.clean
|
3
|
+
BazaModels::TestDatabaseCleaner.new.truncate_all_tables
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
raise "Not in test-environment" unless Rails.env.test?
|
8
|
+
|
9
|
+
@db = BazaModels.primary_db
|
10
|
+
|
11
|
+
raise "No primary database on BazaModels?" unless @db
|
12
|
+
|
13
|
+
truncate_all_tables
|
14
|
+
end
|
15
|
+
|
16
|
+
def truncate_all_tables
|
17
|
+
@db.transaction do
|
18
|
+
@db.tables.list do |table|
|
19
|
+
table.truncate unless table.name == "baza_schema_migrations"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -5,4 +5,18 @@ class BazaModels::Validators::BaseValidator
|
|
5
5
|
@attribute_name = attribute_name
|
6
6
|
@args = args
|
7
7
|
end
|
8
|
+
|
9
|
+
def fire?(model)
|
10
|
+
result = true
|
11
|
+
|
12
|
+
if @args[:if]
|
13
|
+
if @args.fetch(:if).is_a?(Symbol)
|
14
|
+
result = model.__send__(@args.fetch(:if))
|
15
|
+
else
|
16
|
+
raise "Unknown 'if'-argument: #{@args[:if]} (#{@args[:if].class.name})"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
result
|
21
|
+
end
|
8
22
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class BazaModels::Validators::ConfirmationValidator < BazaModels::Validators::BaseValidator
|
2
|
+
def validate(model, value)
|
3
|
+
confirmation_attribute_name = "#{attribute_name}_confirmation"
|
4
|
+
confirmation_value = model.__send__(confirmation_attribute_name)
|
5
|
+
|
6
|
+
if value && !confirmation_value
|
7
|
+
model.errors.add(attribute_name, "hasn't been confirmed")
|
8
|
+
end
|
9
|
+
|
10
|
+
model.errors.add(attribute_name, "was not the same as the confirmation") if value && confirmation_value && confirmation_value != value
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class BazaModels::Validators::FormatValidator < BazaModels::Validators::BaseValidator
|
2
|
+
def validate(model, value)
|
3
|
+
model.errors.add(attribute_name, "has an invalid format") unless value.to_s.match(format_regex)
|
4
|
+
end
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def format_regex
|
9
|
+
@args.fetch(:format)[:with]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class BazaModels::Validators::LengthValidator < BazaModels::Validators::BaseValidator
|
2
|
+
def validate(model, value)
|
3
|
+
model.errors.add(attribute_name, "is too long") if max_length && value.to_s.length > max_length
|
4
|
+
model.errors.add(attribute_name, "is too short") if min_length && value.to_s.length < min_length
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def max_length
|
10
|
+
@args.fetch(:length)[:maximum]
|
11
|
+
end
|
12
|
+
|
13
|
+
def min_length
|
14
|
+
@args.fetch(:length)[:minimum]
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class BazaModels::Validators::UniquenessValidator < BazaModels::Validators::BaseValidator
|
2
|
+
def validate(model, value)
|
3
|
+
query_same = model.class.where(attribute_name => value)
|
4
|
+
|
5
|
+
if scope
|
6
|
+
scope.each do |scope_part|
|
7
|
+
query_same = query_same.where(scope_part => model.__send__(scope_part))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
model.errors.add(attribute_name, "isn't unique") if query_same.any?
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def scope
|
17
|
+
scope = @args.fetch(:uniqueness)[:scope]
|
18
|
+
scope = [scope] if scope && !scope.is_a?(Array)
|
19
|
+
scope
|
20
|
+
end
|
21
|
+
end
|
data/shippable.yml
CHANGED
@@ -2,8 +2,10 @@ language: ruby
|
|
2
2
|
cache: bundler
|
3
3
|
archive: true
|
4
4
|
rvm:
|
5
|
-
- 2.1.2
|
5
|
+
- ruby-2.1.2
|
6
|
+
- jruby-1.7.13
|
6
7
|
script:
|
7
8
|
- CODECLIMATE_REPO_TOKEN=b91c00ba044df16a09d7120a2449a43ccad754de9271a7ecf594e3b0cf432eeb bundle exec rspec
|
9
|
+
- bundle exec rake best_practice_project:run
|
8
10
|
notifications:
|
9
11
|
email: false
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BazaModels::Autoloader do
|
4
|
+
include DatabaseHelper
|
5
|
+
|
6
|
+
let!(:organization) { Organization.create! }
|
7
|
+
let!(:another_user) { User.create!(email: "another@example.com") }
|
8
|
+
let!(:user) { User.create!(email: "test@example.com", organization: organization) }
|
9
|
+
let!(:user_passport) { UserPassport.create!(user: user) }
|
10
|
+
let(:role_user) { Role.new(user: user, role: "user") }
|
11
|
+
let!(:role_admin) { Role.create!(user: user, role: "administrator") }
|
12
|
+
|
13
|
+
it "autoloads via includes on has_many relations" do
|
14
|
+
query = User.includes(:roles).to_a
|
15
|
+
user_from_query = query.detect { |user| user.email == "test@example.com" }
|
16
|
+
|
17
|
+
expect(user_from_query.autoloads.fetch(:roles)).to eq [role_admin]
|
18
|
+
expect(user_from_query.roles.__send__(:any_mods?)).to eq false
|
19
|
+
expect(user_from_query.roles.__send__(:any_wheres_other_than_relation?)).to eq false
|
20
|
+
expect(user_from_query.roles.__send__(:autoloaded_on_previous_model?)).to eq true
|
21
|
+
expect(user_from_query.roles.to_enum).to eq [role_admin]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "autoloads via includes on belongs_to relations" do
|
25
|
+
query = Role.includes(:user).to_a
|
26
|
+
role = query.first
|
27
|
+
|
28
|
+
allow(role.autoloads).to receive(:[]).and_call_original
|
29
|
+
expect(role.user).to eq user
|
30
|
+
expect(role.autoloads).to have_received(:[]).with(:user)
|
31
|
+
expect(role.autoloads[:user]).to eq user
|
32
|
+
end
|
33
|
+
|
34
|
+
it "autoloads via includes on has_one relations" do
|
35
|
+
query = User.includes(:user_passport).to_a
|
36
|
+
user = query.detect { |user_i| user_i.email == "test@example.com" }
|
37
|
+
|
38
|
+
allow(user.autoloads).to receive(:[]).and_call_original
|
39
|
+
expect(user.user_passport).to eq user_passport
|
40
|
+
expect(user.autoloads).to have_received(:[]).with(:user_passport)
|
41
|
+
expect(user.autoloads[:user_passport]).to eq user_passport
|
42
|
+
end
|
43
|
+
|
44
|
+
it "autoloads sub models" do
|
45
|
+
organizations = Organization.includes(users: :roles).to_a
|
46
|
+
organization = organizations.first
|
47
|
+
|
48
|
+
expect(organization.autoloads.fetch(:users)).to eq [user]
|
49
|
+
|
50
|
+
expect(organization.users.to_a).to eq [user]
|
51
|
+
org_user = organization.autoloads.fetch(:users).first
|
52
|
+
expect(org_user.autoloads.fetch(:roles)).to eq [role_admin]
|
53
|
+
|
54
|
+
org_user = organization.users.first
|
55
|
+
expect(org_user.autoloads.fetch(:roles)).to eq [role_admin]
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BazaModels::Query do
|
4
|
+
include DatabaseHelper
|
5
|
+
|
6
|
+
let(:user) { User.new(email: "test@example.com") }
|
7
|
+
|
8
|
+
it "#get" do
|
9
|
+
user.save!
|
10
|
+
expect(User.to_adapter.get([1])).to eq user
|
11
|
+
expect(User.to_adapter.get(1)).to eq user
|
12
|
+
expect(User.to_adapter.get(5)).to eq nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it "#get!" do
|
16
|
+
user.save!
|
17
|
+
expect(User.to_adapter.get!([1])).to eq user
|
18
|
+
expect(User.to_adapter.get!(1)).to eq user
|
19
|
+
|
20
|
+
expect do
|
21
|
+
User.to_adapter.get!(5)
|
22
|
+
end.to raise_error(BazaModels::Errors::RecordNotFound)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "#create!" do
|
26
|
+
expect { User.to_adapter.create!(email: "test@example.com") }.to change(User, :count).by(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#destroy" do
|
30
|
+
user.save!
|
31
|
+
|
32
|
+
expect do
|
33
|
+
expect(User.to_adapter.destroy(user)).to eq true
|
34
|
+
end.to change(User, :count).by(-1)
|
35
|
+
|
36
|
+
expect { user.reload }.to raise_error(BazaModels::Errors::RecordNotFound)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "#find_first" do
|
40
|
+
user.save!
|
41
|
+
expect(User.to_adapter.find_first(id: 1)).to eq user
|
42
|
+
end
|
43
|
+
|
44
|
+
it "#find_all" do
|
45
|
+
user.save!
|
46
|
+
expect(User.to_adapter.find_all(id: 1).to_a).to eq [user]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "#column_names" do
|
50
|
+
expect(User.to_adapter.column_names).to eq %w(id organization_id email email_confirmation created_at updated_at)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BazaModels::ClassTranslation do
|
4
|
+
include DatabaseHelper
|
5
|
+
|
6
|
+
it "#model_name" do
|
7
|
+
expect(User.model_name.human).to eq "User"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "#param_key" do
|
11
|
+
expect(User.model_name.param_key).to eq "user"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "#route_key" do
|
15
|
+
expect(User.model_name.route_key).to eq "users"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "#singular_route_key" do
|
19
|
+
expect(User.model_name.singular_route_key).to eq "user"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "#i18n_key" do
|
23
|
+
expect(User.model_name.i18n_key).to eq :user
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "factory girl with baza models" do
|
4
|
+
include DatabaseHelper
|
5
|
+
|
6
|
+
let(:user) { create :user, organization: organization }
|
7
|
+
let(:organization) { create :organization }
|
8
|
+
|
9
|
+
it "creates the user" do
|
10
|
+
expect(user.email).to eq "user@example.com"
|
11
|
+
expect(user.organization).to eq organization
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe BazaModels::Model::BelongsToRelations do
|
4
|
+
include DatabaseHelper
|
5
|
+
|
6
|
+
let(:user) { User.new(email: "test@example.com") }
|
7
|
+
let(:role_user) { Role.new(user: user, role: "user") }
|
8
|
+
let(:role_admin) { Role.new(user: user, role: "administrator") }
|
9
|
+
|
10
|
+
context "relationships" do
|
11
|
+
before do
|
12
|
+
user.save!
|
13
|
+
role_user.save!
|
14
|
+
role_admin.save!
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#belongs_to" do
|
18
|
+
expect(role_user.user).to eq user
|
19
|
+
end
|
20
|
+
|
21
|
+
it "joins correctly" do
|
22
|
+
roles = Role.joins(:user).where(role: "administrator", users: {email: "test@example.com"})
|
23
|
+
expect(roles.to_a).to eq [role_admin]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|