@pgpm/types 0.12.2 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
- Copyright (c) 2025 Interweb, Inc.
4
+ Copyright (c) 2025 Constructive
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # @pgpm/types
2
2
 
3
3
  <p align="center" width="100%">
4
- <img height="250" src="https://raw.githubusercontent.com/launchql/launchql/refs/heads/main/assets/outline-logo.svg" />
4
+ <img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
5
5
  </p>
6
6
 
7
7
  <p align="center" width="100%">
8
- <a href="https://github.com/launchql/pgpm-modules/actions/workflows/ci.yml">
9
- <img height="20" src="https://github.com/launchql/pgpm-modules/actions/workflows/ci.yml/badge.svg" />
8
+ <a href="https://github.com/constructive-io/pgpm-modules/actions/workflows/ci.yml">
9
+ <img height="20" src="https://github.com/constructive-io/pgpm-modules/actions/workflows/ci.yml/badge.svg" />
10
10
  </a>
11
- <a href="https://github.com/launchql/pgpm-modules/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
12
- <a href="https://www.npmjs.com/package/@pgpm/types"><img height="20" src="https://img.shields.io/github/package-json/v/launchql/pgpm-modules?filename=packages%2Fdata-types%2Ftypes%2Fpackage.json"/></a>
11
+ <a href="https://github.com/constructive-io/pgpm-modules/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
12
+ <a href="https://www.npmjs.com/package/@pgpm/types"><img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/pgpm-modules?filename=packages%2Fdata-types%2Ftypes%2Fpackage.json"/></a>
13
13
  </p>
14
14
 
15
15
  Core PostgreSQL data types with SQL scripts.
@@ -68,7 +68,7 @@ pgpm deploy
68
68
 
69
69
  ```bash
70
70
  # 1. Create a workspace
71
- pgpm init --workspace
71
+ pgpm init workspace
72
72
 
73
73
  # 2. Create your first module
74
74
  cd my-workspace
@@ -158,6 +158,7 @@ INSERT INTO customers (domain) VALUES
158
158
  ### Image and Attachment Domains
159
159
 
160
160
  The `image` domain stores JSON objects with URL and MIME type information. The `attachment` domain accepts either that JSON shape or a plain URL string.
161
+ The `upload` domain uses the same JSON object shape as `image`, ensuring both the file URL and MIME type are present.
161
162
 
162
163
  ```sql
163
164
  -- Valid image
