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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +35 -0
  3. data/Gemfile +9 -3
  4. data/Gemfile.lock +90 -51
  5. data/README.md +98 -3
  6. data/Rakefile +20 -17
  7. data/VERSION +1 -1
  8. data/baza_models.gemspec +149 -0
  9. data/config/best_project_practice_rubocop.yml +2 -0
  10. data/config/best_project_practice_rubocop_todo.yml +35 -0
  11. data/lib/baza_models.rb +15 -0
  12. data/lib/baza_models/autoloader.rb +135 -0
  13. data/lib/baza_models/baza_orm_adapter.rb +39 -0
  14. data/lib/baza_models/can_can_adapter.rb +9 -0
  15. data/lib/baza_models/class_translation.rb +44 -0
  16. data/lib/baza_models/errors.rb +24 -2
  17. data/lib/baza_models/model.rb +236 -115
  18. data/lib/baza_models/model/belongs_to_relations.rb +49 -0
  19. data/lib/baza_models/model/custom_validations.rb +24 -0
  20. data/lib/baza_models/model/delegation.rb +21 -0
  21. data/lib/baza_models/model/has_many_relations.rb +85 -0
  22. data/lib/baza_models/model/has_one_relations.rb +93 -0
  23. data/lib/baza_models/model/manipulation.rb +123 -0
  24. data/lib/baza_models/model/queries.rb +45 -0
  25. data/lib/baza_models/model/scopes.rb +19 -0
  26. data/lib/baza_models/model/translation_functionality.rb +30 -0
  27. data/lib/baza_models/model/validations.rb +95 -0
  28. data/lib/baza_models/query.rb +447 -0
  29. data/lib/baza_models/query/inspector.rb +74 -0
  30. data/lib/baza_models/query/not.rb +34 -0
  31. data/lib/baza_models/ransacker.rb +30 -0
  32. data/lib/baza_models/test_database_cleaner.rb +23 -0
  33. data/lib/baza_models/validators/base_validator.rb +14 -0
  34. data/lib/baza_models/validators/confirmation_validator.rb +12 -0
  35. data/lib/baza_models/validators/format_validator.rb +11 -0
  36. data/lib/baza_models/validators/length_validator.rb +16 -0
  37. data/lib/baza_models/validators/uniqueness_validator.rb +21 -0
  38. data/shippable.yml +3 -1
  39. data/spec/baza_models/autoloader_spec.rb +57 -0
  40. data/spec/baza_models/baza_orm_adapter_spec.rb +52 -0
  41. data/spec/baza_models/class_translation_spec.rb +25 -0
  42. data/spec/baza_models/factory_girl_spec.rb +13 -0
  43. data/spec/baza_models/model/belongs_to_relations_spec.rb +26 -0
  44. data/spec/baza_models/model/custom_validations_spec.rb +18 -0
  45. data/spec/baza_models/model/delgation_spec.rb +16 -0
  46. data/spec/baza_models/model/has_many_relations_spec.rb +68 -0
  47. data/spec/baza_models/model/has_one_relations_spec.rb +35 -0
  48. data/spec/baza_models/model/manipulation_spec.rb +25 -0
  49. data/spec/baza_models/model/queries_spec.rb +59 -0
  50. data/spec/baza_models/model/scopes_spec.rb +23 -0
  51. data/spec/baza_models/model/translate_functionality_spec.rb +13 -0
  52. data/spec/baza_models/model/validations_spec.rb +52 -0
  53. data/spec/baza_models/model_spec.rb +75 -98
  54. data/spec/baza_models/query/not_spec.rb +16 -0
  55. data/spec/baza_models/query_spec.rb +155 -0
  56. data/spec/baza_models/ransacker_spec.rb +15 -0
  57. data/spec/baza_models/validators/confirmation_validator_spec.rb +28 -0
  58. data/spec/baza_models/validators/format_validator_spec.rb +17 -0
  59. data/spec/baza_models/validators/length_validator_spec.rb +19 -0
  60. data/spec/baza_models/validators/uniqueness_validator_spec.rb +24 -0
  61. data/spec/factories/organization.rb +5 -0
  62. data/spec/factories/user.rb +7 -0
  63. data/spec/spec_helper.rb +17 -5
  64. data/spec/support/database_helper.rb +87 -0
  65. data/spec/test_classes/organization.rb +3 -0
  66. data/spec/test_classes/person.rb +3 -0
  67. data/spec/test_classes/role.rb +12 -0
  68. data/spec/test_classes/user.rb +40 -0
  69. data/spec/test_classes/user_passport.rb +3 -0
  70. metadata +146 -7
  71. 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