pg_ltree 1.1.9 → 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: ba0cf379067eb0d7c24ff36828795d78b6cbbdc5b6738c45427868164940516d
4
- data.tar.gz: c63501e14473075c2916567fdee20d974c09fe77d93c0553b9d16c185af436a1
3
+ metadata.gz: 10ef65e0c0c08d2f3670fb0c688eae0e549d40feded3b2c9e63db1109d50b6e2
4
+ data.tar.gz: c50d76b1d9157dca93b1f49748718300f066b5799672d655aacda68917f48891
5
5
  SHA512:
6
- metadata.gz: 8c8545986852ec4d61a2b9623a2142d4f79e2a3613d75fb7efff6511e70699531831527a625b89693b4b9d21c8bc7e4937f432bb14315ea82c01cc4a6eb34079
7
- data.tar.gz: 1be5c7b2a06dc1228ba07ab50284f5d6af6147a27bbec92fb6768b92d7f718399dacf6150532ea2c1939a5660cd62e7f650463d7f534301df5cde8b29d7e9fb6
6
+ metadata.gz: 6e6742bfcefacebf4124b782c96b1f4b4ada81da57f41f25ebb2dd2eaed7f5f15b32011fc1f8facda0e5648b6b279b604786216ddd1baf6254bec53be6c1ff5b
7
+ data.tar.gz: 62739b19de39ea1df10d1cd62ea48b981d103b2b54b149ab06f918157637f07f798a9a247811ab4e68b884bee2c85b1e1d15089fce30ec213e69a61bda74cfef
data/Rakefile CHANGED
@@ -1,22 +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'
5
-
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
6
+ RSpec::Core::RakeTask.new(:spec)
22
7
 
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,28 +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
- module Ltree
7
- # Initialzie ltree for active model
8
- #
9
- # @param column [String] ltree column name
10
- def ltree(column = :path, cascade: true)
11
- cattr_accessor :ltree_path_column
12
-
13
- self.ltree_path_column = column
14
-
15
- if cascade
16
- after_update :cascade_update
17
- after_destroy :cascade_destroy
18
- end
19
-
20
- extend ClassMethods
21
- include InstanceMethods
22
- 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
23
9
 
24
- # Define class methods
25
- module ClassMethods
26
10
  # Get roots
27
11
  #
28
12
  # @return [ActiveRecord::Relation] relations of node's roots
@@ -43,9 +27,9 @@ module PgLtree
43
27
  # @return [ActiveRecord::Relation] relations of node's leaves
44
28
  def leaves
45
29
  subquery = unscoped.select("#{table_name}.#{ltree_path_column}")
46
- .from("#{table_name} AS subquery")
47
- .where("#{table_name}.#{ltree_path_column} <> subquery.#{ltree_path_column}")
48
- .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}")
49
33
 
50
34
  where.not ltree_path_column => subquery
51
35
  end
@@ -67,8 +51,7 @@ module PgLtree
67
51
  end
68
52
  end
69
53
 
70
- # Define instance methods
71
- module InstanceMethods
54
+ included do
72
55
  # Get default scope of ltree
73
56
  #
74
57
  # @return current class
@@ -79,9 +62,7 @@ module PgLtree
79
62
  # Get lTree column
80
63
  #
81
64
  # @return [String] ltree column name
82
- def ltree_path_column
83
- ltree_scope.ltree_path_column
84
- end
65
+ delegate :ltree_path_column, to: :ltree_scope
85
66
 
86
67
  # Get lTree value
87
68
  #
@@ -138,21 +119,23 @@ module PgLtree
138
119
  #
139
120
  # return [Object] root node
140
121
  def root
141
- 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
142
123
  end
143
124
 
144
125
  # Get parent of the node
145
126
  #
146
127
  # return [Object] root node
147
128
  def parent
148
- 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
149
131
  end
150
132
 
151
133
  # Get leaves of the node
152
134
  #
153
135
  # @return [ActiveRecord::Relation]
154
136
  def leaves
155
- 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
156
139
  end
157
140
 
158
141
  # Check what current node have leaves
