partial_ks 0.4.2 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad9df615166ffb1addb9feff9c7a0db7cc73c841
4
- data.tar.gz: 9781d32d0230aa6e376822cd9803cfbea2938084
3
+ metadata.gz: 642d94cc600de50ae308e592033b37eb76332797
4
+ data.tar.gz: 7df7585728a3fe621ed0200d0a83451e3ee0855e
5
5
  SHA512:
6
- metadata.gz: 7445c9ebc62962e3ee09bd7650d79545a3af9477c89fdfdf0d81b530713ebe012e90c3abe007cbfeec24df28c1624bfe94935c1794929363ccbc75759d80d7ca
7
- data.tar.gz: c5ea6e4a4d723d8e6f86e748bd7f969974bff2775bb18f38ca33c5d5f1a015a15b2df1ceb26e079337541381e8686a3cf5abc6d38c53d95962116007c640c974
6
+ metadata.gz: ca7b7e3247cfa18f6ba92aa9de44bb2e52f5cee6ff42a61ff64f9c2e6214b61a78f7bcb29d707f210b7062e998abd09c7dd4e4f224f7a1f27b2ce8e4081e989d
7
+ data.tar.gz: eee97be3e6b61d8f3e05a077217ef7d3b6b0659bf663e45c5b06899c7dd58ca8729811c298cef16c09f0c9fa8de01587997fec3e2d52e0cdc972181e4c24c317
data/CHANGES.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ # 0.5.0
4
+
5
+ * New single entry point, `PartialKs::KitchenSync`. This means that Runner and ConfigurationGenerator are now internal concerns
6
+
7
+ * Teach ModelsList about #issues - Basically a list of models where its "parent" is a MultiParent. Exposed via PartialKs::KitchenSync#issues
8
+
9
+ * Various refactors and simplifications
10
+
3
11
  # 0.4.2
4
12
 
5
13
  Fix an issue where we did not support the new ApplicationRecord convention
data/CONTRIBUTING.md CHANGED
@@ -2,7 +2,7 @@ This document should tell all you need to know for contributing to this project.
2
2
 
3
3
  # Testing
4
4
 
5
- Tested with activerecord 4.2.7.1, 4.2.8 and 5.0.2 (on Ruby 2.3.3)
5
+ Tested with activerecord 4.2.7.1, 4.2.8, 5.0.2, 5.1.0 (on Ruby 2.3.3)
6
6
 
7
7
 
8
8
  To install and run tests :
data/README.md CHANGED
@@ -8,9 +8,7 @@ So how does it work ?
8
8
 
9
9
 
