activerecord-postgresql-branched 0.2.0 → 0.4.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/CHANGELOG.md +11 -2
- data/README.md +16 -2
- data/lib/active_record/connection_adapters/postgresql/branched/adapter.rb +4 -3
- data/lib/active_record/connection_adapters/postgresql/branched/branch_manager.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/branched/railtie.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/branched/schema_dumper.rb +2 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1742fc285cfd6d57e93baa73da6dd675fa3b75df1f02a3320fae25bcfe08f28d
|
|
4
|
+
data.tar.gz: 2ee36f561b9a1e9b4b555f48e39499189bd0da2bbf4344bb2b52616869d52008
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 623f743e34d6db55c2b9b3b447dcf1b2b7066d9aad8d05f656580dcf5546a6e20f142ee35d2a7f7f9a7260eea9b2dcb76e78d35006eb1ecf54d8b604d6af0f98
|
|
7
|
+
data.tar.gz: c48eefaa0809be95fdda529956160f85ba240afb0ac97b94c983d80648d4ba7bce5eab35050d100c21ffee5538f93b219bcee8db2059d7df8c442846f78ef091
|
data/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
- Restore primary branch — the primary branch (default: `main`) writes to `public` so feature branches see shared state via `search_path` fallthrough
|
|
6
|
+
- Comprehensive test suite: workflow tests, full DDL coverage (69 tests, 163 assertions)
|
|
7
|
+
- Rewrite README from first principles
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
- Add `db:branch:console` rake task — opens psql with the branch `search_path`
|
|
12
|
+
|
|
3
13
|
## 0.2.0
|
|
4
14
|
|
|
5
|
-
- Remove primary branch concept — every branch gets its own schema equally
|
|
6
15
|
- Add shadow interception for `add_foreign_key`, `remove_foreign_key`, `add_check_constraint`, `remove_check_constraint`, `validate_foreign_key`, `validate_check_constraint`
|
|
7
16
|
- Simplify branch resolution to `PGBRANCH` env var with git fallback
|
|
8
17
|
- Remove `branch_override` config option and `BRANCH` env var
|
|
9
18
|
- `db:branch:prune` accepts `KEEP=branch1,branch2` for explicit control
|
|
10
19
|
- Fix railtie to reuse the adapter's existing BranchManager
|
|
11
|
-
-
|
|
20
|
+
- Pass shadow to `activate` instead of creating a redundant instance
|
|
12
21
|
- Quote schema identifiers consistently in shadow SQL
|
|
13
22
|
|
|
14
23
|
## 0.1.0
|
data/README.md
CHANGED
|
@@ -117,22 +117,36 @@ rails db:branch:discard BRANCH=agent-0
|
|
|
117
117
|
## Rake tasks
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
rails db:branch:reset
|
|
120
|
+
rails db:branch:reset # drop and recreate current branch schema
|
|
121
121
|
rails db:branch:discard # drop current branch schema (or BRANCH=name)
|
|
122
122
|
rails db:branch:list # list all branch schemas and their sizes
|
|
123
123
|
rails db:branch:diff # show tables in the current branch schema
|
|
124
124
|
rails db:branch:prune # drop stale schemas (KEEP=main,feature/x or auto-detect from git)
|
|
125
|
+
rails db:branch:console # open psql with the branch search_path
|
|
125
126
|
```
|
|
126
127
|
|
|
128
|
+
### psql
|
|
129
|
+
|
|
130
|
+
`psql` connects directly to PostgreSQL and knows nothing about branch schemas. Use `db:branch:console` instead — it launches psql with `search_path` set to your branch schema, so you see exactly what your Rails app sees.
|
|
131
|
+
|
|
127
132
|
## Configuration
|
|
128
133
|
|
|
129
|
-
|
|
134
|
+
```yaml
|
|
135
|
+
development:
|
|
136
|
+
adapter: postgresql_branched
|
|
137
|
+
database: myapp_development
|
|
138
|
+
primary_branch: main # default, can be 'master', 'trunk', etc.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The adapter needs a branch name. Resolution order:
|
|
130
142
|
|
|
131
143
|
1. `PGBRANCH` environment variable
|
|
132
144
|
2. `git branch --show-current` (automatic fallback)
|
|
133
145
|
|
|
134
146
|
If neither is available, the adapter raises an error.
|
|
135
147
|
|
|
148
|
+
On the **primary branch** (`main` by default), the adapter stands aside entirely. No branch schema is created. Migrations land directly in `public`. This is how the shared baseline advances — when you pull main and run `db:migrate`, the tables go to `public` where every feature branch can see them via `search_path` fallthrough.
|
|
149
|
+
|
|
136
150
|
All standard PostgreSQL connection parameters work as normal (`host`, `port`, `username`, `password`, etc.).
|
|
137
151
|
|
|
138
152
|
**Do not set `schema_search_path` in database.yml** — it conflicts with the adapter's `search_path` management.
|
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
|
31
31
|
def initialize(...)
|
|
32
32
|
super
|
|
33
33
|
@branch_manager = BranchManager.new(self, @config)
|
|
34
|
-
@shadow = Shadow.new(self, @branch_manager.branch_schema)
|
|
34
|
+
@shadow = Shadow.new(self, @branch_manager.branch_schema) unless @branch_manager.primary_branch?
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def configure_connection
|
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
|
41
41
|
|
|
42
42
|
SHADOW_BEFORE.each do |method|
|
|
43
43
|
define_method(method) do |table_name, *args, **kwargs, &block|
|
|
44
|
-
@shadow
|
|
44
|
+
@shadow&.call(table_name)
|
|
45
45
|
super(table_name, *args, **kwargs, &block)
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -51,9 +51,10 @@ module ActiveRecord
|
|
|
51
51
|
# the branch schema. The table and index renames succeed before the
|
|
52
52
|
# sequence rename fails, so we rescue the sequence error.
|
|
53
53
|
def rename_table(table_name, new_name, **options)
|
|
54
|
-
@shadow
|
|
54
|
+
@shadow&.call(table_name)
|
|
55
55
|
super
|
|
56
56
|
rescue ActiveRecord::StatementInvalid => e
|
|
57
|
+
raise if @branch_manager.primary_branch?
|
|
57
58
|
raise unless e.cause.is_a?(PG::UndefinedTable)
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -13,11 +13,17 @@ module ActiveRecord
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def activate(shadow)
|
|
16
|
+
return if primary_branch?
|
|
17
|
+
|
|
16
18
|
ensure_schema
|
|
17
19
|
set_search_path
|
|
18
20
|
shadow_migration_tables(shadow)
|
|
19
21
|
end
|
|
20
22
|
|
|
23
|
+
def primary_branch?
|
|
24
|
+
@branch == primary_branch_name
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
def reset
|
|
22
28
|
drop_schema
|
|
23
29
|
ensure_schema
|
|
@@ -26,6 +32,11 @@ module ActiveRecord
|
|
|
26
32
|
|
|
27
33
|
def discard(branch_name = @branch)
|
|
28
34
|
schema = self.class.sanitise(branch_name)
|
|
35
|
+
|
|
36
|
+
if schema == self.class.sanitise(primary_branch_name)
|
|
37
|
+
raise "Cannot discard the primary branch schema"
|
|
38
|
+
end
|
|
39
|
+
|
|
29
40
|
@connection.execute("DROP SCHEMA IF EXISTS #{quote(schema)} CASCADE")
|
|
30
41
|
end
|
|
31
42
|
|
|
@@ -45,6 +56,8 @@ module ActiveRecord
|
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
def diff
|
|
59
|
+
return [] if primary_branch?
|
|
60
|
+
|
|
48
61
|
@connection.select_values(<<~SQL)
|
|
49
62
|
SELECT table_name FROM information_schema.tables
|
|
50
63
|
WHERE table_schema = #{@connection.quote(@branch_schema)}
|
|
@@ -107,6 +120,10 @@ module ActiveRecord
|
|
|
107
120
|
name
|
|
108
121
|
end
|
|
109
122
|
|
|
123
|
+
def primary_branch_name
|
|
124
|
+
(@config[:primary_branch] || "main").to_s
|
|
125
|
+
end
|
|
126
|
+
|
|
110
127
|
def ensure_schema
|
|
111
128
|
@connection.execute("CREATE SCHEMA IF NOT EXISTS #{quote(@branch_schema)}")
|
|
112
129
|
end
|
|
@@ -9,6 +9,12 @@ module ActiveRecord
|
|
|
9
9
|
desc "Drop and recreate the current branch schema"
|
|
10
10
|
task reset: :load_config do
|
|
11
11
|
manager = branch_manager
|
|
12
|
+
|
|
13
|
+
if manager.primary_branch?
|
|
14
|
+
puts "On primary branch (#{manager.branch}), nothing to reset."
|
|
15
|
+
next
|
|
16
|
+
end
|
|
17
|
+
|
|
12
18
|
manager.reset
|
|
13
19
|
puts "Reset branch schema #{manager.branch_schema}. Run db:migrate to reapply branch migrations."
|
|
14
20
|
end
|
|
@@ -53,6 +59,12 @@ module ActiveRecord
|
|
|
53
59
|
desc "Show objects in the current branch schema"
|
|
54
60
|
task diff: :load_config do
|
|
55
61
|
manager = branch_manager
|
|
62
|
+
|
|
63
|
+
if manager.primary_branch?
|
|
64
|
+
puts "On primary branch, no diff."
|
|
65
|
+
next
|
|
66
|
+
end
|
|
67
|
+
|
|
56
68
|
tables = manager.diff
|
|
57
69
|
|
|
58
70
|
if tables.empty?
|
|
@@ -62,6 +74,26 @@ module ActiveRecord
|
|
|
62
74
|
tables.each { |t| puts " #{t}" }
|
|
63
75
|
end
|
|
64
76
|
end
|
|
77
|
+
|
|
78
|
+
desc "Open psql with the branch search_path"
|
|
79
|
+
task console: :load_config do
|
|
80
|
+
manager = branch_manager
|
|
81
|
+
config = ActiveRecord::Base.connection_db_config.configuration_hash
|
|
82
|
+
|
|
83
|
+
env = {}
|
|
84
|
+
unless manager.primary_branch?
|
|
85
|
+
env["PGOPTIONS"] = "-c search_path=#{manager.branch_schema},public"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
args = ["psql"]
|
|
89
|
+
args.push("-h", config[:host].to_s) if config[:host]
|
|
90
|
+
args.push("-p", config[:port].to_s) if config[:port]
|
|
91
|
+
args.push("-U", config[:username].to_s) if config[:username]
|
|
92
|
+
args.push(config[:database].to_s)
|
|
93
|
+
|
|
94
|
+
puts "Connecting to #{config[:database]}#{" as #{manager.branch_schema}" unless manager.primary_branch?}..."
|
|
95
|
+
exec(env, *args)
|
|
96
|
+
end
|
|
65
97
|
end
|
|
66
98
|
end
|
|
67
99
|
|