baza_models 0.0.0 → 0.0.1
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/.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
|