pgterra 0.1.2 → 0.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.
- package/LICENSE +21 -0
- package/README.md +179 -50
- package/dist/index.js +8256 -2292
- package/package.json +11 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Terra Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,69 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="assets/readme-hero.png" alt="Terra - Declarative PostgreSQL schema management" />
|
|
3
|
+
<br />
|
|
4
|
+
<br />
|
|
5
|
+
<a href="https://github.com/elitan/terra/blob/main/LICENSE">
|
|
6
|
+
<img alt="MIT License" src="https://img.shields.io/github/license/elitan/terra" />
|
|
7
|
+
</a>
|
|
8
|
+
<a href="https://github.com/elitan/terra/stargazers">
|
|
9
|
+
<img alt="GitHub Stars" src="https://img.shields.io/github/stars/elitan/terra?style=social" />
|
|
10
|
+
</a>
|
|
11
|
+
<br />
|
|
12
|
+
<a href="https://x.com/elitasson">
|
|
13
|
+
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/elitasson?style=social" />
|
|
14
|
+
</a>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<br />
|
|
18
|
+
|
|
19
|
+
Declarative PostgreSQL schema management. Write CREATE statements, Terra generates the migrations.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
6
22
|
|
|
7
23
|
```bash
|
|
8
24
|
npm install -g pgterra
|
|
9
25
|
```
|
|
10
26
|
|
|
11
|
-
##
|
|
27
|
+
## Usage
|
|
12
28
|
|
|
13
|
-
**1.
|
|
29
|
+
**1. Create schema.sql:**
|
|
14
30
|
|
|
15
31
|
```sql
|
|
16
|
-
-- schema.sql
|
|
17
32
|
CREATE TABLE users (
|
|
18
33
|
id SERIAL PRIMARY KEY,
|
|
19
|
-
email VARCHAR(255) NOT NULL UNIQUE
|
|
20
|
-
created_at TIMESTAMP DEFAULT NOW()
|
|
34
|
+
email VARCHAR(255) NOT NULL UNIQUE
|
|
21
35
|
);
|
|
22
36
|
```
|
|
23
37
|
|
|
38
|
+
**2. Preview changes:**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
terra plan
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**3. Apply:**
|
|
45
|
+
|
|
24
46
|
```bash
|
|
25
|
-
|
|
47
|
+
terra apply
|
|
26
48
|
```
|
|
27
49
|
|
|
28
|
-
**
|
|
50
|
+
**4. Update schema.sql:**
|
|
29
51
|
|
|
30
52
|
```sql
|
|
31
|
-
-- schema.sql
|
|
32
53
|
CREATE TABLE users (
|
|
33
54
|
id SERIAL PRIMARY KEY,
|
|
34
55
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
created_at TIMESTAMP DEFAULT NOW()
|
|
56
|
+
name VARCHAR(100) NOT NULL, -- added
|
|
57
|
+
active BOOLEAN DEFAULT true -- added
|
|
38
58
|
);
|
|
39
59
|
|
|
40
|
-
CREATE TABLE posts ( --
|
|
60
|
+
CREATE TABLE posts ( -- added
|
|
41
61
|
id SERIAL PRIMARY KEY,
|
|
42
62
|
title VARCHAR(255) NOT NULL,
|
|
43
|
-
user_id INTEGER
|
|
44
|
-
|
|
63
|
+
user_id INTEGER NOT NULL,
|
|
64
|
+
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
|
|
45
65
|
);
|
|
66
|
+
|
|
67
|
+
CREATE INDEX idx_user_email ON users (LOWER(email)); -- added
|
|
46
68
|
```
|
|
47
69
|
|
|
48
|
-
**
|
|
70
|
+
**5. Terra generates the ALTER statements:**
|
|
49
71
|
|
|
50
72
|
```bash
|
|
51
|
-
$
|
|
52
|
-
|
|
73
|
+
$ terra plan
|
|
74
|
+
ALTER TABLE users ADD COLUMN name VARCHAR(100) NOT NULL
|
|
75
|
+
ALTER TABLE users ADD COLUMN active BOOLEAN DEFAULT true
|
|
76
|
+
CREATE TABLE posts (...)
|
|
77
|
+
CREATE INDEX idx_user_email ON users (LOWER(email))
|
|
53
78
|
|
|
54
|
-
|
|
55
|
-
1. ALTER TABLE users ADD COLUMN full_name VARCHAR(200) NOT NULL
|
|
56
|
-
2. ALTER TABLE users ADD COLUMN is_active BOOLEAN DEFAULT true
|
|
57
|
-
3. CREATE TABLE posts (id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, user_id INTEGER REFERENCES users(id), created_at TIMESTAMP DEFAULT NOW())
|
|
58
|
-
|
|
59
|
-
$ pgterra apply # Applies the changes safely
|
|
79
|
+
$ terra apply
|
|
60
80
|
```
|
|
61
81
|
|
|
62
|
-
**That's it.** No migration files, no manual ALTER statements, no dependency ordering. Just define what you want.
|
|
63
|
-
|
|
64
82
|
## Configuration
|
|
65
83
|
|
|
66
|
-
|
|
84
|
+
Database connection via `DATABASE_URL` or individual variables:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
export DATABASE_URL="postgres://user:password@localhost:5432/mydb"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or:
|
|
67
91
|
|
|
68
92
|
```bash
|
|
69
93
|
export DB_HOST=localhost
|
|
@@ -73,37 +97,142 @@ export DB_USER=postgres
|
|
|
73
97
|
export DB_PASSWORD=password
|
|
74
98
|
```
|
|
75
99
|
|
|
76
|
-
##
|
|
100
|
+
## What's supported
|
|
101
|
+
|
|
102
|
+
**Tables & Columns:**
|
|
103
|
+
All PostgreSQL column types, default values, NOT NULL constraints
|
|
104
|
+
|
|
105
|
+
**Functions & Procedures:**
|
|
106
|
+
User-defined functions and procedures with full PostgreSQL feature support
|
|
107
|
+
|
|
108
|
+
**Triggers:**
|
|
109
|
+
Table triggers with BEFORE/AFTER/INSTEAD OF timing
|
|
110
|
+
|
|
111
|
+
**Sequences:**
|
|
112
|
+
Custom sequences with configurable properties
|
|
113
|
+
|
|
114
|
+
**Constraints:**
|
|
115
|
+
```sql
|
|
116
|
+
-- Primary keys
|
|
117
|
+
id SERIAL PRIMARY KEY
|
|
118
|
+
|
|
119
|
+
-- Foreign keys with actions
|
|
120
|
+
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
121
|
+
|
|
122
|
+
-- Check constraints
|
|
123
|
+
CONSTRAINT check_positive CHECK (quantity > 0)
|
|
124
|
+
|
|
125
|
+
-- Unique constraints
|
|
126
|
+
email VARCHAR(255) UNIQUE
|
|
127
|
+
CONSTRAINT unique_email UNIQUE (email, domain)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Indexes:**
|
|
131
|
+
```sql
|
|
132
|
+
-- Basic
|
|
133
|
+
CREATE INDEX idx_email ON users (email);
|
|
134
|
+
|
|
135
|
+
-- Partial
|
|
136
|
+
CREATE INDEX idx_active_users ON users (email) WHERE active = true;
|
|
137
|
+
|
|
138
|
+
-- Expression
|
|
139
|
+
CREATE INDEX idx_lower_email ON users (LOWER(email));
|
|
140
|
+
|
|
141
|
+
-- Concurrent (built automatically when safe)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**ENUM types:**
|
|
145
|
+
```sql
|
|
146
|
+
CREATE TYPE status AS ENUM ('pending', 'active', 'inactive');
|
|
147
|
+
|
|
148
|
+
CREATE TABLE users (
|
|
149
|
+
id SERIAL PRIMARY KEY,
|
|
150
|
+
status status NOT NULL
|
|
151
|
+
);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Views:**
|
|
155
|
+
```sql
|
|
156
|
+
CREATE VIEW active_users AS
|
|
157
|
+
SELECT id, email FROM users WHERE active = true;
|
|
158
|
+
|
|
159
|
+
CREATE MATERIALIZED VIEW user_stats AS
|
|
160
|
+
SELECT COUNT(*) as total FROM users;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Functions:**
|
|
164
|
+
```sql
|
|
165
|
+
CREATE FUNCTION calculate_total(quantity INT, price DECIMAL)
|
|
166
|
+
RETURNS DECIMAL
|
|
167
|
+
AS $$
|
|
168
|
+
SELECT quantity * price
|
|
169
|
+
$$
|
|
170
|
+
LANGUAGE SQL IMMUTABLE;
|
|
171
|
+
```
|
|
77
172
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
173
|
+
**Procedures:**
|
|
174
|
+
```sql
|
|
175
|
+
CREATE PROCEDURE archive_old_posts(days_old INT)
|
|
176
|
+
LANGUAGE SQL
|
|
177
|
+
AS $$
|
|
178
|
+
DELETE FROM posts WHERE created_at < NOW() - INTERVAL '1 day' * days_old;
|
|
179
|
+
$$;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Triggers:**
|
|
183
|
+
```sql
|
|
184
|
+
-- First create a trigger function
|
|
185
|
+
CREATE FUNCTION update_modified_timestamp()
|
|
186
|
+
RETURNS TRIGGER
|
|
187
|
+
AS $$
|
|
188
|
+
BEGIN
|
|
189
|
+
NEW.modified_at = NOW();
|
|
190
|
+
RETURN NEW;
|
|
191
|
+
END;
|
|
192
|
+
$$
|
|
193
|
+
LANGUAGE plpgsql;
|
|
194
|
+
|
|
195
|
+
-- Then create the trigger
|
|
196
|
+
CREATE TRIGGER set_modified_timestamp
|
|
197
|
+
BEFORE UPDATE ON users
|
|
198
|
+
FOR EACH ROW
|
|
199
|
+
EXECUTE FUNCTION update_modified_timestamp();
|
|
200
|
+
```
|
|
85
201
|
|
|
86
|
-
|
|
202
|
+
**Sequences:**
|
|
203
|
+
```sql
|
|
204
|
+
CREATE SEQUENCE custom_id_seq
|
|
205
|
+
START 1000
|
|
206
|
+
INCREMENT 1
|
|
207
|
+
CACHE 20;
|
|
208
|
+
```
|
|
87
209
|
|
|
88
|
-
|
|
210
|
+
## Commands
|
|
89
211
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
212
|
+
```bash
|
|
213
|
+
terra plan # Preview changes
|
|
214
|
+
terra plan -f custom.sql # Use custom schema file
|
|
215
|
+
terra apply # Apply changes
|
|
216
|
+
terra apply -f custom.sql # Apply from custom file
|
|
217
|
+
```
|
|
94
218
|
|
|
95
219
|
## Development
|
|
96
220
|
|
|
221
|
+
Requires [Bun](https://bun.sh):
|
|
222
|
+
|
|
97
223
|
```bash
|
|
98
|
-
git clone https://github.com/elitan/
|
|
99
|
-
cd
|
|
224
|
+
git clone https://github.com/elitan/terra.git
|
|
225
|
+
cd terra
|
|
100
226
|
bun install
|
|
101
227
|
|
|
102
|
-
#
|
|
103
|
-
|
|
228
|
+
# Start test database
|
|
229
|
+
docker compose up -d
|
|
104
230
|
|
|
105
231
|
# Run tests
|
|
232
|
+
export DATABASE_URL="postgres://test_user:test_password@localhost:5487/sql_terraform_test"
|
|
106
233
|
bun test
|
|
107
234
|
```
|
|
108
235
|
|
|
109
|
-
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
MIT
|