@@ -166,7 +149,7 @@ module PgLtree
166
149
  #
167
150
  # @return [ActiveRecord::Relation]
168
151
  def self_and_ancestors
169
- 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)
170
153
  end
171
154
 
172
155
  # Get ancestors
@@ -180,15 +163,7 @@ module PgLtree
180
163
  #
181
164
  # @return [ActiveRecord::Relation]
182
165
  def self_and_descendants
183
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path)
184
- end
185
-
186
- # Get self and descendants
187
- # @deprecated Please use {#self_and_descendants} instead
188
- # @return [ActiveRecord::Relation]
189
- def self_and_descendents
190
- warn '[DEPRECATION] `self_and_descendents` is deprecated. Please use `self_and_descendants` instead.'
191
- self_and_descendants
166
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path)
192
167
  end
193
168
 
194
169
  # Get descendants
@@ -198,20 +173,12 @@ module PgLtree
198
173
  self_and_descendants.where.not ltree_path_column => ltree_path
199
174
  end
200
175
 
201
- # Get descendants
202
- # @deprecated Please use {#descendants} instead
203
- # @return [ActiveRecord::Relation]
204
- def descendents
205
- warn '[DEPRECATION] `descendents` is deprecated. Please use `descendants` instead.'
206
- descendants
207
- end
208
-
209
176
  # Get self and siblings
210
177
  #
211
178
  # @return [ActiveRecord::Relation]
212
179
  def self_and_siblings
213
180
  ltree_scope.where(
214
- "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(?)",
215
182
  ltree_path, ltree_path, ltree_path
216
183
  )
217
184
  end
@@ -227,23 +194,25 @@ module PgLtree
227
194
  #
228
195
  # @return [ActiveRecord::Relation]
229
196
  def children
230
- ltree_scope.where "? @> #{ltree_scope.table_name}.#{ltree_path_column} AND nlevel(#{ltree_scope.table_name}.#{ltree_path_column}) = NLEVEL(?) + 1",
231
- 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
232
199
  end
233
200
 
234
201
  # Update all childen for current path
235
202
  #
236
203
  # @return [ActiveRecord::Relation]
237
204
  def cascade_update
238
- 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])
239
- .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)
240
209
  end
241
210
 
242
211
  # Delete all children for current path
243
212
  #
244
213
  # @return [ActiveRecord::Relation]
245
214
  def cascade_destroy
246
- ltree_scope.where("#{ltree_scope.table_name}.#{ltree_path_column} <@ ?", ltree_path_in_database).destroy_all
215
+ ltree_scope.where("#{self.class.table_name}.#{ltree_path_column} <@ ?", ltree_path_in_database).destroy_all
247
216
  end
248
217
  end
249
218
  end
@@ -1,4 +1,3 @@
1
- # Organize ActiveRecord model into a tree structure with PostgreSQL LTree
2
1
  module PgLtree
3
- VERSION = '1.1.9'.freeze
2
+ VERSION = "1.2.0".freeze
4
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.9
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Panamarenka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-12 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
@@ -36,7 +36,7 @@ dependencies:
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,34 +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'
122
+ version: 0.9.28
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: appraisal
125
125
  requirement: !ruby/object:Gem::Requirement
126
126
  requirements:
127
- - - ">="
127
+ - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: '0'
129
+ version: '2.4'
130
130
  type: :development
131
131
  prerelease: false
132
132
  version_requirements: !ruby/object:Gem::Requirement
133
133
  requirements:
134
- - - ">="
134
+ - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: '0'
137
- description: Organise ActiveRecord model into a tree structure with PostgreSQL LTree
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
138
166
  email:
139
167
  - andrei.panamarenka@gmail.com
140
168
  executables: []
@@ -144,16 +172,10 @@ files:
144
172
  - MIT-LICENSE
145
173
  - Rakefile
146
174
  - lib/pg_ltree.rb
