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 +4 -4
- data/Rakefile +6 -49
- data/lib/pg_ltree/base.rb +40 -0
- data/lib/pg_ltree/callbacks.rb +27 -0
- data/lib/pg_ltree/{ltree.rb → model.rb} +27 -60
- data/lib/pg_ltree/version.rb +1 -5
- data/lib/pg_ltree.rb +6 -14
- metadata +68 -38
- data/lib/pg_ltree/scoped_for.rb +0 -28
- data/lib/pg_ltree/versions/rails_older_than_51.rb +0 -28
- data/test/database.yml +0 -5
- data/test/database.yml.sample +0 -5
- data/test/pg_ltree/ltree_test.rb +0 -198
- data/test/pg_ltree/scoped_for_test.rb +0 -192
- data/test/pg_ltree_test.rb +0 -7
- data/test/test_helper.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 10ef65e0c0c08d2f3670fb0c688eae0e549d40feded3b2c9e63db1109d50b6e2
|
|
4
|
+
data.tar.gz: c50d76b1d9157dca93b1f49748718300f066b5799672d655aacda68917f48891
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6e6742bfcefacebf4124b782c96b1f4b4ada81da57f41f25ebb2dd2eaed7f5f15b32011fc1f8facda0e5648b6b279b604786216ddd1baf6254bec53be6c1ff5b
|
|
7
|
+
data.tar.gz: 62739b19de39ea1df10d1cd62ea48b981d103b2b54b149ab06f918157637f07f798a9a247811ab4e68b884bee2c85b1e1d15089fce30ec213e69a61bda74cfef
|
data/Rakefile
CHANGED
|
@@ -1,51 +1,8 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "standard/rake"
|
|
3
|
+
require "rspec/core/rake_task"
|
|
4
|
+
require "appraisal"
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
require 'rdoc/task'
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
5
7
|
|
|
6
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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("#{
|
|
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 "#{
|
|
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("#{
|
|
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("#{
|
|
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("#{
|
|
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) @> #{
|
|
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 "? @> #{
|
|
233
|
-
|
|
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
|
|
241
|
-
|
|
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("#{
|
|
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
|
data/lib/pg_ltree/version.rb
CHANGED
data/lib/pg_ltree.rb
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
require
|
|
2
|
-
require 'pg_ltree/ltree'
|
|
3
|
-
require 'pg_ltree/scoped_for'
|
|
4
|
-
require 'pg_ltree/version'
|
|
1
|
+
require "active_support"
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ActiveRecord::Base.extend(PgLtree::Ltree)
|
|
3
|
+
module PgLtree
|
|
4
|
+
autoload :Base, "pg_ltree/base"
|
|
5
|
+
end
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
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.
|
|
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:
|
|
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:
|
|
20
|
-
- - "
|
|
19
|
+
version: '5.2'
|
|
20
|
+
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version:
|
|
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:
|
|
30
|
-
- - "
|
|
29
|
+
version: '5.2'
|
|
30
|
+
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
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.
|
|
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.
|
|
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:
|
|
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:
|
|
110
|
+
name: yard
|
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
|
112
112
|
requirements:
|
|
113
|
-
- - "
|
|
113
|
+
- - "~>"
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
|
-
version:
|
|
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:
|
|
123
|
-
|
|
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/
|
|
134
|
-
- lib/pg_ltree/
|
|
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.
|
|
163
|
-
signing_key:
|
|
198
|
+
rubygems_version: 3.1.6
|
|
199
|
+
signing_key:
|
|
164
200
|
specification_version: 4
|
|
165
|
-
summary:
|
|
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: []
|
data/lib/pg_ltree/scoped_for.rb
DELETED
|
@@ -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
data/test/database.yml.sample
DELETED
data/test/pg_ltree/ltree_test.rb
DELETED
|
@@ -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
|
data/test/pg_ltree_test.rb
DELETED
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
|