joiner 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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: