pg_ltree 1.1.8 → 1.2.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: af73780dad2653e9068d80d56ad53a1cac86f88968cbe9f697bc832e42aedcf6
4
- data.tar.gz: a4bea89ea088fe18ce1a5d5ce9606bceecb1833a36b9ec4ce7b252bcde5e7f83
3
+ metadata.gz: 10ef65e0c0c08d2f3670fb0c688eae0e549d40feded3b2c9e63db1109d50b6e2
4
+ data.tar.gz: c50d76b1d9157dca93b1f49748718300f066b5799672d655aacda68917f48891
5
5
  SHA512:
6
- metadata.gz: '086bcf6439fdfd185d738ab1c120c41192567f8d3e9c1ee456c0ef82bf28d0e6c921d9c9a397ff5cacd7735dfc21605c078ade8927266e6685ef7fefbc1d0b58'
7
- data.tar.gz: 9317b961bd9ae4f6ff781c3aa72bf2b5ee0c5136bb6b2a28482853a8c0262278f5a00daf6d8b4dfd71302d4e2b52975abc8e4f2b0629fffdb03037d95ca51ced
6
+ metadata.gz: 6e6742bfcefacebf4124b782c96b1f4b4ada81da57f41f25ebb2dd2eaed7f5f15b32011fc1f8facda0e5648b6b279b604786216ddd1baf6254bec53be6c1ff5b
7
+ data.tar.gz: 62739b19de39ea1df10d1cd62ea48b981d103b2b54b149ab06f918157637f07f798a9a247811ab4e68b884bee2c85b1e1d15089fce30ec213e69a61bda74cfef
data/Rakefile CHANGED
@@ -1,51 +1,8 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
+ require "standard/rake"
3
+ require "rspec/core/rake_task"
4
+ require "appraisal"
2
5
 
3
- require 'rake/testtask'
4
- require 'rdoc/task'
6
+ RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- gemspec = eval(File.read(Dir['*.gemspec'].first))
7
-
8
- RDoc::Task.new(:rdoc) do |rdoc|
9
- rdoc.rdoc_dir = 'rdoc'
10
- rdoc.title = 'PgLtree'
11
- rdoc.options << '--line-numbers'
12
- rdoc.rdoc_files.include('README.rdoc')
13
- rdoc.rdoc_files.include('lib/**/*.rb')
14
- end
15
-
16
- Rake::TestTask.new(:test) do |t|
17
- t.libs << 'lib'
18
- t.libs << 'test'
19
- t.pattern = 'test/**/*_test.rb'
20
- t.verbose = false
21
- end
22
-
23
- desc 'Default: run unit tests.'
24
- task default: 'test:all'
25
-
26
- namespace :test do
27
- AVAILABLE_CASES = %w(
28
- activerecord_40_pg_017 activerecord_40_pg_018
29
- activerecord_41_pg_017 activerecord_41_pg_018
30
- activerecord_42_pg_017 activerecord_42_pg_018
31
- activerecord_50_pg_018 activerecord_51_pg_020
32
- activerecord_51_pg_021 activerecord_52_pg_100
33
- activerecord_60_pg_021 activerecord_60_pg_100
34
- activerecord_60_pg_110
35
- ).freeze
36
-
37
- AVAILABLE_CASES.each do |version|
38
- desc "Test pg_ltree against #{version}"
39
- task version do
40
- sh "bundle install --gemfile=gemfiles/#{version}.gemfile --quiet"
41
- sh "BUNDLE_GEMFILE='gemfiles/#{version}.gemfile' bundle exec rake -t test"
42
- end
43
- end
44
-
45
- desc 'Run all tests for pg_ltree'
46
- task :all do
47
- AVAILABLE_CASES.each do |version|
48
- sh "rake test:#{version}"
49
- end
50
- end
51
- end
8
+ task default: :spec
@@ -0,0 +1,40 @@
1
+ require_relative "model"
2
+ require_relative "callbacks"
3
+
4
+ module PgLtree
5
+ module Base
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ attr_reader :ltree_options
10
+
11
+ # Initialize ltree module for the model
12
+ #
13
+ # @param column [String] lTree column name
14
+ # @param cascade_update [Boolean] Update all child nodes when the self path is changed
15
+ # @param cascade_destroy [Boolean] Destroy all child nodes on self-destroying
16
+ def ltree(column = :path, cascade_update: true, cascade_destroy: true, cascade: nil)
17
+ if cascade
18
+ ActiveSupport::Deprecation.warn("'cascade' param is deprecated. Use 'cascade_update' and 'cascade_destroy' instead.")
19
+ end
20
+
21
+ @ltree_options = {
22
+ column: column,
23
+ cascade_update: cascade.nil? ? cascade_update : cascade,
24
+ cascade_destroy: cascade.nil? ? cascade_destroy : cascade
25
+ }
26
+
27
+ send(:include, PgLtree::Model)
28
+ send(:include, PgLtree::Callbacks)
29
+ end
30
+
31
+ def ltree_option_for(key)
32
+ ltree_options[key]
33
+ end
34
+ end
35
+
36
+ included do
37
+ delegate :ltree_option_for, to: :class
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ module PgLtree
2
+ module Callbacks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ after_commit :cascade_update, on: :update, if: -> { ltree_option_for :cascade_update }
7
+ after_commit :cascade_destroy, on: :destroy, if: -> { ltree_option_for :cascade_destroy }
8
+
9
+ # Update child nodes path
10
+ #
11
+ # @return [ActiveRecord::Relation]
12
+ def cascade_update
13
+ ltree_scope
14
+ .where(["#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path_before_last_save])
15
+ .where(["#{self.class.table_name}.#{ltree_path_column} != ?", ltree_path])
16
+ .update_all ["#{ltree_path_column} = ? || subpath(#{ltree_path_column}, nlevel(?))", ltree_path, ltree_path_before_last_save]
17
+ end
18
+
19
+ # Destroy child nodes
20
+ #
21
+ # @return [ActiveRecord::Relation]
22
+ def cascade_destroy
23
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path_in_database).destroy_all
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,30 +1,12 @@
1
1
  module PgLtree
2
- # Implementatios Postgres ltree for ActiveRecord
3
- #
4
- # @see [ActiveRecord::Base]
5
- # @see http://www.postgresql.org/docs/current/static/ltree.html
6
- #
7
- # @author a.ponomarenko
8
- module Ltree
9
- # Initialzie ltree for active model
10
- #
11
- # @param column [String] ltree column name
12
- def ltree(column = :path, options: { cascade: true })
13
- cattr_accessor :ltree_path_column
14
-
15
- self.ltree_path_column = column
16
-
17
- if options[:cascade]
18
- after_update :cascade_update
19
- after_destroy :cascade_destroy
20
- end
21
-
22
- extend ClassMethods
23
- include InstanceMethods
24
- end
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+
5
+ class_methods do
6
+ def ltree_path_column
7
+ ltree_option_for :column
8
+ end
25
9
 
26
- # Define class methods
27
- module ClassMethods
28
10
  # Get roots
29
11
  #
30
12
  # @return [ActiveRecord::Relation] relations of node's roots
@@ -45,9 +27,9 @@ module PgLtree
45
27
  # @return [ActiveRecord::Relation] relations of node's leaves
46
28
  def leaves
47
29
  subquery = unscoped.select("#{table_name}.#{ltree_path_column}")
48
- .from("#{table_name} AS subquery")
49
- .where("#{table_name}.#{ltree_path_column} <> subquery.#{ltree_path_column}")
50
- .where("#{table_name}.#{ltree_path_column} @> subquery.#{ltree_path_column}")
30
+ .from("#{table_name} AS subquery")
31
+ .where("#{table_name}.#{ltree_path_column} <> subquery.#{ltree_path_column}")
32
+ .where("#{table_name}.#{ltree_path_column} @> subquery.#{ltree_path_column}")
51
33
 
52
34
  where.not ltree_path_column => subquery
53
35
  end
@@ -69,8 +51,7 @@ module PgLtree
69
51
  end
70
52
  end
71
53
 
72
- # Define instance methods
73
- module InstanceMethods
54
+ included do
74
55
  # Get default scope of ltree
75
56
  #
76
57
  # @return current class
@@ -81,9 +62,7 @@ module PgLtree
81
62
  # Get lTree column
82
63
  #
83
64
  # @return [String] ltree column name
84
- def ltree_path_column
85
- ltree_scope.ltree_path_column
86
- end
65
+ delegate :ltree_path_column, to: :ltree_scope
87
66
 
88
67
  # Get lTree value
89
68
  #
@@ -140,21 +119,23 @@ module PgLtree
140
119
  #
141
120
  # return [Object] root node
142
121
  def root
143
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} = SUBPATH(?, 0, 1)", ltree_path).first
122
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} = SUBPATH(?, 0, 1)", ltree_path).first
144
123
  end
145
124
 
146
125
  # Get parent of the node
147
126
  #
148
127
  # return [Object] root node
149
128
  def parent
150
- ltree_scope.find_by "#{ltree_scope.table_name}.#{ltree_path_column} = SUBPATH(?, 0, NLEVEL(?) - 1)", ltree_path, ltree_path
129
+ ltree_scope.find_by "#{self.class.table_name}.#{ltree_path_column} = SUBPATH(?, 0, NLEVEL(?) - 1)", ltree_path,
130
+ ltree_path
151
131
  end
152
132
 
153
133
  # Get leaves of the node
154
134
  #
155
135
  # @return [ActiveRecord::Relation]
156
136
  def leaves
157
- ltree_scope.leaves.where("#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path).where.not ltree_path_column => ltree_path
137
+ ltree_scope.leaves.where("#{self.class.table_name}.#{ltree_path_column} <@ ?",
138
+ ltree_path).where.not ltree_path_column => ltree_path
158
139
  end
159
140
 
160
141
  # Check what current node have leaves
@@ -168,7 +149,7 @@ module PgLtree
168
149
  #
169
150
  # @return [ActiveRecord::Relation]
170
151
  def self_and_ancestors
171
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} @> ?", ltree_path)
152
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} @> ?", ltree_path)
172
153
  end
173
154
 
174
155
  # Get ancestors
@@ -182,15 +163,7 @@ module PgLtree
182
163
  #
183
164
  # @return [ActiveRecord::Relation]
184
165
  def self_and_descendants
185
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path)
186
- end
187
-
188
- # Get self and descendants
189
- # @deprecated Please use {#self_and_descendants} instead
190
- # @return [ActiveRecord::Relation]
191
- def self_and_descendents
192
- warn '[DEPRECATION] `self_and_descendents` is deprecated. Please use `self_and_descendants` instead.'
193
- self_and_descendants
166
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path)
194
167
  end
195
168
 
196
169
  # Get descendants
@@ -200,20 +173,12 @@ module PgLtree
200
173
  self_and_descendants.where.not ltree_path_column => ltree_path
201
174
  end
202
175
 
203
- # Get descendants
204
- # @deprecated Please use {#descendants} instead
205
- # @return [ActiveRecord::Relation]
206
- def descendents
207
- warn '[DEPRECATION] `descendents` is deprecated. Please use `descendants` instead.'
208
- descendants
209
- end
210
-
211
176
  # Get self and siblings
212
177
  #
213
178
  # @return [ActiveRecord::Relation]
214
179
  def self_and_siblings
215
180
  ltree_scope.where(
216
- "SUBPATH(?, 0, NLEVEL(?) - 1) @> #{ltree_scope.table_name}.#{ltree_path_column} AND nlevel(#{ltree_scope.table_name}.#{ltree_path_column}) = NLEVEL(?)",
181
+ "SUBPATH(?, 0, NLEVEL(?) - 1) @> #{self.class.table_name}.#{ltree_path_column} AND nlevel(#{self.class.table_name}.#{ltree_path_column}) = NLEVEL(?)",
217
182
  ltree_path, ltree_path, ltree_path
218
183
  )
219
184
  end
@@ -229,23 +194,25 @@ module PgLtree
229
194
  #
230
195
  # @return [ActiveRecord::Relation]
231
196
  def children
232
- ltree_scope.where "? @> #{ltree_scope.table_name}.#{ltree_path_column} AND nlevel(#{ltree_scope.table_name}.#{ltree_path_column}) = NLEVEL(?) + 1",
233
- ltree_path, ltree_path
197
+ ltree_scope.where "? @> #{self.class.table_name}.#{ltree_path_column} AND nlevel(#{self.class.table_name}.#{ltree_path_column}) = NLEVEL(?) + 1",
198
+ ltree_path, ltree_path
234
199
  end
235
200
 
236
201
  # Update all childen for current path
237
202
  #
238
203
  # @return [ActiveRecord::Relation]
239
204
  def cascade_update
240
- ltree_scope.where(["#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path_before_last_save]).where(["#{ltree_scope.table_name}.#{ltree_path_column} != ?", ltree_path])
241
- .update_all ["#{ltree_path_column} = ? || subpath(#{ltree_path_column}, nlevel(?))", ltree_path, ltree_path_before_last_save]
205
+ ltree_scope
206
+ .where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path_before_last_save)
207
+ .where("#{self.class.table_name}.#{ltree_path_column} != ?", ltree_path)
208
+ .update_all("#{ltree_path_column} = ? || subpath(#{ltree_path_column}, nlevel(?))", ltree_path, ltree_path_before_last_save)
242
209
  end
243
210
 
244
211
  # Delete all children for current path
245
212
  #
246
213
  # @return [ActiveRecord::Relation]
247
214
  def cascade_destroy
248
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path_in_database).delete_all
215
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path_in_database).destroy_all
249
216
  end
250
217
  end
251
218
  end
@@ -1,7 +1,3 @@
1
- # Organize ActiveRecord model into a tree structure with PostgreSQL LTree
2
- #
3
- # @author a.ponomarenko
4
1
  module PgLtree
5
- # Gem Version
6
- VERSION = '1.1.8'.freeze
2
+ VERSION = "1.2.0".freeze
7
3
  end
data/lib/pg_ltree.rb CHANGED
@@ -1,17 +1,9 @@
1
- require 'active_record'
2
- require 'pg_ltree/ltree'
3
- require 'pg_ltree/scoped_for'
4
- require 'pg_ltree/version'
1
+ require "active_support"
5
2
 
6
- Dir[File.expand_path('../pg_ltree/versions/**/*.rb', __FILE__)].each { |file| require file }
7
-
8
- if defined?(ActiveRecord)
9
- ActiveRecord::Base.extend(PgLtree::Ltree)
3
+ module PgLtree
4
+ autoload :Base, "pg_ltree/base"
5
+ end
10
6
 
11
- # The behavior of _was changes in Rails 5.1
12
- # http://blog.toshima.ru/2017/04/06/saved-change-to-attribute.html
13
- # This is for backward compability
14
- if ActiveRecord::VERSION::MAJOR < 5 || (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR < 1)
15
- ActiveRecord::Base.extend(PgLtree::Versions::RailsOlderThan51)
16
- end
7
+ ActiveSupport.on_load(:active_record) do
8
+ ActiveRecord::Base.include PgLtree::Base
17
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_ltree
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Panamarenka
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-13 00:00:00.000000000 Z
11
+ date: 2022-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,27 +16,27 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.0.0
20
- - - "<="
19
+ version: '5.2'
20
+ - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 7.0.0.rc1
22
+ version: '8.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 4.0.0
30
- - - "<="
29
+ version: '5.2'
30
+ - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 7.0.0.rc1
32
+ version: '8.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: pg
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.17.0
39
+ version: '0.19'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '2'
@@ -46,7 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 0.17.0
49
+ version: '0.19'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '2'
@@ -93,7 +93,7 @@ dependencies:
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  - !ruby/object:Gem::Dependency
96
- name: yard
96
+ name: standard
97
97
  requirement: !ruby/object:Gem::Requirement
98
98
  requirements:
99
99
  - - ">="
@@ -107,20 +107,62 @@ dependencies:
107
107
  - !ruby/object:Gem::Version
108
108
  version: '0'
109
109
  - !ruby/object:Gem::Dependency
110
- name: minitest
110
+ name: yard
111
111
  requirement: !ruby/object:Gem::Requirement
112
112
  requirements:
113
- - - ">="
113
+ - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '0'
115
+ version: 0.9.28
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
- - - ">="
120
+ - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '0'
123
- description: Organise ActiveRecord model into a tree structure with PostgreSQL LTree
122
+ version: 0.9.28
123
+ - !ruby/object:Gem::Dependency
124
+ name: appraisal
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '2.4'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '2.4'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.11'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '3.11'
151
+ - !ruby/object:Gem::Dependency
152
+ name: database_cleaner
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '2.0'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '2.0'
165
+ description: Organize ActiveRecord model into a tree structure using PostgreSQL LTree
124
166
  email:
125
167
  - andrei.panamarenka@gmail.com
126
168
  executables: []
@@ -130,21 +172,15 @@ files:
130
172
  - MIT-LICENSE
131
173
  - Rakefile
132
174
  - lib/pg_ltree.rb
133
- - lib/pg_ltree/ltree.rb
134
- - lib/pg_ltree/scoped_for.rb
175
+ - lib/pg_ltree/base.rb
176
+ - lib/pg_ltree/callbacks.rb
177
+ - lib/pg_ltree/model.rb
135
178
  - lib/pg_ltree/version.rb
136
- - lib/pg_ltree/versions/rails_older_than_51.rb
137
- - test/database.yml
138
- - test/database.yml.sample
139
- - test/pg_ltree/ltree_test.rb
140
- - test/pg_ltree/scoped_for_test.rb
141
- - test/pg_ltree_test.rb
142
- - test/test_helper.rb
143
179
  homepage: https://github.com/sjke/pg_ltree
144
180
  licenses:
145
181
  - MIT
146
182
  metadata: {}
147
- post_install_message:
183
+ post_install_message:
148
184
  rdoc_options: []
149
185
  require_paths:
150
186
  - lib
@@ -159,14 +195,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
195
  - !ruby/object:Gem::Version
160
196
  version: '0'
161
197
  requirements: []
162
- rubygems_version: 3.1.0.pre2
163
- signing_key:
198
+ rubygems_version: 3.1.6
199
+ signing_key:
164
200
  specification_version: 4
165
- summary: Organise ActiveRecord model into a tree structure with PostgreSQL LTree
166
- test_files:
167
- - test/database.yml.sample
168
- - test/pg_ltree_test.rb
169
- - test/database.yml
170
- - test/pg_ltree/scoped_for_test.rb
171
- - test/pg_ltree/ltree_test.rb
172
- - test/test_helper.rb
201
+ summary: Organize ActiveRecord model into a tree structure using PostgreSQL LTree
202
+ test_files: []
@@ -1,28 +0,0 @@
1
- module PgLtree
2
- # Narrowing the Scope for ActiveRecord Model
3
- # @note When model have composite uniq key (for example: state + path), you should use this module for narrowing the scope
4
- #
5
- # @author a.ponomarenko
6
- module ScopedFor
7
- # Define base instance scope for model by columns
8
- #
9
- # @param columns [Array] List of scoped fields
10
- def ltree_scoped_for(columns = [])
11
- cattr_accessor :ltree_scoped_for
12
-
13
- self.ltree_scoped_for = Array.wrap(columns)
14
-
15
- include InstanceMethods
16
- end
17
-
18
- # Define instance methods
19
- module InstanceMethods
20
- # Get default scope of ltree
21
- #
22
- # @return current class
23
- def ltree_scope
24
- self.class.where *(ltree_scoped_for.map { |column| { column => public_send(column) } })
25
- end
26
- end
27
- end
28
- end
@@ -1,28 +0,0 @@
1
- module PgLtree
2
- module Versions
3
- module RailsOlderThan51
4
- def ltree(column = :path, options: { cascade: true })
5
- super
6
- include InstanceMethods
7
- end
8
-
9
- module InstanceMethods
10
- # Get lTree previous value
11
- #
12
- # Related changes in > Rails 5.1.0
13
- # https://github.com/rails/rails/pull/25337
14
- #
15
- # @return [String] Rails 5.1 replace attribute_was method with two methods, this is a wrapper for older rails
16
- def ltree_path_before_last_save
17
- public_send :attribute_was, ltree_path_column
18
- end
19
-
20
- #
21
- # @return [String] Rails 5.1 replace attribute_was method with two methods, this is a wrapper for older rails
22
- def ltree_path_in_database
23
- public_send :attribute_was, ltree_path_column
24
- end
25
- end
26
- end
27
- end
28
- end
data/test/database.yml DELETED
@@ -1,5 +0,0 @@
1
- adapter: postgresql
2
- host: localhost
3
- username: postgres
4
- password:
5
- database: pg_ltree_test
@@ -1,5 +0,0 @@
1
- adapter: postgresql
2
- host: localhost
3
- username: postgres
4
- password:
5
- database: pg_ltree_test
@@ -1,198 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PgLtree::LtreeTest < BaseTest
4
- def setup
5
- super
6
- %w(
7
- Top
8
- Top.Science
9
- Top.Science.Astronomy
10
- Top.Science.Astronomy.Astrophysics
11
- Top.Science.Astronomy.Cosmology
12
- Top.Hobbies
13
- Top.Hobbies.Amateurs_Astronomy
14
- Top.Collections
15
- Top.Collections.Pictures
16
- Top.Collections.Pictures.Astronomy
17
- Top.Collections.Pictures.Astronomy.Stars
18
- Top.Collections.Pictures.Astronomy.Galaxies
19
- Top.Collections.Pictures.Astronomy.Astronauts
20
- ).each do |path|
21
- TreeNode.create! path: path
22
- end
23
- end
24
-
25
- test 'Default configuration' do
26
- assert_equal TreeNode.ltree_path_column, :path
27
- end
28
-
29
- test 'Custom configuration' do
30
- assert_equal NotUniqTreeNode.ltree_path_column, :new_path
31
- end
32
-
33
- test '#roots' do
34
- assert_equal TreeNode.roots.pluck(:path), ['Top']
35
- end
36
-
37
- test '#at_depth' do
38
- assert_equal TreeNode.at_depth(5).pluck(:path), %w(
39
- Top.Collections.Pictures.Astronomy.Stars
40
- Top.Collections.Pictures.Astronomy.Galaxies
41
- Top.Collections.Pictures.Astronomy.Astronauts
42
- )
43
- end
44
-
45
- test '#leaves' do
46
- assert_equal TreeNode.leaves.pluck(:path), %w(
47
- Top.Science.Astronomy.Astrophysics
48
- Top.Science.Astronomy.Cosmology
49
- Top.Hobbies.Amateurs_Astronomy
50
- Top.Collections.Pictures.Astronomy.Stars
51
- Top.Collections.Pictures.Astronomy.Galaxies
52
- Top.Collections.Pictures.Astronomy.Astronauts
53
- )
54
- end
55
-
56
- test '#leaves with a relation' do
57
- assert_equal TreeNode.where("path <> 'Top.Collections.Pictures.Astronomy.Stars'").leaves.pluck(:path), %w(
58
- Top.Science.Astronomy.Astrophysics
59
- Top.Science.Astronomy.Cosmology
60
- Top.Hobbies.Amateurs_Astronomy
61
- Top.Collections.Pictures.Astronomy.Galaxies
62
- Top.Collections.Pictures.Astronomy.Astronauts
63
- )
64
- end
65
-
66
- test '#where_path_liked' do
67
- assert_equal TreeNode.where_path_liked('*{2}.Astronomy|Pictures').pluck(:path), %w(
68
- Top.Science.Astronomy
69
- Top.Collections.Pictures
70
- )
71
- end
72
-
73
- test '#where_path_matches_ltxtquery' do
74
- assert_equal TreeNode.where_path_matches_ltxtquery('Astro*% & !pictures@').pluck(:path), %w(
75
- Top.Science.Astronomy
76
- Top.Science.Astronomy.Astrophysics
77
- Top.Science.Astronomy.Cosmology
78
- Top.Hobbies.Amateurs_Astronomy
79
- )
80
- end
81
-
82
- test '.root?' do
83
- assert TreeNode.find_by(path: 'Top').root?
84
- assert_not TreeNode.find_by(path: 'Top.Science').root?
85
- end
86
-
87
- test '.height' do
88
- assert_equal 4, TreeNode.find_by(path: 'Top').height
89
- assert_equal 0, TreeNode.find_by(path: 'Top.Science.Astronomy.Astrophysics').height
90
- end
91
-
92
- test '.depth' do
93
- assert_equal TreeNode.find_by(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
94
- end
95
-
96
- test '.depth on new record' do
97
- assert_equal TreeNode.new(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
98
- end
99
-
100
- test '.depth on new record when database is empty' do
101
- TreeNode.delete_all
102
- assert_equal TreeNode.new(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
103
- end
104
-
105
- test '.root' do
106
- assert_equal TreeNode.find_by(path: 'Top.Hobbies.Amateurs_Astronomy').root.path, 'Top'
107
- end
108
-
109
- test '.parent' do
110
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').parent.path,
111
- 'Top.Collections.Pictures.Astronomy'
112
- end
113
-
114
- test '.leaves' do
115
- assert_equal TreeNode.find_by(path: 'Top.Science').leaves.pluck(:path), %w(
116
- Top.Science.Astronomy.Astrophysics
117
- Top.Science.Astronomy.Cosmology
118
- )
119
- end
120
-
121
- test '.leaf?' do
122
- assert_not TreeNode.find_by(path: 'Top').leaf?
123
- assert TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').leaf?
124
- end
125
-
126
- test '.self_and_ancestors' do
127
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').self_and_ancestors.pluck(:path), %w(
128
- Top
129
- Top.Collections
130
- Top.Collections.Pictures
131
- Top.Collections.Pictures.Astronomy
132
- Top.Collections.Pictures.Astronomy.Astronauts
133
- )
134
- end
135
-
136
- test '.ancestors' do
137
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').ancestors.pluck(:path), %w(
138
- Top
139
- Top.Collections
140
- Top.Collections.Pictures
141
- Top.Collections.Pictures.Astronomy
142
- )
143
- end
144
-
145
- test '.self_and_descendants' do
146
- assert_equal TreeNode.find_by(path: 'Top.Science').self_and_descendants.pluck(:path), %w(
147
- Top.Science
148
- Top.Science.Astronomy
149
- Top.Science.Astronomy.Astrophysics
150
- Top.Science.Astronomy.Cosmology
151
- )
152
- end
153
-
154
- test '.descendants' do
155
- assert_equal TreeNode.find_by(path: 'Top.Science').descendants.pluck(:path), %w(
156
- Top.Science.Astronomy
157
- Top.Science.Astronomy.Astrophysics
158
- Top.Science.Astronomy.Cosmology
159
- )
160
- end
161
-
162
- test '.self_and_siblings' do
163
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Stars').self_and_siblings.pluck(:path), %w(
164
- Top.Collections.Pictures.Astronomy.Stars
165
- Top.Collections.Pictures.Astronomy.Galaxies
166
- Top.Collections.Pictures.Astronomy.Astronauts
167
- )
168
- end
169
-
170
- test '.siblings' do
171
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Stars').siblings.pluck(:path), %w(
172
- Top.Collections.Pictures.Astronomy.Galaxies
173
- Top.Collections.Pictures.Astronomy.Astronauts
174
- )
175
- end
176
-
177
- test '.children' do
178
- assert_equal TreeNode.find_by(path: 'Top.Hobbies').children.pluck(:path), %w(
179
- Top.Hobbies.Amateurs_Astronomy
180
- )
181
- end
182
-
183
- test '.cascade_update' do
184
- node = TreeNode.find_by(path: 'Top.Hobbies')
185
- node.update path: 'Top.WoW'
186
-
187
- assert_equal node.self_and_descendants.pluck(:path), %w(
188
- Top.WoW
189
- Top.WoW.Amateurs_Astronomy
190
- )
191
- end
192
-
193
- test '.cascade_destroy' do
194
- TreeNode.find_by(path: 'Top.Collections').destroy
195
-
196
- assert_equal TreeNode.where("path ~ 'Top.Collections'").pluck(:path), %w()
197
- end
198
- end
@@ -1,192 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PgLtree::ScopedForTest < BaseTest
4
- def setup
5
- super
6
- %w(
7
- Top
8
- Top.Science
9
- Top.Science.Astronomy
10
- Top.Science.Astronomy.Astrophysics
11
- Top.Science.Astronomy.Cosmology
12
- Top.Hobbies
13
- Top.Hobbies.Amateurs_Astronomy
14
- Top.Collections
15
- Top.Collections.Pictures
16
- Top.Collections.Pictures.Astronomy
17
- Top.Collections.Pictures.Astronomy.Stars
18
- Top.Collections.Pictures.Astronomy.Galaxies
19
- Top.Collections.Pictures.Astronomy.Astronauts
20
- ).each do |path|
21
- %i( active deactive ).each do |status|
22
- NotUniqTreeNode.create! new_path: path, status: status
23
- end
24
- end
25
- end
26
-
27
- test '#roots' do
28
- assert_equal NotUniqTreeNode.roots.pluck(:new_path), %w(Top Top)
29
- end
30
-
31
- test '#at_depth' do
32
- assert_equal NotUniqTreeNode.at_depth(5).pluck(:new_path), %w(
33
- Top.Collections.Pictures.Astronomy.Stars
34
- Top.Collections.Pictures.Astronomy.Stars
35
- Top.Collections.Pictures.Astronomy.Galaxies
36
- Top.Collections.Pictures.Astronomy.Galaxies
37
- Top.Collections.Pictures.Astronomy.Astronauts
38
- Top.Collections.Pictures.Astronomy.Astronauts
39
- )
40
- end
41
-
42
- test '#leaves' do
43
- assert_equal NotUniqTreeNode.where(status: :active).leaves.pluck(:new_path), %w(
44
- Top.Science.Astronomy.Astrophysics
45
- Top.Science.Astronomy.Cosmology
46
- Top.Hobbies.Amateurs_Astronomy
47
- Top.Collections.Pictures.Astronomy.Stars
48
- Top.Collections.Pictures.Astronomy.Galaxies
49
- Top.Collections.Pictures.Astronomy.Astronauts
50
- )
51
- end
52
-
53
- test '#where_path_liked' do
54
- assert_equal NotUniqTreeNode.where_path_liked('*{2}.Astronomy|Pictures').pluck(:new_path), %w(
55
- Top.Science.Astronomy
56
- Top.Science.Astronomy
57
- Top.Collections.Pictures
58
- Top.Collections.Pictures
59
- )
60
- end
61
-
62
- def not_uniq_tree_node_find_by_path(path)
63
- NotUniqTreeNode.find_by(status: :active, new_path: path)
64
- end
65
-
66
- test '.root?' do
67
- assert not_uniq_tree_node_find_by_path('Top').root?
68
- assert_not not_uniq_tree_node_find_by_path('Top.Science').root?
69
- end
70
-
71
- test '.depth' do
72
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies.Amateurs_Astronomy').depth, 3
73
- end
74
-
75
- test '.root' do
76
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies.Amateurs_Astronomy').root.new_path, 'Top'
77
- end
78
-
79
- test '.parent' do
80
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').parent.new_path,
81
- 'Top.Collections.Pictures.Astronomy'
82
- end
83
-
84
- test '.leaves' do
85
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').leaves.pluck(:new_path), %w(
86
- Top.Science.Astronomy.Astrophysics
87
- Top.Science.Astronomy.Cosmology
88
- )
89
- end
90
-
91
- test '.leaf?' do
92
- assert_not not_uniq_tree_node_find_by_path('Top').leaf?
93
- assert not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').leaf?
94
- end
95
-
96
- test '.self_and_ancestors' do
97
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').self_and_ancestors.pluck(:new_path), %w(
98
- Top
99
- Top.Collections
100
- Top.Collections.Pictures
101
- Top.Collections.Pictures.Astronomy
102
- Top.Collections.Pictures.Astronomy.Astronauts
103
- )
104
- end
105
-
106
- test '.ancestors' do
107
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').ancestors.pluck(:new_path), %w(
108
- Top
109
- Top.Collections
110
- Top.Collections.Pictures
111
- Top.Collections.Pictures.Astronomy
112
- )
113
- end
114
-
115
- test '.self_and_descendants' do
116
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').self_and_descendants.pluck(:new_path), %w(
117
- Top.Science
118
- Top.Science.Astronomy
119
- Top.Science.Astronomy.Astrophysics
120
- Top.Science.Astronomy.Cosmology
121
- )
122
- end
123
-
124
- test '.descendants' do
125
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').descendants.pluck(:new_path), %w(
126
- Top.Science.Astronomy
127
- Top.Science.Astronomy.Astrophysics
128
- Top.Science.Astronomy.Cosmology
129
- )
130
- end
131
-
132
- test '.self_and_siblings' do
133
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Stars').self_and_siblings.pluck(:new_path), %w(
134
- Top.Collections.Pictures.Astronomy.Stars
135
- Top.Collections.Pictures.Astronomy.Galaxies
136
- Top.Collections.Pictures.Astronomy.Astronauts
137
- )
138
- end
139
-
140
- test '.siblings' do
141
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Stars').siblings.pluck(:new_path), %w(
142
- Top.Collections.Pictures.Astronomy.Galaxies
143
- Top.Collections.Pictures.Astronomy.Astronauts
144
- )
145
- end
146
-
147
- test '.children' do
148
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies').children.pluck(:new_path), %w(
149
- Top.Hobbies.Amateurs_Astronomy
150
- )
151
- end
152
-
153
- test '.cascade_update' do
154
- node = NotUniqTreeNode.find_by(new_path: 'Top.Hobbies', status: :active)
155
- node.update new_path: 'Top.WoW'
156
-
157
- assert_equal node.self_and_descendants.pluck(:new_path), %w(
158
- Top.WoW
159
- Top.WoW.Amateurs_Astronomy
160
- )
161
- end
162
-
163
- test '.cascade_destroy' do
164
- assert_equal NotUniqTreeNode.where("new_path <@ 'Top.Collections'").pluck(:new_path), %w(
165
- Top.Collections
166
- Top.Collections
167
- Top.Collections.Pictures
168
- Top.Collections.Pictures
169
- Top.Collections.Pictures.Astronomy
170
- Top.Collections.Pictures.Astronomy
171
- Top.Collections.Pictures.Astronomy.Stars
172
- Top.Collections.Pictures.Astronomy.Stars
173
- Top.Collections.Pictures.Astronomy.Galaxies
174
- Top.Collections.Pictures.Astronomy.Galaxies
175
- Top.Collections.Pictures.Astronomy.Astronauts
176
- Top.Collections.Pictures.Astronomy.Astronauts
177
- )
178
-
179
- NotUniqTreeNode.find_by(new_path: 'Top.Collections', status: :active).destroy
180
-
181
- assert_equal NotUniqTreeNode.where("new_path <@ 'Top.Collections'").where(status: :active).pluck(:new_path), %w()
182
-
183
- assert_equal NotUniqTreeNode.where("new_path <@ 'Top.Collections'").where(status: :deactive).pluck(:new_path), %w(
184
- Top.Collections
185
- Top.Collections.Pictures
186
- Top.Collections.Pictures.Astronomy
187
- Top.Collections.Pictures.Astronomy.Stars
188
- Top.Collections.Pictures.Astronomy.Galaxies
189
- Top.Collections.Pictures.Astronomy.Astronauts
190
- )
191
- end
192
- end
@@ -1,7 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PgLtreeTest < ActiveSupport::TestCase
4
- test 'truth' do
5
- assert_kind_of Module, PgLtree
6
- end
7
- end
data/test/test_helper.rb DELETED
@@ -1,78 +0,0 @@
1
- require 'bundler'
2
- begin
3
- Bundler.require(:default, :development)
4
- rescue Bundler::BundlerError => e
5
- $stderr.puts e.message
6
- $stderr.puts 'Run `bundle install` to install missing gems'
7
- exit e.status_code
8
- end
9
-
10
- require 'pg'
11
- require 'pg_ltree'
12
- require 'minitest/autorun'
13
-
14
- class BaseTest < ActiveSupport::TestCase
15
- def setup
16
- prepare_db
17
- end
18
-
19
- def teardown
20
- drop_db
21
- end
22
-
23
- private
24
-
25
- def prepare_db
26
- begin
27
- db_connection = YAML.load_file(File.expand_path('../database.yml', __FILE__))
28
- rescue => e
29
- $stderr.puts e.message
30
- $stderr.puts 'Copy `test/database.yml.sample` to `test/database.yml` and configure connection to DB'
31
- exit 0
32
- end
33
-
34
- begin
35
- PG.connect(host: db_connection["host"], user: db_connection["username"], password: db_connection["password"])
36
- .exec("CREATE DATABASE #{db_connection['database']}")
37
- rescue
38
- # Ignore errors on DB:CEATE
39
- end
40
-
41
- ActiveRecord::Base.establish_connection db_connection
42
- ActiveRecord::Schema.verbose = false
43
-
44
- ActiveRecord::Schema.define(version: 1) do
45
- enable_extension 'plpgsql'
46
- enable_extension 'ltree'
47
-
48
- create_table 'not_uniq_tree_nodes', force: :cascade do |t|
49
- t.string 'status'
50
- t.ltree 'new_path'
51
- end
52
-
53
- create_table 'tree_nodes', force: :cascade do |t|
54
- t.ltree 'path'
55
- end
56
- end
57
- end
58
-
59
- def drop_db
60
- tables = if ActiveRecord::VERSION::MAJOR < 5
61
- ActiveRecord::Base.connection.tables
62
- else
63
- ActiveRecord::Base.connection.data_sources
64
- end
65
- tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
66
- end
67
- end
68
-
69
- class NotUniqTreeNode < ActiveRecord::Base
70
- extend PgLtree::ScopedFor
71
-
72
- ltree :new_path
73
- ltree_scoped_for :status
74
- end
75
-
76
- class TreeNode < ActiveRecord::Base
77
- ltree
78
- end