joiner 0.5.0 → 0.6.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
  SHA256:
3
- metadata.gz: 76a7e71eaef54a09627a9d72231ab9fe99c966736a7c7bffbedcd110bcbcef4a
4
- data.tar.gz: 8aed7b7b5081bf0c564ea7e81f6a2d229f4e5e0b45b4ce3aae89d15e19879d39
3
+ metadata.gz: 50d83b6e1af0b5ef8c29fbbaabbb56a8c33ed99acbf57f507d13bcff673d92b2
4
+ data.tar.gz: 62adfb53520243ff108e85f68c61ca121cf28f1e6344fac539aa36c725efe0c1
5
5
  SHA512:
6
- metadata.gz: 00b8286b10577f26e2999601cfb4cf5c73b213ef452fa8608ccbbb1b5d33cb27b0505b08fac73a90d951dc18f7f9636be1c2fb58e39ac073aa0fbed73298e516
7
- data.tar.gz: 944cf099ea7df456ecfe2f52a21a624bef9e74154d524425e845312a626b4be5d72b264467a2fd38be4fdefd14097a88a1ee0fd40d1ba0009506664892c63b3b
6
+ metadata.gz: f96a6e7b1165be044ae4fba8dd71f9950f6635cbac352d7aa9d0aea9f7ead03d8bc0928f4fa69422539e4945976207394efc86704556c5fe44b8bcbda9ac2106
7
+ data.tar.gz: fa5f47d42b4d823581706dc5644b1b7b0ff4b47232f4216667c9526065e01fa13d1d1f46424e815f6df4bfc42b5659a56dc4831e5af1928ca3151d63bd0a7b5f
@@ -0,0 +1,23 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: [ '2.5', '2.6', '2.7' ]
13
+
14
+ steps:
15
+ - name: Check out code
16
+ uses: actions/checkout@v2
17
+ - name: Set up ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: ${{ matrix.ruby }}
21
+ bundler-cache: true
22
+ - name: Test
23
+ run: "bundle exec rspec"
@@ -2,8 +2,8 @@ language: ruby
2
2
  dist: xenial
3
3
  sudo: false
4
4
  rvm:
5
- - 2.5.5
6
- - 2.6.3
5
+ - 2.5.8
6
+ - 2.6.6
7
7
  before_install:
8
8
  - gem update --system
9
9
  script: bundle exec rspec
data/README.md CHANGED
@@ -9,7 +9,7 @@ If this gem is used by anyone other than myself/Thinking Sphinx, I'll be surpris
9
9
  It's a gem - so you can either install it yourself, or add it to the appropriate Gemfile or gemspec.
10
10
 
11
11
  ```term
12
- gem install joiner --version 0.5.0
12
+ gem install joiner --version 0.6.0
13
13
  ```
14
14
 
15
15
  ## Usage
@@ -17,7 +17,7 @@ gem install joiner --version 0.5.0
17
17
  First, create a join collection, based on an ActiveRecord model:
18
18
 
19
19
  ```ruby
20
- joiner = Joiner::Joins.new user
20
+ joiner = Joiner::Joins.new User
21
21
  ```
22
22
 
23
23
  Then you can add joins for a given association path. For example, if User has many articles, and articles have many comments:
@@ -59,4 +59,4 @@ Please note that this project now has a [Contributor Code of Conduct](http://con
59
59
 
60
60
  ## Licence
61
61
 
62
- Copyright (c) 2013-2019, Joiner is developed and maintained by [Pat Allan](http://freelancing-gods.com), and is released under the open MIT Licence.
62
+ Copyright (c) 2013-2020, Joiner is developed and maintained by [Pat Allan](http://freelancing-gods.com), and is released under the open MIT Licence.
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  Gem::Specification.new do |spec|
3
3
  spec.name = 'joiner'
4
- spec.version = '0.5.0'
4
+ spec.version = '0.6.0'
5
5
  spec.authors = ['Pat Allan']
6
6
  spec.email = ['pat@freelancing-gods.com']
7
7
  spec.summary = %q{Builds ActiveRecord joins from association paths}
@@ -13,10 +13,10 @@ Gem::Specification.new do |spec|
13
13
  spec.test_files = spec.files.grep(%r{^(spec)/})
14
14
  spec.require_paths = ['lib']
15
15
 
16
- spec.add_runtime_dependency 'activerecord', '>= 6.0.0.rc2'
16
+ spec.add_runtime_dependency 'activerecord', '>= 6.1.0'
17
17
 
18
18
  spec.add_development_dependency 'combustion', '~> 1.1'
19
- spec.add_development_dependency 'rails', '>= 6.0.0.rc2'
20
- spec.add_development_dependency 'rspec-rails', '~> 3'
19
+ spec.add_development_dependency 'rails', '>= 6.1.0'
20
+ spec.add_development_dependency 'rspec-rails', '~> 4'
21
21
  spec.add_development_dependency 'sqlite3', '~> 1.4'
22
22
  end
@@ -6,6 +6,8 @@ module Joiner
6
6
  end
7
7
  end
8
8
 
9
+ require 'joiner/alias_tracker'
10
+ require 'joiner/join_aliaser'
9
11
  require 'joiner/join_dependency'
10
12
  require 'joiner/joins'
11
13
  require 'joiner/path'
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/conversions"
4
+
5
+ # This code is taken straight from Rails, prior to v6.1.0.
6
+ # I'm maintaining a copy here to save myself having to work through aliasing
7
+ # logic myself - there's a good chance I don't need all of thiis, but it'll do
8
+ # to get this gem working with Rails 6.1.
9
+
10
+ class Joiner::AliasTracker # :nodoc:
11
+ def self.create(connection, initial_table, joins, aliases = nil)
12
+ if joins.empty?
13
+ aliases ||= Hash.new(0)
14
+ elsif aliases
15
+ default_proc = aliases.default_proc || proc { 0 }
16
+ aliases.default_proc = proc { |h, k|
17
+ h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
18
+ }
19
+ else
20
+ aliases = Hash.new { |h, k|
21
+ h[k] = initial_count_for(connection, k, joins)
22
+ }
23
+ end
24
+ aliases[initial_table] = 1
25
+ new(connection, aliases)
26
+ end
27
+
28
+ def self.initial_count_for(connection, name, table_joins)
29
+ quoted_name = nil
30
+
31
+ counts = table_joins.map do |join|
32
+ if join.is_a?(Arel::Nodes::StringJoin)
33
+ # quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
34
+ quoted_name ||= connection.quote_table_name(name)
35
+
36
+ # Table names + table aliases
37
+ join.left.scan(
38
+ /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
39
+ ).size
40
+ elsif join.is_a?(Arel::Nodes::Join)
41
+ join.left.name == name ? 1 : 0
42
+ else
43
+ raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
44
+ end
45
+ end
46
+
47
+ counts.sum
48
+ end
49
+
50
+ # table_joins is an array of arel joins which might conflict with the aliases we assign here
51
+ def initialize(connection, aliases)
52
+ @aliases = aliases
53
+ @connection = connection
54
+ end
55
+
56
+ def aliased_table_for(table_name, aliased_name, type_caster)
57
+ if aliases[table_name].zero?
58
+ # If it's zero, we can have our table_name
59
+ aliases[table_name] = 1
60
+ Arel::Table.new(table_name, type_caster: type_caster)
61
+ else
62
+ # Otherwise, we need to use an alias
63
+ aliased_name = @connection.table_alias_for(aliased_name)
64
+
65
+ # Update the count
66
+ aliases[aliased_name] += 1
67
+
68
+ table_alias = if aliases[aliased_name] > 1
69
+ "#{truncate(aliased_name)}_#{aliases[aliased_name]}"
70
+ else
71
+ aliased_name
72
+ end
73
+ Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
74
+ end
75
+ end
76
+
77
+ attr_reader :aliases
78
+
79
+ private
80
+
81
+ def truncate(name)
82
+ name.slice(0, @connection.table_alias_length - 2)
83
+ end
84
+ end
@@ -0,0 +1,41 @@
1
+ # The core logic of this class is old Rails behaviour, replicated here because
2
+ # their own alias logic has evolved, but I haven't yet found a way to make use
3
+ # of it - and besides, this is only used to generate Thinking Sphinx's
4
+ # configuration rarely - not in any web requests, so performance issues are less
5
+ # critical here.
6
+
7
+ class Joiner::JoinAliaser
8
+ def self.call(join_root, alias_tracker)
9
+ new(join_root, alias_tracker).call
10
+ end
11
+
12
+ def initialize(join_root, alias_tracker)
13
+ @join_root = join_root
14
+ @alias_tracker = alias_tracker
15
+ end
16
+
17
+ def call
18
+ join_root.each_children do |parent, child|
19
+ child.table = table_aliases_for(parent, child).first
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :join_root, :alias_tracker
26
+
27
+ def table_aliases_for(parent, node)
28
+ node.reflection.chain.map { |reflection|
29
+ alias_tracker.aliased_table_for(
30
+ reflection.table_name,
31
+ table_alias_for(reflection, parent, reflection != node.reflection),
32
+ reflection.klass.type_caster
33
+ )
34
+ }
35
+ end
36
+
37
+ def table_alias_for(reflection, parent, join)
38
+ name = reflection.alias_candidate(parent.table_name)
39
+ join ? "#{name}_join" : name
40
+ end
41
+ end
@@ -1,7 +1,8 @@
1
1
  class Joiner::JoinDependency < ActiveRecord::Associations::JoinDependency
2
2
  def join_association_for(path, alias_tracker = nil)
3
3
  @alias_tracker = alias_tracker
4
- construct_tables! join_root
4
+
5
+ Joiner::JoinAliaser.call join_root, alias_tracker
5
6
 
6
7
  path.inject(join_root) do |node, piece|
7
8
  node.children.detect { |child| child.reflection.name == piece }
@@ -2,8 +2,6 @@ require 'active_record'
2
2
  require 'active_support/ordered_hash'
3
3
 
4
4
  class Joiner::Joins
5
- ACTIVE_RECORD_VERSION = Gem::Version.new(ActiveRecord::VERSION::STRING)
6
-
7
5
  attr_reader :model
8
6
 
9
7
  def initialize(model)
@@ -21,7 +19,7 @@ class Joiner::Joins
21
19
  return model.table_name if path.empty?
22
20
 
23
21
  add_join_to path
24
- association_for(path).tables.first.name
22
+ association_for(path).table.name
25
23
  end
26
24
 
27
25
  def join_values
@@ -35,7 +33,7 @@ class Joiner::Joins
35
33
  attr_reader :joins_cache
36
34
 
37
35
  def alias_tracker
38
- ActiveRecord::Associations::AliasTracker.create(
36
+ Joiner::AliasTracker.create(
39
37
  model.connection, table.name, []
40
38
  )
41
39
  end
@@ -3,7 +3,7 @@ require 'bundler/setup'
3
3
 
4
4
  require 'combustion'
5
5
 
6
- Combustion.initialize! :all
6
+ Combustion.initialize! :active_record
7
7
 
8
8
  require 'rspec/rails'
9
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joiner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-04 00:00:00.000000000 Z
11
+ date: 2020-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0.rc2
19
+ version: 6.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.0.rc2
26
+ version: 6.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: combustion
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 6.0.0.rc2
47
+ version: 6.1.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 6.0.0.rc2
54
+ version: 6.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec-rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3'
61
+ version: '4'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3'
68
+ version: '4'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +88,7 @@ executables: []
88
88
  extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
+ - ".github/workflows/ci.yml"
91
92
  - ".gitignore"
92
93
  - ".travis.yml"
93
94
  - Gemfile
@@ -96,6 +97,8 @@ files:
96
97
  - Rakefile
97
98
  - joiner.gemspec
98
99
  - lib/joiner.rb
100
+ - lib/joiner/alias_tracker.rb
101
+ - lib/joiner/join_aliaser.rb
99
102
  - lib/joiner/join_dependency.rb
100
103
  - lib/joiner/joins.rb
101
104
  - lib/joiner/path.rb
@@ -112,7 +115,7 @@ homepage: https://github.com/pat/joiner
112
115
  licenses:
113
116
  - MIT
114
117
  metadata: {}
115
- post_install_message:
118
+ post_install_message:
116
119
  rdoc_options: []
117
120
  require_paths:
118
121
  - lib
@@ -127,8 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
130
  - !ruby/object:Gem::Version
128
131
  version: '0'
129
132
  requirements: []
130
- rubygems_version: 3.0.4
131
- signing_key:
133
+ rubygems_version: 3.1.2
134
+ signing_key:
132
135
  specification_version: 4
133
136
  summary: Builds ActiveRecord joins from association paths
134
137
  test_files: