active_tree 0.3 → 0.3.1

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: 5fb9ce62863408c33ab2b8db4bdfa7b21a67b15f14927f43d9b168dfe121604a
4
- data.tar.gz: 8dc8ad54ec03529d82bab17e219389057a7040fb1340bc691a0c9de06566ef66
3
+ metadata.gz: b3e791b0f19ec736feb7d89abd9cf24081c7e4bcd862b08cea3f095432cbf9a9
4
+ data.tar.gz: e74e6e2fec69129d45f6b5c62332c42f3537039bc44dfc0dbf0d711a5eba5e00
5
5
  SHA512:
6
- metadata.gz: cda0e7157dfa1abd83dd92df6430bce8842500cc93aa58b07a0fa0216ea8c826f9ff61dec764bfa3bfbd915a67f32e8006987a960f7beede67d1a9357e68280d
7
- data.tar.gz: 0e62ce8e6fb8d9ffe4d1caecfa32f6129842607452ed217116b0d7802c2c2d190ba48dc58f432c886a95dc902074308fad7071dd4b94a025d2856a73bd18783e
6
+ metadata.gz: 102b71e83e19b2bcf330eef8d4fbc001cfec5015368301705c79611ef8ea5d19f2e00d8de6944398b7db83250e9a87a135cde71a8a9a87e05695b1c25e7d7938
7
+ data.tar.gz: fec20af4b4653f1526cdf321e826fb3a125840708f96205ba9ea2da2d5b0a0927d9fe2d7099096eff2b6ee24f497db6499bdd6cb970a8f0f4a0fbc996560c735
@@ -13,8 +13,13 @@ module ActiveTree
13
13
  before_destroy :active_tree_delete_storage
14
14
 
15
15
  # instance methods
16
+ def store
17
+ ActiveTree::Store.new id, ACTIVE_TREE_OPTIONS
18
+ end # store
19
+
16
20
  def active_tree_role
17
- "active_tree_owner_#{id}_#{ ACTIVE_TREE_OPTIONS[:owner_role_suffix] }"
21
+ #"active_tree_owner_#{id}_#{ ACTIVE_TREE_OPTIONS[:owner_role_suffix] }"
22
+ store.role_name
18
23
  end # role
19
24
 
20
25
  # Generates a JWT token the client (SPA) can pass to PostgREST for privilege escalation
@@ -24,64 +29,17 @@ module ActiveTree
24
29
  end # .generate_jwt
25
30
 
26
31
 
27
- # Returns the LCA table name as configured within config/active_tree.yml
28
- def active_tree_table_name
29
- ACTIVE_TREE_OPTIONS[:table_name]
30
- end # .active_tree_table_name
31
-
32
-
33
- # Creates LCA table partition and role for owner
32
+ # Creates table partition and role for owner
34
33
  def active_tree_create_storage
35
-
36
- # create data partition
37
- active_tree_sql "create table if not exists #{active_tree_table_name}_#{id} partition of #{active_tree_table_name} for values in (#{id})"
38
- # create partition indexes
39
- active_tree_sql "create index index_#{id}_by_id on #{active_tree_table_name}_#{id} (id)"
40
- active_tree_sql "create index index_#{id}_by_owner_id on #{active_tree_table_name}_#{id} (owner_id)"
41
- active_tree_sql "create index index_#{id}_by_type on #{active_tree_table_name}_#{id} (type)"
42
- active_tree_sql "create index index_#{id}_by_parent_entity_id on #{active_tree_table_name}_#{id} (parent_entity_id)"
43
- active_tree_sql "create index index_#{id}_by_path on #{active_tree_table_name}_#{id} using gist (path)"
44
- active_tree_sql "create index index_#{id}_by_data_provider_and_data_external_id on #{active_tree_table_name}_#{id} (data_provider, data_external_id)"
45
-
46
-
47
- if ACTIVE_TREE_OPTIONS[:create_postgrest_roles]
48
- # drop role if it exists
49
- active_tree_sql "drop role if exists #{ active_tree_role }"
50
-
51
- # create role
52
- active_tree_sql "create role #{ active_tree_role }"
53
-
54
- # grant privs
55
- active_tree_sql "grant all privileges on #{active_tree_table_name}_#{id} to #{ active_tree_role }"
56
- end
57
-
34
+ store.up!
58
35
  end # create_storage
