ltree_hierarchy 0.0.6 → 0.0.7
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/CHANGELOG.md +7 -0
- data/Gemfile.lock +26 -14
- data/Rakefile +7 -7
- data/init.rb +1 -0
- data/lib/ltree_hierarchy/hierarchy.rb +29 -24
- data/lib/ltree_hierarchy/version.rb +1 -1
- data/ltree_hierarchy.gemspec +31 -0
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0585962140ffc7543e0575b23b594e45a6fa3fe
|
4
|
+
data.tar.gz: a56c281183b6e21796066fa59e391a4d95b4f874
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 550602c092d26f7655ffaf3f657496c44f75d5684263b80729a39a9a9de5030687bcaeab097f0ba7d2db0707bf5c66107de987ac92d338d6e6e154b2c0424b8a
|
7
|
+
data.tar.gz: d18adbfe3ef8cca05cda4a4a9138dcec0f40522faee33f805ed17e0234d1cd44af55aff7ef1996b0492e41dac49d9b1fb8f09db82f0df6b32d33bdff5ac188cf
|
data/CHANGELOG.md
ADDED
data/Gemfile.lock
CHANGED
@@ -1,34 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ltree_hierarchy (0.0.
|
4
|
+
ltree_hierarchy (0.0.6)
|
5
5
|
activerecord (>= 3.1.0)
|
6
6
|
pg
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activemodel (4.1
|
12
|
-
activesupport (= 4.1
|
11
|
+
activemodel (4.2.1)
|
12
|
+
activesupport (= 4.2.1)
|
13
13
|
builder (~> 3.1)
|
14
|
-
activerecord (4.1
|
15
|
-
activemodel (= 4.1
|
16
|
-
activesupport (= 4.1
|
17
|
-
arel (~>
|
18
|
-
activesupport (4.1
|
19
|
-
i18n (~> 0.
|
14
|
+
activerecord (4.2.1)
|
15
|
+
activemodel (= 4.2.1)
|
16
|
+
activesupport (= 4.2.1)
|
17
|
+
arel (~> 6.0)
|
18
|
+
activesupport (4.2.1)
|
19
|
+
i18n (~> 0.7)
|
20
20
|
json (~> 1.7, >= 1.7.7)
|
21
21
|
minitest (~> 5.1)
|
22
|
-
thread_safe (~> 0.
|
22
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
23
23
|
tzinfo (~> 1.1)
|
24
|
-
arel (
|
24
|
+
arel (6.0.0)
|
25
25
|
builder (3.2.2)
|
26
|
+
coderay (1.1.0)
|
26
27
|
i18n (0.7.0)
|
27
28
|
json (1.8.2)
|
28
|
-
|
29
|
-
|
29
|
+
method_source (0.8.2)
|
30
|
+
minitest (5.6.1)
|
31
|
+
pg (0.18.2)
|
32
|
+
pry (0.10.1)
|
33
|
+
coderay (~> 1.1.0)
|
34
|
+
method_source (~> 0.8.1)
|
35
|
+
slop (~> 3.4)
|
36
|
+
pry-nav (0.2.4)
|
37
|
+
pry (>= 0.9.10, < 0.11.0)
|
30
38
|
rake (10.4.2)
|
31
|
-
|
39
|
+
slop (3.6.0)
|
40
|
+
thread_safe (0.3.5)
|
32
41
|
tzinfo (1.2.2)
|
33
42
|
thread_safe (~> 0.1)
|
34
43
|
|
@@ -37,4 +46,7 @@ PLATFORMS
|
|
37
46
|
|
38
47
|
DEPENDENCIES
|
39
48
|
ltree_hierarchy!
|
49
|
+
minitest
|
50
|
+
pry
|
51
|
+
pry-nav
|
40
52
|
rake
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rake"
|
2
|
+
require "rake/testtask"
|
3
3
|
|
4
|
-
desc
|
5
|
-
task :
|
4
|
+
desc "Default: run unit tests."
|
5
|
+
task default: :test
|
6
6
|
|
7
|
-
desc
|
7
|
+
desc "Test the ltree_hierarchy plugin."
|
8
8
|
Rake::TestTask.new(:test) do |t|
|
9
|
-
t.libs <<
|
10
|
-
t.pattern =
|
9
|
+
t.libs << "lib"
|
10
|
+
t.pattern = "test/**/*_test.rb"
|
11
11
|
t.verbose = true
|
12
12
|
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "ltree_hierarchy"
|
@@ -2,49 +2,51 @@ module Ltree
|
|
2
2
|
module Hierarchy
|
3
3
|
def has_ltree_hierarchy(options = {})
|
4
4
|
options = {
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
5
|
+
fragment: :id,
|
6
|
+
parent_fragment: :parent_id,
|
7
|
+
path: :path
|
8
8
|
}.merge(options)
|
9
9
|
|
10
10
|
options.assert_valid_keys(:fragment, :parent_fragment, :path)
|
11
11
|
|
12
12
|
cattr_accessor :ltree_fragment_column, :ltree_parent_fragment_column, :ltree_path_column
|
13
13
|
|
14
|
-
self.ltree_fragment_column
|
14
|
+
self.ltree_fragment_column = options[:fragment]
|
15
15
|
self.ltree_parent_fragment_column = options[:parent_fragment]
|
16
|
-
self.ltree_path_column
|
16
|
+
self.ltree_path_column = options[:path]
|
17
17
|
|
18
|
-
belongs_to :parent, :
|
18
|
+
belongs_to :parent, class_name: name, foreign_key: ltree_parent_fragment_column
|
19
19
|
|
20
|
-
validate :prevent_circular_paths, :
|
20
|
+
validate :prevent_circular_paths, if: :ltree_parent_fragment_changed?
|
21
21
|
|
22
|
-
after_create
|
23
|
-
before_update :assign_path, :cascade_path_change, :
|
22
|
+
after_create :commit_path
|
23
|
+
before_update :assign_path, :cascade_path_change, if: :ltree_parent_fragment_changed?
|
24
24
|
|
25
25
|
include InstanceMethods
|
26
26
|
end
|
27
27
|
|
28
28
|
def roots
|
29
|
-
where(
|
29
|
+
where(ltree_parent_fragment_column => nil)
|
30
30
|
end
|
31
31
|
|
32
32
|
def at_depth(depth)
|
33
|
-
where(["
|
33
|
+
where(["NLEVEL(#{ltree_path_column}) = ?", depth])
|
34
34
|
end
|
35
35
|
|
36
36
|
def leaves
|
37
|
-
subquery =
|
37
|
+
subquery = where("#{ltree_parent_fragment_column} IS NOT NULL")
|
38
|
+
.select("DISTINCT #{ltree_parent_fragment_column}")
|
39
|
+
|
38
40
|
where("#{ltree_fragment_column} NOT IN(#{subquery.to_sql})")
|
39
41
|
end
|
40
42
|
|
41
43
|
def lowest_common_ancestor_paths(paths)
|
42
44
|
sql = if paths.respond_to?(:to_sql)
|
43
|
-
"SELECT
|
45
|
+
"SELECT LCA(ARRAY(#{paths.to_sql}))"
|
44
46
|
else
|
45
47
|
return [] if paths.empty?
|
46
48
|
safe_paths = paths.map { |p| "#{connection.quote(p)}::ltree" }
|
47
|
-
"SELECT
|
49
|
+
"SELECT LCA(ARRAY[#{safe_paths.join(", ")}])"
|
48
50
|
end
|
49
51
|
connection.select_values(sql)
|
50
52
|
end
|
@@ -63,7 +65,7 @@ module Ltree
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def ltree_fragment
|
66
|
-
send(
|
68
|
+
send(ltree_fragment_column)
|
67
69
|
end
|
68
70
|
|
69
71
|
def ltree_parent_fragment_column
|
@@ -91,7 +93,7 @@ module Ltree
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def prevent_circular_paths
|
94
|
-
if parent && parent.ltree_path.split(
|
96
|
+
if parent && parent.ltree_path.split(".").include?(ltree_fragment.to_s)
|
95
97
|
errors.add(ltree_parent_fragment_column, :invalid)
|
96
98
|
end
|
97
99
|
end
|
@@ -118,14 +120,14 @@ module Ltree
|
|
118
120
|
# SET path = NEW.path || subpath(path, nlevel(OLD.path))
|
119
121
|
# WHERE path <@ OLD.path AND id != NEW.id;
|
120
122
|
ltree_scope.where(
|
121
|
-
["#{ltree_path_column} <@ :old_path AND #{ltree_fragment_column} != :id", :
|
123
|
+
["#{ltree_path_column} <@ :old_path AND #{ltree_fragment_column} != :id", old_path: ltree_path_was, id: ltree_fragment]
|
122
124
|
).update_all(
|
123
|
-
["#{ltree_path_column} = :new_path || subpath(#{ltree_path_column}, nlevel(:old_path))", :
|
125
|
+
["#{ltree_path_column} = :new_path || subpath(#{ltree_path_column}, nlevel(:old_path))", new_path: ltree_path, old_path: ltree_path_was]
|
124
126
|
)
|
125
127
|
end
|
126
128
|
|
127
129
|
def root?
|
128
|
-
if
|
130
|
+
if ltree_parent_fragment
|
129
131
|
false
|
130
132
|
else
|
131
133
|
parent.nil?
|
@@ -136,18 +138,18 @@ module Ltree
|
|
136
138
|
!children.exists?
|
137
139
|
end
|
138
140
|
|
139
|
-
def depth # 1-based, for compatibility with ltree's
|
141
|
+
def depth # 1-based, for compatibility with ltree's NLEVEL().
|
140
142
|
if root?
|
141
143
|
1
|
142
144
|
elsif ltree_path
|
143
|
-
ltree_path.split(
|
145
|
+
ltree_path.split(".").length
|
144
146
|
elsif parent
|
145
147
|
parent.depth + 1
|
146
148
|
end
|
147
149
|
end
|
148
150
|
|
149
151
|
def root
|
150
|
-
ltree_scope.where("#{ltree_path_column} =
|
152
|
+
ltree_scope.where("#{ltree_path_column} = SUBPATH(?, 0, 1)", ltree_path).first
|
151
153
|
end
|
152
154
|
|
153
155
|
def ancestors
|
@@ -160,7 +162,10 @@ module Ltree
|
|
160
162
|
alias :and_ancestors :self_and_ancestors
|
161
163
|
|
162
164
|
def siblings
|
163
|
-
ltree_scope.where(
|
165
|
+
ltree_scope.where(
|
166
|
+
"#{ltree_parent_fragment_column} = ? AND #{ltree_fragment_column} != ?",
|
167
|
+
ltree_parent_fragment, ltree_fragment
|
168
|
+
)
|
164
169
|
end
|
165
170
|
|
166
171
|
def self_and_siblings
|
@@ -182,7 +187,7 @@ module Ltree
|
|
182
187
|
end
|
183
188
|
|
184
189
|
def self_and_children
|
185
|
-
ltree_scope.where("#{ltree_fragment_column} = :id OR #{ltree_parent_fragment_column} = :id", :
|
190
|
+
ltree_scope.where("#{ltree_fragment_column} = :id OR #{ltree_parent_fragment_column} = :id", id: ltree_fragment)
|
186
191
|
end
|
187
192
|
alias :and_children :self_and_children
|
188
193
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ltree_hierarchy/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ltree_hierarchy"
|
7
|
+
s.version = Ltree::Hierarchy::VERSION
|
8
|
+
s.authors = ["Rob Worley", "Leadformance"]
|
9
|
+
s.email = ["dev@leadformance.com"]
|
10
|
+
s.homepage = "https://github.com/Leadformance/ltree_hierarchy"
|
11
|
+
s.summary = "Organize ActiveRecord models into a tree using PostgreSQL's ltree datatype"
|
12
|
+
s.description = "Organizes ActiveRecord models into a tree/hierarchy using a materialized path implementation based around PostgreSQL's ltree datatype. ltree's operators ensure that queries are fast and easily understood."
|
13
|
+
|
14
|
+
s.rubyforge_project = "ltree_hierarchy"
|
15
|
+
|
16
|
+
s.files = Dir["{lib/**/*,[A-Z]*}"]
|
17
|
+
s.platform = Gem::Platform::RUBY
|
18
|
+
s.license = "MIT"
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
if RUBY_PLATFORM == "java"
|
22
|
+
s.add_dependency "activerecord-jdbcpostgresql-adapter"
|
23
|
+
else
|
24
|
+
s.add_dependency "pg"
|
25
|
+
end
|
26
|
+
|
27
|
+
s.add_dependency "activerecord", ">= 3.1.0"
|
28
|
+
|
29
|
+
s.add_development_dependency "minitest"
|
30
|
+
s.add_development_dependency "rake"
|
31
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ltree_hierarchy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Worley
|
8
|
+
- Leadformance
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
12
|
+
date: 2015-05-29 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: pg
|
@@ -70,20 +71,23 @@ description: Organizes ActiveRecord models into a tree/hierarchy using a materia
|
|
70
71
|
path implementation based around PostgreSQL's ltree datatype. ltree's operators
|
71
72
|
ensure that queries are fast and easily understood.
|
72
73
|
email:
|
73
|
-
-
|
74
|
+
- dev@leadformance.com
|
74
75
|
executables: []
|
75
76
|
extensions: []
|
76
77
|
extra_rdoc_files: []
|
77
78
|
files:
|
79
|
+
- CHANGELOG.md
|
78
80
|
- Gemfile
|
79
81
|
- Gemfile.lock
|
80
82
|
- MIT-LICENSE
|
81
83
|
- README.md
|
82
84
|
- Rakefile
|
85
|
+
- init.rb
|
83
86
|
- lib/ltree_hierarchy.rb
|
84
87
|
- lib/ltree_hierarchy/hierarchy.rb
|
85
88
|
- lib/ltree_hierarchy/version.rb
|
86
|
-
|
89
|
+
- ltree_hierarchy.gemspec
|
90
|
+
homepage: https://github.com/Leadformance/ltree_hierarchy
|
87
91
|
licenses:
|
88
92
|
- MIT
|
89
93
|
metadata: {}
|
@@ -103,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
107
|
version: '0'
|
104
108
|
requirements: []
|
105
109
|
rubyforge_project: ltree_hierarchy
|
106
|
-
rubygems_version: 2.4.
|
110
|
+
rubygems_version: 2.4.5
|
107
111
|
signing_key:
|
108
112
|
specification_version: 4
|
109
113
|
summary: Organize ActiveRecord models into a tree using PostgreSQL's ltree datatype
|