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.
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