Skip to content

Commit 46e7b92

Browse files
committed
chore: baseline schema
1 parent 7a60cda commit 46e7b92

7 files changed

Lines changed: 271 additions & 5 deletions

File tree

.github/workflows/pgschema-multifile-apply.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ jobs:
4545
- name: Install pgschema
4646
run: go install github.com/pgschema/pgschema@latest
4747

48+
- name: Load baseline schema
49+
run: |
50+
echo "::group::Loading baseline schema to emulate remote database"
51+
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d testdb -f baseline.sql
52+
echo "::endgroup::"
53+
4854
- name: Run pgschema apply
4955
id: apply
5056
run: |

.github/workflows/pgschema-multifile-plan.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ jobs:
4545
- name: Install pgschema
4646
run: go install github.com/pgschema/pgschema@latest
4747

48+
- name: Load baseline schema
49+
run: |
50+
echo "::group::Loading baseline schema to emulate remote database"
51+
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d testdb -f baseline.sql
52+
echo "::endgroup::"
53+
4854
- name: Run pgschema plan
4955
id: plan
5056
run: |

.github/workflows/pgschema-singlefile-apply.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ jobs:
4545
- name: Install pgschema
4646
run: go install github.com/pgschema/pgschema@latest
4747

48+
- name: Load baseline schema
49+
run: |
50+
echo "::group::Loading baseline schema to emulate remote database"
51+
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d testdb -f baseline.sql
52+
echo "::endgroup::"
53+
4854
- name: Run pgschema apply
4955
id: apply
5056
run: |

.github/workflows/pgschema-singlefile-plan.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ jobs:
4545
- name: Install pgschema
4646
run: go install github.com/pgschema/pgschema@latest
4747

48+
- name: Load baseline schema
49+
run: |
50+
echo "::group::Loading baseline schema to emulate remote database"
51+
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d testdb -f baseline.sql
52+
echo "::endgroup::"
53+
4854
- name: Run pgschema plan
4955
id: plan
5056
run: |

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@ Apply workflows automatically:
2929

3030
## Setup
3131

32+
### PostgreSQL 17 Test Container Setup
33+
34+
The workflows automatically set up a PostgreSQL 17 test container and load the baseline schema to emulate a remote database with existing schema. The `baseline.sql` file contains a complete schema.
35+
36+
### Workflow Behavior
37+
38+
Each workflow now:
39+
40+
1. **Starts a clean PostgreSQL 17 container**
41+
2. **Loads baseline.sql** to simulate an existing remote database
42+
3. **Runs pgschema** against this baseline to generate migration plans or apply changes
43+
4. **Reports results** with detailed logging
44+
45+
This approach ensures that:
46+
47+
- Migration plans show realistic diffs against existing schema
48+
- Apply operations work against a database with existing data structure
49+
- Tests validate changes in a production-like environment
50+
3251
### GitHub Secrets
3352

3453
No secrets required! Both workflows start a PostgreSQL 17 test container for demonstration purposes, making them fully self-contained.