59
36
 
60
37
 
61
38
  # Deletes or detaches the partition and removes the role for this owner
62
39
  def active_tree_delete_storage
63
-
64
- if ACTIVE_TREE_OPTIONS[:create_postgrest_roles]
65
- # revoke privs
66
- active_tree_sql "REVOKE ALL PRIVILEGES ON #{active_tree_table_name}_#{id} FROM #{ active_tree_role }"
67
-
68
- # delete role
69
- active_tree_sql "drop role #{ active_tree_role }"
70
- end
71
-
72
- if ACTIVE_TREE_OPTIONS[:destroy_partition_on_owner_destroy]
73
- # delete partition
74
- active_tree_sql "drop table if exists #{active_tree_table_name}_#{id}"
75
- else
76
- # detach and forget about it
77
- active_tree_sql "alter table #{active_tree_table_name} detach partition #{ active_tree_role }"
78
- end
40
+ store.down!
79
41
  end # delete_storage
80
42
 
81
- def active_tree_sql sql
82
- ActiveRecord::Base.connection.execute sql
83
- end # active_tree_sql
84
-
85
43
  end # ClassMethods
86
44
  end
87
45
  end
@@ -37,7 +37,8 @@ class ActiveTree::Model < ActiveRecord::Base
37
37
 
38
38
  partition_suffix = "_#{owner_id}"
39
39
 
40
- table = "#{ self.table_name }#{ partition_suffix }"
40
+ #table = "#{ self.table_name }#{ partition_suffix }"
41
+ table = ActiveTree::Store.new(owner_id).partition_name
41
42
 
42
43
  ApplicationRecord.connection.schema_cache.clear!
43
44
  return self if !ApplicationRecord.connection.schema_cache.data_source_exists? table
