pg_ltree 1.1.9 → 1.2.1

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: ba0cf379067eb0d7c24ff36828795d78b6cbbdc5b6738c45427868164940516d
4
- data.tar.gz: c63501e14473075c2916567fdee20d974c09fe77d93c0553b9d16c185af436a1
3
+ metadata.gz: 3d8c4f4847b427a162fe71f52c16679988a238e3aa46aeab3a434b33ca283c36
4
+ data.tar.gz: e5c1f6888f28d81946b669fe89909f0782795f8f5a103ba5bb631b49e1916efc
5
5
  SHA512:
6
- metadata.gz: 8c8545986852ec4d61a2b9623a2142d4f79e2a3613d75fb7efff6511e70699531831527a625b89693b4b9d21c8bc7e4937f432bb14315ea82c01cc4a6eb34079
7
- data.tar.gz: 1be5c7b2a06dc1228ba07ab50284f5d6af6147a27bbec92fb6768b92d7f718399dacf6150532ea2c1939a5660cd62e7f650463d7f534301df5cde8b29d7e9fb6
6
+ metadata.gz: 202fe4cf0e53dd5b913a5fc1f1e8f263b4e82aec77de9bfb0907a94bd7bb93faef52cb352ef8ae3560e3e8baf6714dc488db2156365652bb57e4643049ea4cf5
7
+ data.tar.gz: df3b6dd34d6aa13d228fde6523d1b06ad0eb02b092c47b754374b06143be48f234290ee1eeb01617e90a107c446742fece71213a64f32aec1a5343d2911a0c5c
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,44 @@
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_options
32
+ @ltree_options || superclass.ltree_options
33
+ end
34
+
35
+ def ltree_option_for(key)
36
+ ltree_options[key]
37
+ end
38
+ end
39
+
40
+ included do
41
+ delegate :ltree_option_for, to: :class
42
+ end
43
+ end
44
+ 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.1".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.1
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-29 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
@@ -173,14 +195,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
195
  - !ruby/object:Gem::Version
174
196
  version: '0'
175
197
  requirements: []
176
- rubygems_version: 3.1.6
198
+ rubygems_version: 3.0.9
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