@@ -184,7 +185,7 @@ INSERT INTO customers (document) VALUES ('https://storage.example.com/favicon.ic
184
185
  | `hostname` | `text` | Domain name without protocol | `example.com` |
185
186
  | `image` | `json` | Image metadata with URL and MIME | `{"url": "...", "mime": "image/jpeg"}` |
186
187
  | `attachment` | `json` | File attachment URL or metadata | `{"url": "...", "mime": "application/pdf"}` or `https://example.com/favicon.ico` |
187
- | `upload` | `text` | File upload identifier | Various formats |
188
+ | `upload` | `json` | File upload metadata (URL + MIME) | `{"url": "...", "mime": "application/pdf"}` |
188
189
  | `single_select` | `text` | Single selection value | Text value |
189
190
  | `multiple_select` | `text[]` | Multiple selection values | Array of text values |
190
191
 
@@ -212,17 +213,17 @@ The test suite validates:
212
213
  - Email format validation (valid and invalid cases)
213
214
  - URL format validation with extensive test cases
214
215
  - Hostname format validation
215
- - Image and attachment JSON structure validation
216
+ - Image, upload, and attachment JSON structure validation
216
217
 
217
218
  ## Related Tooling
218
219
 
219
- * [pgpm](https://github.com/launchql/launchql/tree/main/packages/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
220
- * [pgsql-test](https://github.com/launchql/launchql/tree/main/packages/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
221
- * [supabase-test](https://github.com/launchql/launchql/tree/main/packages/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
222
- * [graphile-test](https://github.com/launchql/launchql/tree/main/packages/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
223
- * [pgsql-parser](https://github.com/launchql/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
224
- * [libpg-query-node](https://github.com/launchql/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
225
- * [pg-proto-parser](https://github.com/launchql/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
220
+ * [pgpm](https://github.com/constructive-io/constructive/tree/main/packages/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
221
+ * [pgsql-test](https://github.com/constructive-io/constructive/tree/main/packages/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
222
+ * [supabase-test](https://github.com/constructive-io/constructive/tree/main/packages/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
223
+ * [graphile-test](https://github.com/constructive-io/constructive/tree/main/packages/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
224
+ * [pgsql-parser](https://github.com/constructive-io/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
225
+ * [libpg-query-node](https://github.com/constructive-io/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
226
+ * [pg-proto-parser](https://github.com/constructive-io/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
226
227
 
227
228
  ## Disclaimer
228
229
 
@@ -44,15 +44,37 @@ const invalidUrls = [
44
44
  ];
45
45
 
46
46
  const validAttachments = [
47
+ 'http://www.foo.bar/some.jpg',
48
+ 'https://foo.bar/some.PNG'
49
+ ];
50
+
51
+ const invalidAttachments = [
52
+ 'hi there',
53
+ 'ftp://foo.bar/some.png',
54
+ 'https:///foo.bar/some.png'
55
+ ];
56
+
57
+ const validImages = [
47
58
  { url: 'http://www.foo.bar/some.jpg', mime: 'image/jpg' },
48
59
  { url: 'https://foo.bar/some.PNG', mime: 'image/jpg' }
49
60
  ];
50
61
 
51
- const invalidAttachments = [
62
+ const invalidImages = [
52
63
  { url: 'hi there' },
53
64
  { url: 'https://foo.bar/some.png' }
54
65
  ];
55
66
 
67
+ const validUploads = [
68
+ { url: 'http://www.foo.bar/some.jpg', mime: 'image/jpg' },
69
+ { url: 'https://foo.bar/some.PNG', mime: 'image/png' }
70
+ ];
71
+
72
+ const invalidUploads = [
73
+ { url: 'hi there' },
74
+ { url: 'https://foo.bar/some.png' },
75
+ { url: 'ftp://foo.bar/some.png', mime: 'image/png' }
76
+ ];
77
+
56
78
  let pg: PgTestClient;
57
79
  let teardown: () => Promise<void>;
58
80
 
@@ -68,7 +90,8 @@ CREATE TABLE customers (
68
90
  image image,
69
91
  attachment attachment,
70
92
  domain hostname,
71
- email email
93
+ email email,
94
+ upload upload
72
95
  );
73
96
  `);
74
97
  });
@@ -87,24 +110,48 @@ afterAll(async () => {
87
110
 
88
111
  describe('types', () => {
89
112
  it('valid attachment and image', async () => {
90
- for (const value of validAttachments) {
91
- await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [value]);
92
- await pg.any(`INSERT INTO customers (attachment) VALUES ($1::json);`, [value]);
113
+ for (const attachment of validAttachments) {
114
+ await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [attachment]);
115
+ }
116
+
117
+ for (const image of validImages) {
118
+ await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [image]);
93
119
  }
94
120
  });
95
121
 
96
122
  it('invalid attachment and image', async () => {
97
- for (const value of invalidAttachments) {
123
+ for (const attachment of invalidAttachments) {
98
124
  let failed = false;
99
125
  try {
100
- await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [value]);
126
+ await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [attachment]);
101
127
  } catch (e) {
102
128
  failed = true;
103
129
  }
104
130
  expect(failed).toBe(true);
105
- failed = false;
131
+ }
132
+
133
+ for (const image of invalidImages) {
134
+ let failed = false;
135
+ try {
136
+ await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [image]);
137
+ } catch (e) {
138
+ failed = true;
139
+ }
140
+ expect(failed).toBe(true);
141
+ }
142
+ });
143
+
144
+ it('valid upload', async () => {
145
+ for (const upload of validUploads) {
146
+ await pg.any(`INSERT INTO customers (upload) VALUES ($1::json);`, [upload]);
147
+ }
148
+ });
149
+
150
+ it('invalid upload', async () => {
151
+ for (const upload of invalidUploads) {
152
+ let failed = false;
106
153
  try {
107
- await pg.any(`INSERT INTO customers (image) VALUES ($1);`, [value]);
154
+ await pg.any(`INSERT INTO customers (upload) VALUES ($1::json);`, [upload]);
108
155
  } catch (e) {
109
156
  failed = true;
110
157
  }
@@ -44,15 +44,37 @@ const invalidUrls = [
44
44
  ];
45
45
 
46
46
  const validAttachments = [
47
+ 'http://www.foo.bar/some.jpg',
48
+ 'https://foo.bar/some.PNG'
49
+ ];
50
+
51
+ const invalidAttachments = [
52
+ 'hi there',
53
+ 'ftp://foo.bar/some.png',
54
+ 'https:///foo.bar/some.png'
55
+ ];
56
+
57
+ const validImages = [
47
58
  { url: 'http://www.foo.bar/some.jpg', mime: 'image/jpg' },
48
59
  { url: 'https://foo.bar/some.PNG', mime: 'image/jpg' }
49
60
  ];
50
61
 
51
- const invalidAttachments = [
62
+ const invalidImages = [
52
63
  { url: 'hi there' },
53
64
  { url: 'https://foo.bar/some.png' }
54
65
  ];
55
66
 
67
+ const validUploads = [
68
+ { url: 'http://www.foo.bar/some.jpg', mime: 'image/jpg' },
69
+ { url: 'https://foo.bar/some.PNG', mime: 'image/png' }
70
+ ];
71
+
72
+ const invalidUploads = [
73
+ { url: 'hi there' },
74
+ { url: 'https://foo.bar/some.png' },
75
+ { url: 'ftp://foo.bar/some.png', mime: 'image/png' }
76
+ ];
77
+
56
78
  let pg: PgTestClient;
57
79
  let teardown: () => Promise<void>;
58
80
 
@@ -68,7 +90,8 @@ CREATE TABLE customers (
68
90
  image image,
69
91
  attachment attachment,
70
92
  domain hostname,
71
- email email
93
+ email email,
94
+ upload upload
72
95
  );
73
96
  `);
74
97
  });
@@ -87,24 +110,48 @@ afterAll(async () => {
87
110
 
88
111
  describe('types', () => {
89
112
  it('valid attachment and image', async () => {
90
- for (const value of validAttachments) {
91
- await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [value]);
92
- await pg.any(`INSERT INTO customers (attachment) VALUES ($1::json);`, [value]);
113
+ for (const attachment of validAttachments) {
114
+ await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [attachment]);
115
+ }
116
+
117
+ for (const image of validImages) {
118
+ await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [image]);
93
119
  }
94
120
  });
95
121
 
96
122
  it('invalid attachment and image', async () => {
97
- for (const value of invalidAttachments) {
123
+ for (const attachment of invalidAttachments) {
98
124
  let failed = false;
99
125
  try {
100
- await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [value]);
126
+ await pg.any(`INSERT INTO customers (attachment) VALUES ($1);`, [attachment]);
101
127
  } catch (e) {
102
128
  failed = true;
103
129
  }
104
130
  expect(failed).toBe(true);
105
- failed = false;
131
+ }
132
+
133
+ for (const image of invalidImages) {
134
+ let failed = false;
135
+ try {
136
+ await pg.any(`INSERT INTO customers (image) VALUES ($1::json);`, [image]);
137
+ } catch (e) {
138
+ failed = true;
139
+ }
140
+ expect(failed).toBe(true);
141
+ }
142
+ });
143
+
144
+ it('valid upload', async () => {
145
+ for (const upload of validUploads) {
146
+ await pg.any(`INSERT INTO customers (upload) VALUES ($1::json);`, [upload]);
147
+ }
148
+ });
149
+
150
+ it('invalid upload', async () => {
151
+ for (const upload of invalidUploads) {
152
+ let failed = false;
106
153
  try {
107
- await pg.any(`INSERT INTO customers (image) VALUES ($1);`, [value]);
154
+ await pg.any(`INSERT INTO customers (upload) VALUES ($1::json);`, [upload]);
108
155
  } catch (e) {
109
156
  failed = true;
110
157
  }
@@ -2,16 +2,6 @@
2
2
  -- requires: schemas/public/schema
3
3
 
4
4
  BEGIN;
5
- CREATE DOMAIN attachment AS jsonb CHECK (
6
- (
7
- jsonb_typeof(VALUE) = 'object'
8
- AND VALUE ?& ARRAY['url', 'mime']
9
- AND VALUE->>'url' ~ '^(https?)://[^\s/$.?#].[^\s]*$'
10
- )
11
- OR (
12
- jsonb_typeof(VALUE) = 'string'
13
- AND VALUE #>> '{}' ~ '^(https?)://[^\s/$.?#].[^\s]*$'
14
- )
15
- );
5
+ CREATE DOMAIN attachment AS text CHECK (VALUE ~ '^(https?)://[^\s/$.?#].[^\s]*$');
16
6
  COMMENT ON DOMAIN attachment IS E'@name launchqlInternalTypeAttachment';
17
7
  COMMIT;
@@ -4,7 +4,11 @@
4
4
 
5
5
  BEGIN;
6
6
 
7
- CREATE DOMAIN upload AS text CHECK (VALUE ~ '^(https?)://[^\s/$.?#].[^\s]*$');
7
+ CREATE DOMAIN upload AS jsonb CHECK (
8
+ value ?& ARRAY['url', 'mime']
9
+ AND
10
+ value->>'url' ~ '^(https?)://[^\s/$.?#].[^\s]*$'
11
+ );
8
12
  COMMENT ON DOMAIN upload IS E'@name launchqlInternalTypeUpload';
9
13
 
10
14
  COMMIT;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@pgpm/types",
3
- "version": "0.12.2",
3
+ "version": "0.14.0",
4
4
  "description": "Core PostgreSQL data types with deploy/verify/revert SQL scripts",
5
5
  "author": "Dan Lynch <pyramation@gmail.com>",
6
6
  "contributors": [
7
- "Interweb <developers@interweb.co>"
7
+ "Constructive <developers@constructive.io>"
8
8
  ],
9
9
  "keywords": [
10
10
  "postgresql",
@@ -21,18 +21,18 @@
21
21
  "test:watch": "jest --watch"
22
22
  },
23
23
  "dependencies": {
24
- "@pgpm/verify": "0.12.0"
24
+ "@pgpm/verify": "0.14.0"
25
25
  },
26
26
  "devDependencies": {
27
- "pgpm": "^0.2.0"
27
+ "pgpm": "^1.0.0"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
31
- "url": "https://github.com/launchql/pgpm-modules"
31
+ "url": "https://github.com/constructive-io/pgpm-modules"
32
32
  },
33
- "homepage": "https://github.com/launchql/pgpm-modules",
33
+ "homepage": "https://github.com/constructive-io/pgpm-modules",
34
34
  "bugs": {
35
- "url": "https://github.com/launchql/pgpm-modules/issues"
35
+ "url": "https://github.com/constructive-io/pgpm-modules/issues"
36
36
  },
37
- "gitHead": "880c1b99631ac536288584ace0ac3dd40300f17e"
37
+ "gitHead": "7369638ab084da95b0cb00ec63ad236637f6ebe5"
38
38
  }
@@ -35,12 +35,15 @@ CREATE DOMAIN single_select AS jsonb
35
35
 
36
36
  COMMENT ON DOMAIN single_select IS '@name launchqlInternalTypeSingleSelect';
37
37
 
38
- CREATE DOMAIN upload AS text
39
- CHECK (value ~ E'^(https?)://[^\\s/$.?#].[^\\s]*$');
38
+ CREATE DOMAIN upload AS jsonb
39
+ CHECK (
40
+ value ?& ARRAY['url', 'mime']
41
+ AND (value ->> 'url') ~ E'^(https?)://[^\\s/$.?#].[^\\s]*$'
42
+ );
40
43
 
41
44
  COMMENT ON DOMAIN upload IS '@name launchqlInternalTypeUpload';
42
45
 
43
46
  CREATE DOMAIN url AS text
44
47
  CHECK (value ~ E'^(https?)://[^\\s/$.?#].[^\\s]*$');
45
48
 
46
- COMMENT ON DOMAIN url IS '@name launchqlInternalTypeUrl';
49
+ COMMENT ON DOMAIN url IS '@name launchqlInternalTypeUrl';