10
10
  ```
11
- manual_configuration = []
12
- config = PartialKs::ConfigurationGenerator.new(manual_configuration).call
13
- PartialKs::Runner.new([config]).run! do |tables_to_filter, tables|
11
+ PartialKs::KitchenSync.new(manual_configuration).run! do |tables_to_filter, tables|
14
12
  puts tables_to_filter.inspect
15
13
  puts tables.inspect
16
14
  end
@@ -27,24 +25,12 @@ manual_configuration = [
27
25
 
28
26
  NB: The first use case for this gem is to be run in conjuction with [Kitchen Sync](https://github.com/willbryant/kitchen_sync). On OSX, one can install Kitchen Sync using `brew install kitchen-sync`
29
27
 
30
- *TODO*
31
-
32
- * Provide a way for users to pass in manual configurations
33
- * Tool to run report using bundle exec
34
-
35
28
  # Public API
36
29
 
37
30
  It currently consists of :
38
31
 
39
- - ConfigurationGenerator
40
- - Runner
41
- - runs
42
- - reports (mostly for debugging)
43
-
44
- *TODO*
32
+ - PartialKs::KitchenSync
45
33
 
46
- * Rename PartialKs::ConfigurationGenerator#call to something better
47
- * Minimize Public API
48
34
 
49
35
  # Not supported
50
36
 
@@ -3,8 +3,8 @@ module PartialKs
3
3
  attr_reader :table, :parent_model, :custom_filter_relation
4
4
  delegate :table_name, :to => :table
5
5
 
6
- def initialize(table, parent_model, custom_filter_relation: nil)
7
- @table = table
6
+ def initialize(model, parent_model, custom_filter_relation: nil)
7
+ @table = PartialKs::Table.new(model)
8
8
  @parent_model = parent_model
9
9
  @custom_filter_relation = custom_filter_relation
10
10
  end
@@ -0,0 +1,14 @@
1
+ module PartialKs
2
+ class KitchenSync
3
+ attr_reader :models_list
4
+ delegate :issues, to: :models_list
5
+
6
+ def initialize(manual_configuration)
7
+ @models_list = ModelsList.new(manual_configuration)
8
+ end
9
+
10
+ def run!(&block)
11
+ Runner.new(models_list.all).run!(&block)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module PartialKs
2
+ class ModelsList
3
+ attr_reader :manual_configuration
4
+
5
+ def initialize(manual_configuration)
6
+ @manual_configuration = manual_configuration
7
+ end
8
+
9
+ def all
10
+ @all ||= manual_configuration + automatic_configuration_except_manual
11
+ end
12
+
13
+ def issues
14
+ all.select{|model, parent| parent.is_a?(PartialKs::MultiParent)}
15
+ end
16
+
17
+ private
18
+ def automatic_configuration_except_manual
19
+ tables_already_present = manual_configuration.map(&:first).map(&:table_name)
20
+
21
+ PartialKs.all_rails_models.reject{|model| tables_already_present.include?(model.table_name) }.map do |model|
22
+ table = PartialKs::Table.new(model)
23
+ [table.model, table.inferred_parent_class]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,9 +1,9 @@
1
1
  module PartialKs
2
2
  class Runner
3
- attr_reader :table_graphs
3
+ attr_reader :models_list
4
4
 
5
- def initialize(table_graphs)
6
- @table_graphs = table_graphs
5
+ def initialize(models_list)
6
+ @models_list = models_list
7
7
  end
8
8
 
9
9
  def run!
@@ -20,7 +20,6 @@ module PartialKs
20
20
  end
21
21
  end
22
22
 
23
- # TODO output only tables_to_filter, depending on how KS handles filters
24
23
  yield tables_to_filter, table_names
25
24
  end
26
25
  end
@@ -44,29 +43,31 @@ module PartialKs
44
43
  end
45
44
 
46
45
  protected
46
+ def filtered_tables
47
+ @filtered_tables ||= models_list.map {|model, parent, custom_filter| PartialKs::FilteredTable.new(model, parent, custom_filter_relation: custom_filter)}
48
+ end
49
+
47
50
  def generations
48
51
  return @generations if defined?(@generations)
49
52
 
50
53
  @generations = []
51
- table_graphs.each do |filtered_tables|
52
- q = []
54
+ q = []
53
55
 
54
- filtered_tables.each do |filtered_table|
55
- q << filtered_table if filtered_table.parent_model.nil?
56
- end
56
+ filtered_tables.each do |filtered_table|
57
+ q << filtered_table if filtered_table.parent_model.nil?
58
+ end
57
59
 
58
- until q.empty?
59
- @generations << q
60
+ until q.empty?
61
+ @generations << q
60
62
 
61
- next_generation = []
62
- q.each do |table|
63
- filtered_tables.each do |child_table|
64
- next_generation << child_table if child_table.parent_model && child_table.parent_model.table_name == table.table_name
65
- end
63
+ next_generation = []
64
+ q.each do |table|
65
+ filtered_tables.each do |child_table|
66
+ next_generation << child_table if child_table.parent_model && child_table.parent_model.table_name == table.table_name
66
67
  end
67
-
68
- q = next_generation
69
68
  end
69
+
70
+ q = next_generation
70
71
  end
71
72
 
72
73
  @generations
@@ -7,14 +7,14 @@ module PartialKs
7
7
  @model = model
8
8
  end
9
9
 
10
- # sometimes the table is present, but the model is not defined
11
- # e.g. in market specific tables
12
- def model?
13
- model && model.respond_to?(:table_name)
14
- end
15
-
16
- def top_level_table?
17
- candidate_parent_classes.empty?
10
+ def inferred_parent_class
11
+ if candidate_parent_classes.empty?
12
+ nil
13
+ elsif candidate_parent_classes.size == 1
14
+ candidate_parent_classes.first
15
+ else
16
+ MultiParent.new(candidate_parent_classes)
17
+ end
18
18
  end
19
19
 
20
20
  # NB: can't do polymorphic for now, rails errors on reflection#klass
@@ -23,10 +23,6 @@ module PartialKs
23
23
  non_nullable_reflections.reject(&:polymorphic?).map(&:klass)
24
24
  end
25
25
 
26
- def parent_tables
27
- belongs_to_reflections.map(&:table_name)
28
- end
29
-
30
26
  def relation_for_associated_model(klass)
31
27
  association = model.reflect_on_all_associations.find {|assoc| assoc.class_name == klass.name}
32
28
  raise "#{filter_condition.name} not found in #{model.name} associations" if association.nil?
@@ -55,4 +51,21 @@ module PartialKs
55
51
  end
56
52
  end
57
53
  end
54
+
55
+ class MultiParent
56
+ attr_reader :parents
57
+
58
+ def initialize(parents)
59
+ @parents = parents
60
+ end
61
+
62
+ def ==(other)
63
+ table_name == other.table_name if other
64
+ end
65
+
66
+ # only used in comparison in Runner
67
+ def table_name
68
+ parents.map(&:table_name).join(",")
69
+ end
70
+ end
58
71
  end
@@ -1,3 +1,3 @@
1
1
  module PartialKs
2
- VERSION = '0.4.2'
2
+ VERSION = '0.5.0'
3
3
  end
data/lib/partial_ks.rb CHANGED
@@ -2,7 +2,7 @@ require 'active_record'
2
2
 
3
3
  require_relative 'partial_ks/all_rails_models'
4
4
  require_relative 'partial_ks/filtered_table'
5
- require_relative 'partial_ks/parent_inferrer'
6
5
  require_relative 'partial_ks/runner'
7
6
  require_relative 'partial_ks/table'
8
- require_relative 'partial_ks/configuration_generator'
7
+ require_relative 'partial_ks/models_list'
8
+ require_relative 'partial_ks/kitchen_sync'
data/partial_ks.gemspec CHANGED
@@ -10,7 +10,7 @@ EOF
10
10
  gem.has_rdoc = false
11
11
  gem.author = "Thong Kuah"
12
12
  gem.email = "kuahyeow@gmail.com"
13
- gem.homepage = "https://github.com/powershop/partial_ks"
13
+ gem.homepage = "https://github.com/fluxfederation/partial_ks"
14
14
  gem.license = "MIT"
15
15
 
16
16
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -16,4 +16,15 @@ describe "all rails tables" do
16
16
  it "returns the same number of models as the number of tables" do
17
17
  PartialKs.all_rails_models.map(&:table_name).sort.must_equal ActiveRecord::Base.connection.tables.sort
18
18
  end
19
+
20
+ it "does not choke on a table which has had its migration run" do
21
+ PartialKs.all_rails_models.wont_include NewModel
22
+ end
23
+
24
+ it "can return models with different table_name" do
25
+ model = OldEntry
26
+ model.table_name.wont_equal model.name.tableize
27
+
28
+ PartialKs.all_rails_models.must_include model
29
+ end
19
30
  end
@@ -1,10 +1,5 @@
1
1
  require 'test_helper'
2
2
 
3
- def generator(manual, tables)
4
- PartialKs::ConfigurationGenerator.new(manual, tables).call.
5
- map {|f| [f.table_name, f.parent_model, f.custom_filter_relation] }
6
- end
7
-
8
3
  describe "generating dependencies" do
9
4
  let(:manual_configuration) do
10
5
  [
@@ -12,39 +7,17 @@ describe "generating dependencies" do
12
7
  ]
13
8
  end
14
9
 
15
- # TODO remove redundant test (cf parent_inferrer_test)
16
- it "auto infers single belongs-to dependencies" do
17
- generator(manual_configuration, models: [User, BlogPost]).
18
- must_equal [
19
- ["users", nil, User.where(:id => [1])],
20
- ["blog_posts", User, nil]
21
- ]
10
+ it "returns the manual_configuration" do
11
+ result = PartialKs::ModelsList.new(manual_configuration).all
12
+ result.must_include manual_configuration.first
22
13
  end
23
14
 
24
- # TODO remove redundant test (cf parent_inferrer_test)
25
- it "auto infers top level tables" do
26
- generator(manual_configuration, models: [User, Tag]).
27
- must_equal [
28
- ["users", nil, User.where(:id => [1])],
29
- ["tags", nil, nil]
30
- ]
15
+ it "processes all models" do
16
+ result = PartialKs::ModelsList.new(manual_configuration).all
17
+ result.size.must_equal PartialKs.all_rails_models.size
31
18
  end
32
19
 
33
- it "can return models with different table_name" do
34
- model = OldEntry
35
- model.table_name.wont_equal model.name.tableize
36
-
37
- generator(manual_configuration, models: [User, model]).
38
- must_equal [
39
- ["users", nil, User.where(:id => [1])],
40
- ["cms_table", nil, nil]
41
- ]
42
- end
43
-
44
- it "does not choke on a table which has had its migration run" do
45
- generator(manual_configuration, models: [User, NewModel]).
46
- must_equal [
47
- ["users", nil, User.where(:id => [1])],
48
- ]
20
+ it "can identify MultiParent as issues" do
21
+ PartialKs::ModelsList.new(manual_configuration).issues.map(&:last).map(&:class).must_equal [PartialKs::MultiParent]
49
22
  end
50
23
  end
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  describe "kitchen sync filter" do
4
- let(:table) { PartialKs::Table.new(PostTag) }
4
+ let(:model) { PostTag }
5
5
  let(:parent) { Minitest::Mock.new }
6
6
 
7
7
  it "proxies to Table if there's parent only" do
@@ -9,39 +9,39 @@ describe "kitchen sync filter" do
9
9
  relation_mock = Minitest::Mock.new
10
10
  relation_mock.expect :where_sql, "WHERE tag_id IN (0)"
11
11
 
12
- filtered_table = PartialKs::FilteredTable.new(table, parent)
13
- table.stub table_parent_relation_method, relation_mock do
12
+ filtered_table = PartialKs::FilteredTable.new(model, parent)
13
+ filtered_table.table.stub table_parent_relation_method, relation_mock do
14
14
  filtered_table.kitchen_sync_filter.must_equal({"only" => 'tag_id IN (0)'})
15
15
  end
16
16
  end
17
17
 
18
18
  it "uses the custom filter if provided" do
19
19
  filter = PostTag.where(:id => [1, 2])
20
- filtered_table = PartialKs::FilteredTable.new(table, nil, custom_filter_relation: filter)
20
+ filtered_table = PartialKs::FilteredTable.new(model, nil, custom_filter_relation: filter)
21
21
  filtered_table.kitchen_sync_filter.must_equal({"only" => '"post_tags"."id" IN (1, 2)'})
22
22
  end
23
23
 
24
24
  it "uses the filter inside a lambda" do
25
25
  filter = -> { PostTag.where(:id => [1, 2]) }
26
- filtered_table = PartialKs::FilteredTable.new(table, nil, custom_filter_relation: filter)
26
+ filtered_table = PartialKs::FilteredTable.new(model, nil, custom_filter_relation: filter)
27
27
  filtered_table.kitchen_sync_filter.must_equal({"only" => '"post_tags"."id" IN (1, 2)'})
28
28
  end
29
29
 
30
30
  it "uses a SQL where fragment as a filter if provided" do
31
31
  string_filter = "1=0"
32
- filtered_table = PartialKs::FilteredTable.new(table, nil, custom_filter_relation: string_filter)
32
+ filtered_table = PartialKs::FilteredTable.new(model, nil, custom_filter_relation: string_filter)
33
33
  filtered_table.kitchen_sync_filter.must_equal({"only" => string_filter})
34
34
  end
35
35
 
36
36
  it "uses a SQL statement as a filter if provided" do
37
37
  string_filter = "1=0"
38
- sql_statement = "select * from #{table.table_name} where #{string_filter}"
39
- filtered_table = PartialKs::FilteredTable.new(table, nil, custom_filter_relation: sql_statement)
38
+ sql_statement = "select * from #{model.table_name} where #{string_filter}"
39
+ filtered_table = PartialKs::FilteredTable.new(model, nil, custom_filter_relation: sql_statement)
40
40
  filtered_table.kitchen_sync_filter.must_equal({"only" => string_filter})
41
41
  end
42
42
 
43
43
  it "returns nil if parent is nil" do
44
- filtered_table = PartialKs::FilteredTable.new(table, nil)
44
+ filtered_table = PartialKs::FilteredTable.new(model, nil)
45
45
  filtered_table.kitchen_sync_filter.must_be_nil
46
46
  end
47
47
 
@@ -3,16 +3,16 @@ require 'test_helper'
3
3
  describe "inferring parents" do
4
4
  it "infers no parent for a top level table" do
5
5
  table = PartialKs::Table.new(Tag)
6
- PartialKs::ParentInferrer.new(table).inferred_parent_class.must_be_nil
6
+ table.inferred_parent_class.must_be_nil
7
7
  end
8
8
 
9
9
  it "infers a parent for a table that has a single belongs_to" do
10
10
  table = PartialKs::Table.new(BlogPost)
11
- PartialKs::ParentInferrer.new(table).inferred_parent_class.must_equal User
11
+ table.inferred_parent_class.must_equal User
12
12
  end
13
13
 
14
- it "infers no parent for a table has multiple belongs_to" do
14
+ it "infers a multi-parent for a table has multiple belongs_to" do
15
15
  table = PartialKs::Table.new(PostTag)
16
- lambda { PartialKs::ParentInferrer.new(table).inferred_parent_class }.must_raise PartialKs::ParentInferrer::CannotInfer
16
+ table.inferred_parent_class.must_equal PartialKs::MultiParent.new([BlogPost, Tag])
17
17
  end
18
18
  end
data/test/runner_test.rb CHANGED
@@ -2,29 +2,29 @@ require 'test_helper'
2
2
 
3
3
  describe 'end to end testing' do
4
4
  it "runs without error" do
5
- generator_output = PartialKs::ConfigurationGenerator.new([]).call
6
- PartialKs::Runner.new([generator_output]).run! do |tables_to_filter, table_names|
7
- # left empty
5
+ count = 0
6
+ multi_parents = [PostTag]
7
+
8
+ generator_output = PartialKs::ModelsList.new([]).all
9
+ PartialKs::Runner.new(generator_output).run! do |tables_to_filter, table_names|
10
+ count += table_names.size
8
11
  end
12
+
13
+ count.must_equal PartialKs.all_rails_models.size - multi_parents.size
9
14
  end
10
15
  end
11
16
 
12
17
  describe 'running based on output from generator' do
13
- let(:manual_configuration) do
14
- [
15
- ["users", nil, User.where(:id => [1])],
16
- ]
17
- end
18
-
19
18
  let(:generator_output) do
20
19
  [
21
- PartialKs::FilteredTable.new(PartialKs::Table.new(User), nil, custom_filter_relation: User.where(:id => [1])),
22
- PartialKs::FilteredTable.new(PartialKs::Table.new(Tag), nil),
23
- PartialKs::FilteredTable.new(PartialKs::Table.new(BlogPost), User),
20
+ [User, nil, User.where(:id => [1])],
21
+ [Tag, nil],
22
+ [BlogPost, User],
23
+ [PostTag, PartialKs::MultiParent.new([BlogPost, Tag])],
24
24
  ]
25
25
  end
26
26
 
27
- let(:runner) { PartialKs::Runner.new([generator_output]) }
27
+ let(:runner) { PartialKs::Runner.new(generator_output) }
28
28
 
29
29
  it "reports everything" do
30
30
  runner.report.must_equal [
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: partial_ks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thong Kuah
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-14 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -69,9 +69,9 @@ files:
69
69
  - Rakefile
70
70
  - lib/partial_ks.rb
71
71
  - lib/partial_ks/all_rails_models.rb
72
- - lib/partial_ks/configuration_generator.rb
73
72
  - lib/partial_ks/filtered_table.rb
74
- - lib/partial_ks/parent_inferrer.rb
73
+ - lib/partial_ks/kitchen_sync.rb
74
+ - lib/partial_ks/models_list.rb
75
75
  - lib/partial_ks/runner.rb
76
76
  - lib/partial_ks/table.rb
77
77
  - lib/partial_ks/version.rb
@@ -86,7 +86,7 @@ files:
86
86
  - test/setup_models.rb
87
87
  - test/table_test.rb
88
88
  - test/test_helper.rb
89
- homepage: https://github.com/powershop/partial_ks
89
+ homepage: https://github.com/fluxfederation/partial_ks
90
90
  licenses:
91
91
  - MIT
92
92
  metadata: {}
@@ -1,66 +0,0 @@
1
- # Given an initial table graph
2
- # goes through each table not already in the table graph,
3
- # and attempts to automatically populate the table into the table graph
4
- module PartialKs
5
- class ConfigurationGenerator
6
- attr_reader :manual_configuration
7
-
8
- def initialize(manual_configuration, models: nil)
9
- @manual_configuration = manual_configuration
10
- @models = models || PartialKs.all_rails_models
11
- end
12
-
13
- def call
14
- @filtered_tables ||= filtered_tables
15
- end
16
-
17
- protected
18
- def all_tables
19
- @all_tables ||= models.map {|model| PartialKs::Table.new(model) }.select(&:model?).index_by(&:table_name)
20
- end
21
-
22
- def models
23
- tables_in_database = ActiveRecord::Base.connection.tables
24
- @models.select{|model| tables_in_database.include?(model.table_name)}
25
- end
26
-
27
- def filtered_tables
28
- synced_tables = {}
29
-
30
- manual_configuration.each do |model, specified_parent_model, filter_for_table|
31
- table_name = model.table_name
32
- next unless all_tables[table_name]
33
-
34
- parent_model = specified_parent_model
35
- synced_tables[table_name] = PartialKs::FilteredTable.new(all_tables[table_name], parent_model, custom_filter_relation: filter_for_table)
36
- end
37
-
38
- all_tables.each do |table_name, table|
39
- next if synced_tables[table_name]
40
-
41
- begin
42
- inferrer = PartialKs::ParentInferrer.new(table)
43
- parent_model = inferrer.inferred_parent_class
44
- synced_tables[table_name] = PartialKs::FilteredTable.new(table, parent_model)
45
- rescue PartialKs::ParentInferrer::CannotInfer
46
- next
47
- end
48
-
49
- end
50
-
51
- # TODO remove this side effect. Maybe yield or a different method call ?
52
- puts "***************"
53
- remaining_size = 0
54
- all_tables.each do |table_name, table|
55
- next if synced_tables[table_name]
56
-
57
- puts "#{table.table_name} - #{table.parent_tables.join(',')}"
58
- remaining_size += 1
59
- end
60
- puts "WARNING: #{remaining_size} tables has no configuration"
61
-
62
- synced_tables.values
63
- end
64
-
65
- end
66
- end
@@ -1,21 +0,0 @@
1
- module PartialKs
2
- class ParentInferrer
3
- CannotInfer = Class.new(StandardError)
4
-
5
- attr_reader :table
6
-
7
- def initialize(table)
8
- @table = table
9
- end
10
-
11
- def inferred_parent_class
12
- if table.top_level_table?
13
- nil
14
- elsif table.candidate_parent_classes.size == 1
15
- table.candidate_parent_classes.first
16
- else
17
- raise CannotInfer, "table has multiple candidates for parents"
18
- end
19
- end
20
- end
21
- end