147
- - lib/pg_ltree/ltree.rb
148
- - lib/pg_ltree/scoped_for.rb
175
+ - lib/pg_ltree/base.rb
176
+ - lib/pg_ltree/callbacks.rb
177
+ - lib/pg_ltree/model.rb
149
178
  - lib/pg_ltree/version.rb
150
- - lib/pg_ltree/versions/rails_older_than_51.rb
151
- - test/database.yml
152
- - test/database.yml.sample
153
- - test/pg_ltree/ltree_test.rb
154
- - test/pg_ltree/scoped_for_test.rb
155
- - test/pg_ltree_test.rb
156
- - test/test_helper.rb
157
179
  homepage: https://github.com/sjke/pg_ltree
158
180
  licenses:
159
181
  - MIT
@@ -176,11 +198,5 @@ requirements: []
176
198
  rubygems_version: 3.1.6
177
199
  signing_key:
178
200
  specification_version: 4
179
- summary: Organise ActiveRecord model into a tree structure with PostgreSQL LTree
180
- test_files:
181
- - test/database.yml.sample
182
- - test/pg_ltree_test.rb
183
- - test/database.yml
184
- - test/pg_ltree/scoped_for_test.rb
185
- - test/pg_ltree/ltree_test.rb
186
- - test/test_helper.rb
201
+ summary: Organize ActiveRecord model into a tree structure using PostgreSQL LTree
202
+ test_files: []
@@ -1,26 +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
- module ScopedFor
5
- # Define base instance scope for model by columns
6
- #
7
- # @param columns [Array] List of scoped fields
8
- def ltree_scoped_for(columns = [])
9
- cattr_accessor :ltree_scoped_for
10
-
11
- self.ltree_scoped_for = Array.wrap(columns)
12
-
13
- include InstanceMethods
14
- end
15
-
16
- # Define instance methods
17
- module InstanceMethods
18
- # Get default scope of ltree
19
- #
20
- # @return current class
21
- def ltree_scope
22
- self.class.where(*(ltree_scoped_for.map { |column| { column => public_send(column) } }))
23
- end
24
- end
25
- end
26
- 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: postgres
5
- database: pg_ltree_test
@@ -1,249 +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
- Top.Collections.Videos
21
- Top.Collections.Videos.Vacation
22
- Top.Collections.Videos.NewYear
23
- ).each do |path|
24
- TreeNode.create! path: path
25
- end
26
- end
27
-
28
- test 'Default configuration' do
29
- assert_equal TreeNode.ltree_path_column, :path
30
- end
31
-
32
- test 'Custom configuration' do
33
- assert_equal NotUniqTreeNode.ltree_path_column, :new_path
34
- end
35
-
36
- test '#roots' do
37
- assert_equal TreeNode.roots.pluck(:path), ['Top']
38
- end
39
-
40
- test '#at_depth' do
41
- assert_equal TreeNode.at_depth(5).pluck(:path), %w(
42
- Top.Collections.Pictures.Astronomy.Stars
43
- Top.Collections.Pictures.Astronomy.Galaxies
44
- Top.Collections.Pictures.Astronomy.Astronauts
45
- )
46
- end
47
-
48
- test '#leaves' do
49
- assert_equal TreeNode.leaves.pluck(:path), %w(
50
- Top.Science.Astronomy.Astrophysics
51
- Top.Science.Astronomy.Cosmology
52
- Top.Hobbies.Amateurs_Astronomy
53
- Top.Collections.Pictures.Astronomy.Stars
54
- Top.Collections.Pictures.Astronomy.Galaxies
55
- Top.Collections.Pictures.Astronomy.Astronauts
56
- Top.Collections.Videos.Vacation
57
- Top.Collections.Videos.NewYear
58
- )
59
- end
60
-
61
- test '#leaves with a relation' do
62
- assert_equal TreeNode.where("path <> 'Top.Collections.Pictures.Astronomy.Stars'").leaves.pluck(:path), %w(
63
- Top.Science.Astronomy.Astrophysics
64
- Top.Science.Astronomy.Cosmology
65
- Top.Hobbies.Amateurs_Astronomy
66
- Top.Collections.Pictures.Astronomy.Galaxies
67
- Top.Collections.Pictures.Astronomy.Astronauts
68
- Top.Collections.Videos.Vacation
69
- Top.Collections.Videos.NewYear
70
- )
71
- end
72
-
73
- test '#where_path_liked' do
74
- assert_equal TreeNode.where_path_liked('*{2}.Astronomy|Pictures').pluck(:path), %w(
75
- Top.Science.Astronomy
76
- Top.Collections.Pictures
77
- )
78
- end
79
-
80
- test '#where_path_matches_ltxtquery' do
81
- assert_equal TreeNode.where_path_matches_ltxtquery('Astro*% & !pictures@').pluck(:path), %w(
82
- Top.Science.Astronomy
83
- Top.Science.Astronomy.Astrophysics
84
- Top.Science.Astronomy.Cosmology
85
- Top.Hobbies.Amateurs_Astronomy
86
- )
87
- end
88
-
89
- test '.root?' do
90
- assert TreeNode.find_by(path: 'Top').root?
91
- assert_not TreeNode.find_by(path: 'Top.Science').root?
92
- end
93
-
94
- test '.height' do
95
- assert_equal 4, TreeNode.find_by(path: 'Top').height
96
- assert_equal 0, TreeNode.find_by(path: 'Top.Science.Astronomy.Astrophysics').height
97
- end
98
-
99
- test '.depth' do
100
- assert_equal TreeNode.find_by(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
101
- end
102
-
103
- test '.depth on new record' do
104
- assert_equal TreeNode.new(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
105
- end
106
-
107
- test '.depth on new record when database is empty' do
108
- TreeNode.delete_all
109
- assert_equal TreeNode.new(path: 'Top.Hobbies.Amateurs_Astronomy').depth, 3
110
- end
111
-
112
- test '.root' do
113
- assert_equal TreeNode.find_by(path: 'Top.Hobbies.Amateurs_Astronomy').root.path, 'Top'
114
- end
115
-
116
- test '.parent' do
117
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').parent.path,
118
- 'Top.Collections.Pictures.Astronomy'
119
- end
120
-
121
- test '.leaves' do
122
- assert_equal TreeNode.find_by(path: 'Top.Science').leaves.pluck(:path), %w(
123
- Top.Science.Astronomy.Astrophysics
124
- Top.Science.Astronomy.Cosmology
125
- )
126
- end
127
-
128
- test '.leaf?' do
129
- assert_not TreeNode.find_by(path: 'Top').leaf?
130
- assert TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').leaf?
131
- end
132
-
133
- test '.self_and_ancestors' do
134
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').self_and_ancestors.pluck(:path), %w(
135
- Top
136
- Top.Collections
137
- Top.Collections.Pictures
138
- Top.Collections.Pictures.Astronomy
139
- Top.Collections.Pictures.Astronomy.Astronauts
140
- )
141
- end
142
-
143
- test '.ancestors' do
144
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Astronauts').ancestors.pluck(:path), %w(
145
- Top
146
- Top.Collections
147
- Top.Collections.Pictures
148
- Top.Collections.Pictures.Astronomy
149
- )
150
- end
151
-
152
- test '.self_and_descendants' do
153
- assert_equal TreeNode.find_by(path: 'Top.Science').self_and_descendants.pluck(:path), %w(
154
- Top.Science
155
- Top.Science.Astronomy
156
- Top.Science.Astronomy.Astrophysics
157
- Top.Science.Astronomy.Cosmology
158
- )
159
- end
160
-
161
- test '.descendants' do
162
- assert_equal TreeNode.find_by(path: 'Top.Science').descendants.pluck(:path), %w(
163
- Top.Science.Astronomy
164
- Top.Science.Astronomy.Astrophysics
165
- Top.Science.Astronomy.Cosmology
166
- )
167
- end
168
-
169
- test '.self_and_siblings' do
170
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Stars').self_and_siblings.pluck(:path), %w(
171
- Top.Collections.Pictures.Astronomy.Stars
172
- Top.Collections.Pictures.Astronomy.Galaxies
173
- Top.Collections.Pictures.Astronomy.Astronauts
174
- )
175
- end
176
-
177
- test '.siblings' do
178
- assert_equal TreeNode.find_by(path: 'Top.Collections.Pictures.Astronomy.Stars').siblings.pluck(:path), %w(
179
- Top.Collections.Pictures.Astronomy.Galaxies
180
- Top.Collections.Pictures.Astronomy.Astronauts
181
- )
182
- end
183
-
184
- test '.children' do
185
- assert_equal TreeNode.find_by(path: 'Top.Hobbies').children.pluck(:path), %w(
186
- Top.Hobbies.Amateurs_Astronomy
187
- )
188
- end
189
-
190
- test '.cascade_update' do
191
- node = TreeNode.find_by(path: 'Top.Hobbies')
192
- node.update path: 'Top.WoW'
193
-
194
- assert_equal node.self_and_descendants.pluck(:path), %w(
195
- Top.WoW
196
- Top.WoW.Amateurs_Astronomy
197
- )
198
- end
199
-
200
- test '.cascade_destroy' do
201
- assert_equal TreeNode.where("path <@ 'Top.Collections'").pluck(:path), %w(
202
- Top.Collections
203
- Top.Collections.Pictures
204
- Top.Collections.Pictures.Astronomy
205
- Top.Collections.Pictures.Astronomy.Stars
206
- Top.Collections.Pictures.Astronomy.Galaxies
207
- Top.Collections.Pictures.Astronomy.Astronauts
208
- Top.Collections.Videos
209
- Top.Collections.Videos.Vacation
210
- Top.Collections.Videos.NewYear
211
- )
212
-
213
- TreeNode.find_by(path: 'Top.Collections.Pictures').destroy
214
-
215
- assert_equal TreeNode.where("path <@ 'Top.Collections'").pluck(:path), %w(
216
- Top.Collections
217
- Top.Collections.Videos
218
- Top.Collections.Videos.Vacation
219
- Top.Collections.Videos.NewYear
220
- )
221
- end
222
-
223
- test '.destroy' do
224
- assert_equal TreeWithoutCascadeNode.where("path <@ 'Top.Collections'").pluck(:path), %w(
225
- Top.Collections
226
- Top.Collections.Pictures
227
- Top.Collections.Pictures.Astronomy
228
- Top.Collections.Pictures.Astronomy.Stars
229
- Top.Collections.Pictures.Astronomy.Galaxies
230
- Top.Collections.Pictures.Astronomy.Astronauts
231
- Top.Collections.Videos
232
- Top.Collections.Videos.Vacation
233
- Top.Collections.Videos.NewYear
234
- )
235
-
236
- TreeWithoutCascadeNode.find_by(path: 'Top.Collections.Pictures').destroy
237
-
238
- assert_equal TreeWithoutCascadeNode.where("path <@ 'Top.Collections'").pluck(:path), %w(
239
- Top.Collections
240
- Top.Collections.Pictures.Astronomy
241
- Top.Collections.Pictures.Astronomy.Stars
242
- Top.Collections.Pictures.Astronomy.Galaxies
243
- Top.Collections.Pictures.Astronomy.Astronauts
244
- Top.Collections.Videos
245
- Top.Collections.Videos.Vacation
246
- Top.Collections.Videos.NewYear
247
- )
248
- end
249
- end
@@ -1,190 +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
- Top.Collections.Videos
21
- Top.Collections.Videos.Vacation
22
- Top.Collections.Videos.NewYear
23
- ).each do |path|
24
- %i( active deactive ).each do |status|
25
- NotUniqTreeNode.create! new_path: path, status: status
26
- end
27
- end
28
- end
29
-
30
- test '#roots' do
31
- assert_equal NotUniqTreeNode.roots.pluck(:new_path), %w(Top Top)
32
- end
33
-
34
- test '#at_depth' do
35
- assert_equal NotUniqTreeNode.at_depth(5).pluck(:new_path), %w(
36
- Top.Collections.Pictures.Astronomy.Stars
37
- Top.Collections.Pictures.Astronomy.Stars
38
- Top.Collections.Pictures.Astronomy.Galaxies
39
- Top.Collections.Pictures.Astronomy.Galaxies
40
- Top.Collections.Pictures.Astronomy.Astronauts
41
- Top.Collections.Pictures.Astronomy.Astronauts
42
- )
43
- end
44
-
45
- test '#leaves' do
46
- assert_equal NotUniqTreeNode.where(status: :active).leaves.pluck(:new_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
- Top.Collections.Videos.Vacation
54
- Top.Collections.Videos.NewYear
55
- )
56
- end
57
-
58
- test '#where_path_liked' do
59
- assert_equal NotUniqTreeNode.where_path_liked('*{2}.Astronomy|Pictures').pluck(:new_path), %w(
60
- Top.Science.Astronomy
61
- Top.Science.Astronomy
62
- Top.Collections.Pictures
63
- Top.Collections.Pictures
64
- )
65
- end
66
-
67
- def not_uniq_tree_node_find_by_path(path)
68
- NotUniqTreeNode.find_by(status: :active, new_path: path)
69
- end
70
-
71
- test '.root?' do
72
- assert not_uniq_tree_node_find_by_path('Top').root?
73
- assert_not not_uniq_tree_node_find_by_path('Top.Science').root?
74
- end
75
-
76
- test '.depth' do
77
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies.Amateurs_Astronomy').depth, 3
78
- end
79
-
80
- test '.root' do
81
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies.Amateurs_Astronomy').root.new_path, 'Top'
82
- end
83
-
84
- test '.parent' do
85
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').parent.new_path,
86
- 'Top.Collections.Pictures.Astronomy'
87
- end
88
-
89
- test '.leaves' do
90
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').leaves.pluck(:new_path), %w(
91
- Top.Science.Astronomy.Astrophysics
92
- Top.Science.Astronomy.Cosmology
93
- )
94
- end
95
-
96
- test '.leaf?' do
97
- assert_not not_uniq_tree_node_find_by_path('Top').leaf?
98
- assert not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').leaf?
99
- end
100
-
101
- test '.self_and_ancestors' do
102
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').self_and_ancestors.pluck(:new_path), %w(
103
- Top
104
- Top.Collections
105
- Top.Collections.Pictures
106
- Top.Collections.Pictures.Astronomy
107
- Top.Collections.Pictures.Astronomy.Astronauts
108
- )
109
- end
110
-
111
- test '.ancestors' do
112
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Astronauts').ancestors.pluck(:new_path), %w(
113
- Top
114
- Top.Collections
115
- Top.Collections.Pictures
116
- Top.Collections.Pictures.Astronomy
117
- )
118
- end
119
-
120
- test '.self_and_descendants' do
121
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').self_and_descendants.pluck(:new_path), %w(
122
- Top.Science
123
- Top.Science.Astronomy
124
- Top.Science.Astronomy.Astrophysics
125
- Top.Science.Astronomy.Cosmology
126
- )
127
- end
128
-
129
- test '.descendants' do
130
- assert_equal not_uniq_tree_node_find_by_path('Top.Science').descendants.pluck(:new_path), %w(
131
- Top.Science.Astronomy
132
- Top.Science.Astronomy.Astrophysics
133
- Top.Science.Astronomy.Cosmology
134
- )
135
- end
136
-
137
- test '.self_and_siblings' do
138
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Stars').self_and_siblings.pluck(:new_path), %w(
139
- Top.Collections.Pictures.Astronomy.Stars
140
- Top.Collections.Pictures.Astronomy.Galaxies
141
- Top.Collections.Pictures.Astronomy.Astronauts
142
- )
143
- end
144
-
145
- test '.siblings' do
146
- assert_equal not_uniq_tree_node_find_by_path('Top.Collections.Pictures.Astronomy.Stars').siblings.pluck(:new_path), %w(
147
- Top.Collections.Pictures.Astronomy.Galaxies
148
- Top.Collections.Pictures.Astronomy.Astronauts
149
- )
150
- end
151
-
152
- test '.children' do
153
- assert_equal not_uniq_tree_node_find_by_path('Top.Hobbies').children.pluck(:new_path), %w(
154
- Top.Hobbies.Amateurs_Astronomy
155
- )
156
- end
157
-
158
- test '.cascade_update' do
159
- node = NotUniqTreeNode.find_by(new_path: 'Top.Hobbies', status: :active)
160
- node.update new_path: 'Top.WoW'
161
-
162
- assert_equal node.self_and_descendants.pluck(:new_path), %w(
163
- Top.WoW
164
- Top.WoW.Amateurs_Astronomy
165
- )
166
- end
167
-
168
- test '.cascade_destroy' do
169
- assert_equal NotUniqTreeNode.where("new_path <@ 'Top.Collections'").where(status: :active).pluck(:new_path), %w(
170
- Top.Collections
171
- Top.Collections.Pictures
172
- Top.Collections.Pictures.Astronomy
173
- Top.Collections.Pictures.Astronomy.Stars
174
- Top.Collections.Pictures.Astronomy.Galaxies
175
- Top.Collections.Pictures.Astronomy.Astronauts
176
- Top.Collections.Videos
177
- Top.Collections.Videos.Vacation
178
- Top.Collections.Videos.NewYear
179
- )
180
-
181
- NotUniqTreeNode.find_by(new_path: 'Top.Collections.Pictures', status: :active).destroy
182
-
183
- assert_equal NotUniqTreeNode.where("new_path <@ 'Top.Collections'").where(status: :active).pluck(:new_path), %w(
184
- Top.Collections
185
- Top.Collections.Videos
186
- Top.Collections.Videos.Vacation
187
- Top.Collections.Videos.NewYear
188
- )
189
- end
190
- 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,85 +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
- $VERBOSE=nil
11
-
12
- require 'pg'
13
- require 'pg_ltree'
14
- require 'minitest/autorun'
15
-
16
- class BaseTest < ActiveSupport::TestCase
17
- def setup
18
- prepare_db
19
- end
20
-
21
- def teardown
22
- drop_db
23
- end
24
-
25
- private
26
-
27
- def prepare_db
28
- begin
29
- db_connection = YAML.load_file(File.expand_path('../database.yml', __FILE__))
30
- rescue => e
31
- $stderr.puts e.message
32
- $stderr.puts 'Copy `test/database.yml.sample` to `test/database.yml` and configure connection to DB'
33
- exit 0
34
- end
35
-
36
- begin
37
- PG.connect(host: db_connection["host"], user: db_connection["username"], password: db_connection["password"])
38
- .exec("CREATE DATABASE #{db_connection['database']}")
39
- rescue
40
- # Ignore errors on DB:CEATE
41
- end
42
-
43
- ActiveRecord::Base.establish_connection db_connection
44
- ActiveRecord::Schema.verbose = false
45
-
46
- ActiveRecord::Schema.define(version: 1) do
47
- enable_extension 'plpgsql'
48
- enable_extension 'ltree'
49
-
50
- create_table 'not_uniq_tree_nodes', force: :cascade do |t|
51
- t.string 'status'
52
- t.ltree 'new_path'
53
- end
54
-
55
- create_table 'tree_nodes', force: :cascade do |t|
56
- t.ltree 'path'
57
- end
58
- end
59
- end
60
-
61
- def drop_db
62
- tables = if ActiveRecord::VERSION::MAJOR < 5
63
- ActiveRecord::Base.connection.tables
64
- else
65
- ActiveRecord::Base.connection.data_sources
66
- end
67
- tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
68
- end
69
- end
70
-
71
- class NotUniqTreeNode < ActiveRecord::Base
72
- extend PgLtree::ScopedFor
73
-
74
- ltree :new_path
75
- ltree_scoped_for :status
76
- end
77
-
78
- class TreeNode < ActiveRecord::Base
79
- ltree
80
- end
81
-
82
- class TreeWithoutCascadeNode < ActiveRecord::Base
83
- self.table_name = 'tree_nodes'
84
- ltree :path, cascade: false
85
- end