baseline.sql

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
--
2+
-- Name: user_status; Type: TYPE; Schema: -; Owner: -
3+
--
4+
5+
CREATE TYPE user_status AS ENUM (
6+
'active',
7+
'inactive'
8+
);
9+
--
10+
-- Name: order_status; Type: TYPE; Schema: -; Owner: -
11+
--
12+
13+
CREATE TYPE order_status AS ENUM (
14+
'pending',
15+
'completed'
16+
);
17+
--
18+
-- Name: address; Type: TYPE; Schema: -; Owner: -
19+
--
20+
21+
CREATE TYPE address AS (street text, city text);
22+
23+
-- Include domain types (constrained base types)
24+
--
25+
-- Name: email_address; Type: DOMAIN; Schema: -; Owner: -
26+
--
27+
28+
CREATE DOMAIN email_address AS text
29+
CONSTRAINT email_address_check CHECK (VALUE ~~ '%@%');
30+
--
31+
-- Name: positive_integer; Type: DOMAIN; Schema: -; Owner: -
32+
--
33+
34+
CREATE DOMAIN positive_integer AS integer
35+
CONSTRAINT positive_integer_check CHECK (VALUE > 0);
36+
37+
-- Include sequences (may be used by tables)
38+
--
39+
-- Name: global_id_seq; Type: SEQUENCE; Schema: -; Owner: -
40+
--
41+
42+
CREATE SEQUENCE IF NOT EXISTS global_id_seq;
43+
--
44+
-- Name: order_number_seq; Type: SEQUENCE; Schema: -; Owner: -
45+
--
46+
47+
CREATE SEQUENCE IF NOT EXISTS order_number_seq;
48+
49+
-- Include trigger function (needed by users table trigger)
50+
--
51+
-- Name: update_timestamp; Type: FUNCTION; Schema: -; Owner: -
52+
--
53+
54+
CREATE OR REPLACE FUNCTION update_timestamp()
55+
RETURNS trigger
56+
LANGUAGE plpgsql
57+
SECURITY INVOKER
58+
STABLE
59+
AS $$
60+
BEGIN
61+
NEW.updated_at = NOW();
62+
RETURN NEW;
63+
END;
64+
$$;
65+
66+
-- Include core tables (with their constraints, indexes, and policies)
67+
--
68+
-- Name: users; Type: TABLE; Schema: -; Owner: -
69+
--
70+
71+
CREATE TABLE IF NOT EXISTS users (
72+
id integer PRIMARY KEY,
73+
email text NOT NULL CHECK (email LIKE '%@%'),
74+
name text NOT NULL
75+
);
76+
77+
COMMENT ON TABLE users IS 'User accounts';
78+
79+
COMMENT ON COLUMN users.email IS 'User email address';
80+
81+
--
82+
-- Name: idx_users_email; Type: INDEX; Schema: -; Owner: -
83+
--
84+
85+
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
86+
87+
--
88+
-- Name: idx_users_name; Type: INDEX; Schema: -; Owner: -
89+
--
90+
91+
CREATE INDEX IF NOT EXISTS idx_users_name ON users (name);
92+
93+
--
94+
-- Name: users; Type: RLS; Schema: -; Owner: -
95+
--
96+
97+
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
98+
99+
--
100+
-- Name: users_policy; Type: POLICY; Schema: -; Owner: -
101+
--
102+
103+
CREATE POLICY users_policy ON users TO PUBLIC USING (true);
104+
105+
--
106+
-- Name: users_update_trigger; Type: TRIGGER; Schema: -; Owner: -
107+
--
108+
109+
CREATE OR REPLACE TRIGGER users_update_trigger
110+
BEFORE UPDATE ON users
111+
FOR EACH ROW
112+
EXECUTE FUNCTION update_timestamp();
113+
--
114+
-- Name: orders; Type: TABLE; Schema: -; Owner: -
115+
--
116+
117+
CREATE TABLE IF NOT EXISTS orders (
118+
id integer PRIMARY KEY,
119+
user_id integer NOT NULL REFERENCES users(id),
120+
status text DEFAULT 'pending' NOT NULL CHECK (status IN ('pending', 'completed')),
121+
amount numeric(10,2) DEFAULT 0.00
122+
);
123+
124+
COMMENT ON TABLE orders IS 'Customer orders';
125+
126+
COMMENT ON COLUMN orders.user_id IS 'Reference to user';
127+
128+
--
129+
-- Name: idx_orders_status; Type: INDEX; Schema: -; Owner: -
130+
--
131+
132+
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders (status);
133+
134+
--
135+
-- Name: idx_orders_user_id; Type: INDEX; Schema: -; Owner: -
136+
--
137+
138+
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders (user_id);
139+
140+
--
141+
-- Name: orders; Type: RLS; Schema: -; Owner: -
142+
--
143+
144+
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
145+
146+
--
147+
-- Name: orders_policy; Type: POLICY; Schema: -; Owner: -
148+
--
149+
150+
CREATE POLICY orders_policy ON orders TO PUBLIC USING (user_id = 1);
151+
152+
-- Include other functions (after tables that they reference)
153+
--
154+
-- Name: get_user_count; Type: FUNCTION; Schema: -; Owner: -
155+
--
156+
157+
CREATE OR REPLACE FUNCTION get_user_count()
158+
RETURNS integer
159+
LANGUAGE sql
160+
SECURITY INVOKER
161+
VOLATILE
162+
AS $$
163+
SELECT COUNT(*) FROM users;
164+
$$;
165+
--
166+
-- Name: get_order_count; Type: FUNCTION; Schema: -; Owner: -
167+
--
168+
169+
CREATE OR REPLACE FUNCTION get_order_count(
170+
user_id_param integer
171+
)
172+
RETURNS integer
173+
LANGUAGE sql
174+
SECURITY INVOKER
175+
VOLATILE
176+
AS $$
177+
SELECT COUNT(*) FROM orders WHERE user_id = user_id_param;
178+
$$;
179+
180+
-- Include procedures
181+
--
182+
-- Name: cleanup_orders; Type: PROCEDURE; Schema: -; Owner: -
183+
--
184+
185+
CREATE OR REPLACE PROCEDURE cleanup_orders()
186+
LANGUAGE sql
187+
AS $$
188+
DELETE FROM orders WHERE status = 'completed';
189+
$$;
190+
--
191+
-- Name: update_status; Type: PROCEDURE; Schema: -; Owner: -
192+
--
193+
194+
CREATE OR REPLACE PROCEDURE update_status(
195+
user_id_param integer,
196+
new_status text
197+
)
198+
LANGUAGE sql
199+
AS $$
200+
UPDATE orders SET status = new_status WHERE user_id = user_id_param;
201+
$$;
202+
203+
-- Include views (depend on tables and functions)
204+
--
205+
-- Name: user_summary; Type: VIEW; Schema: -; Owner: -
206+
--
207+
208+
CREATE OR REPLACE VIEW user_summary AS
209+
SELECT u.id,
210+
u.name,
211+
count(o.id) AS order_count
212+
FROM users u
213+
JOIN orders o ON u.id = o.user_id
214+
GROUP BY u.id, u.name;;
215+
216+
COMMENT ON VIEW user_summary IS 'User order summary';
217+
--
218+
-- Name: order_details; Type: VIEW; Schema: -; Owner: -
219+
--
220+
221+
CREATE OR REPLACE VIEW order_details AS
222+
SELECT o.id,
223+
o.status,
224+
u.name AS user_name
225+
FROM orders o
226+
JOIN users u ON o.user_id = u.id;;
227+
228+
COMMENT ON VIEW order_details IS 'Order details with user info';

singlefile/schema.sql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
-- Main schema file demonstrating \i include functionality
2-
-- This represents a modular approach to organizing database schema
3-
-- Includes ALL supported PostgreSQL database objects
4-
5-
-- Include custom types first (dependencies for tables)
61
--
72
-- Name: user_status; Type: TYPE; Schema: -; Owner: -
83
--

0 commit comments

Comments
 (0)