@@ -0,0 +1,140 @@
1
+ class ActiveTree::Store
2
+ attr_accessor :options
3
+ attr_accessor :debug_sql
4
+
5
+ class StoreException < StandardError
6
+ def initialize(msg="This is a custom exception", exception_type="custom")
7
+ @exception_type = exception_type
8
+ super(msg)
9
+ end
10
+ end
11
+
12
+ def initialize(owner_id = nil, options = ACTIVE_TREE_OPTIONS)
13
+ raise StoreException.new("Unspecified owner_id, please pass an unique identifier for the partitions: ActiveTree::Store.new(your_owner_id)") if !owner_id
14
+ raise StoreException.new("owner_id must be an integer!") if !owner_id.is_a?(Integer)
15
+ @owner_id = owner_id
16
+ @options = options
17
+ @debug_sql = false
18
+ end
19
+
20
+ def up!
21
+ create_partition_for_owner # also adds indexes
22
+ setup_role if @options[:create_postgrest_roles] == true
23
+ end # up!
24
+
25
+ def down!
26
+ drop_role if @options[:create_postgrest_roles] == true
27
+ remove_partition
28
+ end # down!
29
+
30
+ def clear_schema_cache
31
+ ActiveRecord::Base.connection.schema_cache.clear!
32
+ end # clear_schema_cache
33
+
34
+ # partition management
35
+
36
+ def has_partition?
37
+ clear_schema_cache
38
+ ActiveRecord::Base.connection.schema_cache.data_source_exists? partition_name
39
+ end
40
+
41
+ def create_partition_for_owner(indexes = [ :id, :owner_id, :type, :parent_entity_id, :path, [:data_provider, :data_external_id ] ])
42
+ create_partition indexes
43
+ end
44
+
45
+ def create_partition(indexes = [])
46
+ return false if has_partition?
47
+
48
+ run "create table if not exists #{partition_name} partition of #{ @options[:table_name] } for values in ( #{@owner_id} )"
49
+
50
+ indexes.each do |index|
51
+ create_index(index) if !has_index?( index )
52
+ end if indexes.size > 0
53
+ end # create_partition
54
+
55
+ def partition_name
56
+ "#{@options[:table_name]}_#{@owner_id}"
57
+ end # partition_name
58
+
59
+ def should_drop_partition?
60
+ @options[:destroy_partition_on_owner_destroy] == true
61
+ end
62
+
63
+ def remove_partition
64
+ if should_drop_partition?
65
+ drop_partition
66
+ else
67
+ detach_partition
68
+ end
69
+ end # remove_partition
70
+
71
+ def detach_partition
72
+ return false if !has_partition?
73
+ run "alter table #{@options[:table_name]} detach partition #{partition_name}"
74
+ end # detach_partition
75
+ def drop_partition
76
+ return false if !has_partition?
77
+ run "drop table #{partition_name}"
78
+ end # drop partition
79
+
80
+ # index management
81
+
82
+ def partition_indexes
83
+ clear_schema_cache
84
+ ActiveRecord::Base.connection.indexes( partition_name ).map(&:name)
85
+ end
86
+
87
+ def has_index? name
88
+ partition_indexes.include?( index_name(name).truncate(63) )
89
+ end # has_index
90
+ def create_index index
91
+ return false if has_index? index
92
+ name = index_name index
93
+ using = name.include?("path") ? "using gist" : ""
94
+
95
+ cols = [index].flatten.join(",")
96
+
97
+ run "create index #{name} on #{partition_name} #{using} ( #{ cols } )"
98
+ end # create_index
99
+ def drop_index index
100
+ return false if !has_index? index
101
+ run "drop index if exists #{ index_name(index) }"
102
+ end # drop_index
103
+
104
+ def index_name identifier
105
+ i = [identifier].flatten.join("_")
106
+ "#{partition_name}_by_#{i}"
107
+ end
108
+
109
+ # TODO role management
110
+
111
+ def setup_role
112
+ drop_role
113
+ create_role
114
+ end # setup_role
115
+
116
+ def role_name
117
+ "active_tree_owner_#{@owner_id}_#{ @options[:owner_role_suffix] }"
118
+ end # role_name
119
+
120
+ def drop_role
121
+ run "drop role if exists #{role_name}"
122
+ end # drop role
123
+
124
+ def create_role
125
+ run "create role #{role_name}"
126
+ end # create role
127
+
128
+ def assign_to_partition
129
+ run "grant all privileges on #{partition_name} to #{ role_name }"
130
+ end
131
+
132
+ # running SQL
133
+
134
+ def run sql
135
+ puts sql if @debug_sql
136
+ ActiveRecord::Base.connection.execute sql
137
+ true
138
+ end
139
+
140
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveTree
4
- VERSION = "0.3"
4
+ VERSION = "0.3.1"
5
5
  end
data/lib/active_tree.rb CHANGED
@@ -6,6 +6,7 @@ require "active_record"
6
6
  require "pg_ltree"
7
7
 
8
8
  require_relative "active_tree/version"
9
+ require_relative "active_tree/store"
9
10
 
10
11
  require_relative "active_tree/models/concerns/statusable"
11
12
  require_relative "active_tree/models/metadata"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick @ Earthster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-15 00:00:00.000000000 Z
11
+ date: 2021-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -77,6 +77,7 @@ files:
77
77
  - lib/active_tree/models/model.rb
78
78
  - lib/active_tree/queries/active_tree_query.rb
79
79
  - lib/active_tree/queries/model_query.rb
80
+ - lib/active_tree/store.rb
80
81
  - lib/active_tree/version.rb
81
82
  - lib/generators/active_tree/install_generator.rb
82
83
  - lib/generators/active_tree/templates/config.yml.tt