@pgpm/services 0.16.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.
Files changed (31) hide show
  1. package/LICENSE +22 -0
  2. package/__tests__/__snapshots__/services.test.ts.snap +147 -0
  3. package/__tests__/services.test.ts +210 -0
  4. package/deploy/schemas/services_private/schema.sql +14 -0
  5. package/deploy/schemas/services_public/schema.sql +15 -0
  6. package/deploy/schemas/services_public/tables/api_extensions/table.sql +36 -0
  7. package/deploy/schemas/services_public/tables/api_modules/table.sql +30 -0
  8. package/deploy/schemas/services_public/tables/api_schemata/table.sql +30 -0
  9. package/deploy/schemas/services_public/tables/apis/table.sql +26 -0
  10. package/deploy/schemas/services_public/tables/apps/table.sql +34 -0
  11. package/deploy/schemas/services_public/tables/domains/table.sql +41 -0
  12. package/deploy/schemas/services_public/tables/site_metadata/table.sql +33 -0
  13. package/deploy/schemas/services_public/tables/site_modules/table.sql +28 -0
  14. package/deploy/schemas/services_public/tables/site_themes/table.sql +27 -0
  15. package/deploy/schemas/services_public/tables/sites/table.sql +30 -0
  16. package/jest.config.js +15 -0
  17. package/package.json +39 -0
  18. package/pgpm.plan +16 -0
  19. package/revert/schemas/services_private/schema.sql +7 -0
  20. package/revert/schemas/services_public/schema.sql +7 -0
  21. package/revert/schemas/services_public/tables/api_extensions/table.sql +7 -0
  22. package/revert/schemas/services_public/tables/api_modules/table.sql +7 -0
  23. package/revert/schemas/services_public/tables/api_schemata/table.sql +7 -0
  24. package/revert/schemas/services_public/tables/apis/table.sql +7 -0
  25. package/revert/schemas/services_public/tables/apps/table.sql +7 -0
  26. package/revert/schemas/services_public/tables/domains/table.sql +7 -0
  27. package/revert/schemas/services_public/tables/site_metadata/table.sql +7 -0
  28. package/revert/schemas/services_public/tables/site_modules/table.sql +7 -0
  29. package/revert/schemas/services_public/tables/site_themes/table.sql +7 -0
  30. package/revert/schemas/services_public/tables/sites/table.sql +7 -0
  31. package/services.control +7 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
+ Copyright (c) 2025 Constructive
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,147 @@
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
+
3
+ exports[`services functionality should handle complete meta workflow with services 1`] = `
4
+ {
5
+ "hash": null,
6
+ "id": "[ID]",
7
+ "label": null,
8
+ "name": "my-meta-db",
9
+ "owner_id": "[ID]",
10
+ "private_schema_name": null,
11
+ "schema_hash": null,
12
+ "schema_name": null,
13
+ }
14
+ `;
15
+
16
+ exports[`services functionality should handle complete meta workflow with services 2`] = `
17
+ {
18
+ "anon_role": "anonymous",
19
+ "database_id": "[ID]",
20
+ "dbname": "test-database",
21
+ "id": "[ID]",
22
+ "is_public": true,
23
+ "name": "public",
24
+ "role_name": "authenticated",
25
+ }
26
+ `;
27
+
28
+ exports[`services functionality should handle complete meta workflow with services 3`] = `
29
+ {
30
+ "anon_role": "administrator",
31
+ "database_id": "[ID]",
32
+ "dbname": "test-database",
33
+ "id": "[ID]",
34
+ "is_public": true,
35
+ "name": "admin",
36
+ "role_name": "administrator",
37
+ }
38
+ `;
39
+
40
+ exports[`services functionality should handle complete meta workflow with services 4`] = `
41
+ {
42
+ "apple_touch_icon": null,
43
+ "database_id": "[ID]",
44
+ "dbname": "test-database",
45
+ "description": "Website Description",
46
+ "favicon": null,
47
+ "id": "[ID]",
48
+ "logo": null,
49
+ "og_image": null,
50
+ "title": "Website Title",
51
+ }
52
+ `;
53
+
54
+ exports[`services functionality should handle complete meta workflow with services 5`] = `
55
+ {
56
+ "api_id": "[ID]",
57
+ "database_id": "[ID]",
58
+ "domain": "pgpm.io",
59
+ "id": "[ID]",
60
+ "site_id": null,
61
+ "subdomain": "api",
62
+ }
63
+ `;
64
+
65
+ exports[`services functionality should handle complete meta workflow with services 6`] = `
66
+ {
67
+ "api_id": null,
68
+ "database_id": "[ID]",
69
+ "domain": "pgpm.io",
70
+ "id": "[ID]",
71
+ "site_id": "[ID]",
72
+ "subdomain": "app",
73
+ }
74
+ `;
75
+
76
+ exports[`services functionality should handle complete meta workflow with services 7`] = `
77
+ {
78
+ "api_id": "[ID]",
79
+ "database_id": "[ID]",
80
+ "domain": "pgpm.io",
81
+ "id": "[ID]",
82
+ "site_id": null,
83
+ "subdomain": "admin",
84
+ }
85
+ `;
86
+
87
+ exports[`services functionality should handle complete meta workflow with services 8`] = `
88
+ {
89
+ "data": {
90
+ "supportEmail": "support@interweb.co",
91
+ },
92
+ "database_id": "[ID]",
93
+ "id": "[ID]",
94
+ "name": "legal-emails",
95
+ "site_id": "[ID]",
96
+ }
97
+ `;
98
+
99
+ exports[`services functionality should handle complete meta workflow with services 9`] = `
100
+ {
101
+ "api_id": "[ID]",
102
+ "data": {
103
+ "authenticate": "authenticate",
104
+ "authenticate_schema": "services_private",
105
+ },
106
+ "database_id": "[ID]",
107
+ "id": "[ID]",
108
+ "name": "rls_module",
109
+ }
110
+ `;
111
+
112
+ exports[`services functionality should handle complete meta workflow with services 10`] = `
113
+ {
114
+ "data": {
115
+ "auth_schema": "services_public",
116
+ "forgot_password": "forgot_password",
117
+ "reset_password": "reset_password",
118
+ "send_verification_email": "send_verification_email",
119
+ "set_password": "set_password",
120
+ "sign_in": "login",
121
+ "sign_up": "register",
122
+ "verify_email": "verify_email",
123
+ },
124
+ "database_id": "[ID]",
125
+ "id": "[ID]",
126
+ "name": "user_auth_module",
127
+ "site_id": "[ID]",
128
+ }
129
+ `;
130
+
131
+ exports[`services functionality should handle complete meta workflow with services 11`] = `
132
+ {
133
+ "api_id": "[ID]",
134
+ "database_id": "[ID]",
135
+ "id": "[ID]",
136
+ "schema_id": "[ID]",
137
+ }
138
+ `;
139
+
140
+ exports[`services functionality should handle complete meta workflow with services 12`] = `
141
+ {
142
+ "api_id": "[ID]",
143
+ "database_id": "[ID]",
144
+ "id": "[ID]",
145
+ "schema_id": "[ID]",
146
+ }
147
+ `;
@@ -0,0 +1,210 @@
1
+ import { getConnections, PgTestClient, snapshot } from 'pgsql-test';
2
+
3
+ let pg: PgTestClient;
4
+ let teardown: () => Promise<void>;
5
+
6
+ describe('services functionality', () => {
7
+ beforeAll(async () => {
8
+ ({ pg, teardown } = await getConnections());
9
+ });
10
+
11
+ afterAll(async () => {
12
+ await teardown();
13
+ });
14
+
15
+ beforeEach(async () => {
16
+ await pg.beforeEach();
17
+ await pg.any(`GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO public`);
18
+ });
19
+
20
+ afterEach(async () => {
21
+ await pg.afterEach();
22
+ });
23
+
24
+ it('should handle complete meta workflow with services', async () => {
25
+ const objs: Record<string, any> = {
26
+ tables: {},
27
+ domains: {},
28
+ apis: {},
29
+ sites: {}
30
+ };
31
+
32
+ const owner_id = '07281002-1699-4762-57e3-ab1b92243120';
33
+
34
+ const snap = (obj: any) => {
35
+ expect(snapshot(obj)).toMatchSnapshot();
36
+ };
37
+
38
+ const snapWithNormalizedDbname = (obj: any) => {
39
+ const normalized = {
40
+ ...obj,
41
+ dbname: 'test-database'
42
+ };
43
+ expect(snapshot(normalized)).toMatchSnapshot();
44
+ };
45
+
46
+ // Step 1: Create database
47
+ const [database] = await pg.any(
48
+ `INSERT INTO metaschema_public.database (owner_id, name)
49
+ VALUES ($1, $2)
50
+ RETURNING *`,
51
+ [owner_id, 'my-meta-db']
52
+ );
53
+ objs.db = database;
54
+ const database_id = database.id;
55
+ expect(snapshot(database)).toMatchSnapshot();
56
+
57
+ // Step 2: Create APIs first (since domains reference them)
58
+ const [publicApi] = await pg.any(
59
+ `INSERT INTO services_public.apis (database_id, name, role_name, anon_role)
60
+ VALUES ($1, $2, $3, $4)
61
+ RETURNING *`,
62
+ [database_id, 'public', 'authenticated', 'anonymous']
63
+ );
64
+ objs.apis.public = publicApi;
65
+ snapWithNormalizedDbname(publicApi);
66
+
67
+ const [adminApi] = await pg.any(
68
+ `INSERT INTO services_public.apis (database_id, name, role_name, anon_role)
69
+ VALUES ($1, $2, $3, $4)
70
+ RETURNING *`,
71
+ [database_id, 'admin', 'administrator', 'administrator']
72
+ );
73
+ objs.apis.admin = adminApi;
74
+ snapWithNormalizedDbname(adminApi);
75
+
76
+ // Step 3: Create sites
77
+ const [appSite] = await pg.any(
78
+ `INSERT INTO services_public.sites (database_id, title, description)
79
+ VALUES ($1, $2, $3)
80
+ RETURNING *`,
81
+ [database_id, 'Website Title', 'Website Description']
82
+ );
83
+ objs.sites.app = appSite;
84
+ snapWithNormalizedDbname(appSite);
85
+
86
+ // Step 4: Register domains (linking to APIs and sites)
87
+ const [apiDomain] = await pg.any(
88
+ `INSERT INTO services_public.domains (database_id, api_id, domain, subdomain)
89
+ VALUES ($1, $2, $3, $4)
90
+ RETURNING *`,
91
+ [database_id, objs.apis.public.id, 'pgpm.io', 'api']
92
+ );
93
+ objs.domains.api = apiDomain;
94
+ expect(snapshot(apiDomain)).toMatchSnapshot();
95
+
96
+ const [appDomain] = await pg.any(
97
+ `INSERT INTO services_public.domains (database_id, site_id, domain, subdomain)
98
+ VALUES ($1, $2, $3, $4)
99
+ RETURNING *`,
100
+ [database_id, objs.sites.app.id, 'pgpm.io', 'app']
101
+ );
102
+ objs.domains.app = appDomain;
103
+ expect(snapshot(appDomain)).toMatchSnapshot();
104
+
105
+ const [adminDomain] = await pg.any(
106
+ `INSERT INTO services_public.domains (database_id, api_id, domain, subdomain)
107
+ VALUES ($1, $2, $3, $4)
108
+ RETURNING *`,
109
+ [database_id, objs.apis.admin.id, 'pgpm.io', 'admin']
110
+ );
111
+ objs.domains.admin = adminDomain;
112
+ expect(snapshot(adminDomain)).toMatchSnapshot();
113
+
114
+ const [baseDomain] = await pg.any(
115
+ `INSERT INTO services_public.domains (database_id, domain)
116
+ VALUES ($1, $2)
117
+ RETURNING *`,
118
+ [database_id, 'pgpm.io']
119
+ );
120
+ objs.domains.base = baseDomain;
121
+
122
+ // Step 5: Register modules
123
+ const [siteModule1] = await pg.any(
124
+ `INSERT INTO services_public.site_modules (database_id, site_id, name, data)
125
+ VALUES ($1, $2, $3, $4::jsonb)
126
+ RETURNING *`,
127
+ [database_id, objs.sites.app.id, 'legal-emails', JSON.stringify({
128
+ supportEmail: 'support@interweb.co'
129
+ })]
130
+ );
131
+ expect(snapshot(siteModule1)).toMatchSnapshot();
132
+
133
+ const [apiModule] = await pg.any(
134
+ `INSERT INTO services_public.api_modules (database_id, api_id, name, data)
135
+ VALUES ($1, $2, $3, $4::jsonb)
136
+ RETURNING *`,
137
+ [database_id, objs.apis.public.id, 'rls_module', JSON.stringify({
138
+ authenticate_schema: 'services_private',
139
+ authenticate: 'authenticate'
140
+ })]
141
+ );
142
+ expect(snapshot(apiModule)).toMatchSnapshot();
143
+
144
+ const [siteModule2] = await pg.any(
145
+ `INSERT INTO services_public.site_modules (database_id, site_id, name, data)
146
+ VALUES ($1, $2, $3, $4::jsonb)
147
+ RETURNING *`,
148
+ [database_id, objs.sites.app.id, 'user_auth_module', JSON.stringify({
149
+ auth_schema: 'services_public',
150
+ sign_in: 'login',
151
+ sign_up: 'register',
152
+ set_password: 'set_password',
153
+ reset_password: 'reset_password',
154
+ forgot_password: 'forgot_password',
155
+ send_verification_email: 'send_verification_email',
156
+ verify_email: 'verify_email'
157
+ })]
158
+ );
159
+ expect(snapshot(siteModule2)).toMatchSnapshot();
160
+
161
+ // Step 6: Schema associations
162
+ const [schema] = await pg.any(
163
+ `INSERT INTO metaschema_public.schema (database_id, schema_name, name)
164
+ VALUES ($1, $2, $3)
165
+ RETURNING *`,
166
+ [database_id, 'brand-public', 'public']
167
+ );
168
+
169
+ const [publicAssoc] = await pg.any(
170
+ `INSERT INTO services_public.api_schemata (database_id, schema_id, api_id)
171
+ VALUES ($1, $2, $3)
172
+ RETURNING *`,
173
+ [database_id, schema.id, objs.apis.public.id]
174
+ );
175
+
176
+ const [adminAssoc] = await pg.any(
177
+ `INSERT INTO services_public.api_schemata (database_id, schema_id, api_id)
178
+ VALUES ($1, $2, $3)
179
+ RETURNING *`,
180
+ [database_id, schema.id, objs.apis.admin.id]
181
+ );
182
+
183
+ snap(publicAssoc);
184
+ snap(adminAssoc);
185
+ });
186
+
187
+ it('should register domain independently', async () => {
188
+ const owner_id = '07281002-1699-4762-57e3-ab1b92243120';
189
+
190
+ // Create database first
191
+ const [database] = await pg.any(
192
+ `INSERT INTO metaschema_public.database (owner_id, name)
193
+ VALUES ($1, $2)
194
+ RETURNING *`,
195
+ [owner_id, 'test-db-for-domain']
196
+ );
197
+
198
+ // Then create domain
199
+ const [domain] = await pg.any(
200
+ `INSERT INTO services_public.domains (database_id, domain, subdomain)
201
+ VALUES ($1, $2, $3)
202
+ RETURNING *`,
203
+ [database.id, 'example.com', 'api']
204
+ );
205
+
206
+ expect(domain.database_id).toBe(database.id);
207
+ expect(domain.domain).toBe('example.com');
208
+ expect(domain.subdomain).toBe('api');
209
+ });
210
+ });
@@ -0,0 +1,14 @@
1
+ -- Deploy schemas/services_private/schema to pg
2
+
3
+
4
+ BEGIN;
5
+
6
+ CREATE SCHEMA services_private;
7
+
8
+ GRANT USAGE ON SCHEMA services_private TO authenticated;
9
+ GRANT USAGE ON SCHEMA services_private TO administrator;
10
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_private GRANT ALL ON TABLES TO administrator;
11
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_private GRANT ALL ON SEQUENCES TO administrator;
12
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_private GRANT ALL ON FUNCTIONS TO administrator;
13
+
14
+ COMMIT;
@@ -0,0 +1,15 @@
1
+ -- Deploy schemas/services_public/schema to pg
2
+
3
+
4
+ BEGIN;
5
+
6
+ CREATE SCHEMA services_public;
7
+
8
+ GRANT USAGE ON SCHEMA services_public TO authenticated;
9
+ GRANT USAGE ON SCHEMA services_public TO administrator;
10
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_public GRANT ALL ON TABLES TO administrator;
11
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_public GRANT ALL ON SEQUENCES TO administrator;
12
+ ALTER DEFAULT PRIVILEGES IN SCHEMA services_public GRANT ALL ON FUNCTIONS TO administrator;
13
+
14
+
15
+ COMMIT;
@@ -0,0 +1,36 @@
1
+ -- Deploy schemas/services_public/tables/api_extensions/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/apis/table
5
+
6
+ -- requires: schemas/metaschema_public/tables/database_extension/table
7
+ -- requires: schemas/metaschema_public/tables/extension/table
8
+ -- requires: schemas/metaschema_public/tables/database/table
9
+
10
+
11
+ BEGIN;
12
+
13
+ -- NOTE: not directly mapping to extensions on purpose, to make it simple for api usage
14
+
15
+ CREATE TABLE services_public.api_extensions (
16
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
17
+ schema_name text,
18
+ database_id uuid NOT NULL,
19
+ api_id uuid NOT NULL,
20
+
21
+ --
22
+
23
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
24
+ CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE,
25
+
26
+ UNIQUE (schema_name, api_id)
27
+ );
28
+
29
+ -- WE DO WANT m2m!
30
+ -- COMMENT ON CONSTRAINT db_fkey ON services_public.api_extensions IS E'@omit manyToMany';
31
+ -- COMMENT ON CONSTRAINT api_fkey ON services_public.api_extensions IS E'@omit manyToMany';
32
+
33
+ CREATE INDEX api_extension_database_id_idx ON services_public.api_extensions ( database_id );
34
+ CREATE INDEX api_extension_api_id_idx ON services_public.api_extensions ( api_id );
35
+
36
+ COMMIT;
@@ -0,0 +1,30 @@
1
+ -- Deploy schemas/services_public/tables/api_modules/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/apis/table
5
+ -- requires: schemas/metaschema_public/tables/database/table
6
+
7
+ BEGIN;
8
+
9
+ CREATE TABLE services_public.api_modules (
10
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
11
+ database_id uuid NOT NULL,
12
+ api_id uuid NOT NULL,
13
+ name text NOT NULL,
14
+ data json NOT NULL,
15
+
16
+ --
17
+
18
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE
19
+
20
+ );
21
+
22
+ ALTER TABLE services_public.api_modules ADD CONSTRAINT api_modules_api_id_fkey FOREIGN KEY ( api_id ) REFERENCES services_public.apis ( id );
23
+ COMMENT ON CONSTRAINT api_modules_api_id_fkey ON services_public.api_modules IS E'@omit manyToMany';
24
+ CREATE INDEX api_modules_api_id_idx ON services_public.api_modules ( api_id );
25
+
26
+ COMMENT ON CONSTRAINT db_fkey ON services_public.api_modules IS E'@omit manyToMany';
27
+ CREATE INDEX api_modules_database_id_idx ON services_public.api_modules ( database_id );
28
+
29
+
30
+ COMMIT;
@@ -0,0 +1,30 @@
1
+ -- Deploy schemas/services_public/tables/api_schemata/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+
5
+ BEGIN;
6
+
7
+ CREATE TABLE services_public.api_schemata (
8
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
9
+ database_id uuid NOT NULL,
10
+ schema_id uuid NOT NULL,
11
+ api_id uuid NOT NULL,
12
+
13
+ --
14
+
15
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
16
+ CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE,
17
+ CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE,
18
+ unique(api_id, schema_id)
19
+ );
20
+
21
+ -- COMMENT ON CONSTRAINT schema_fkey ON services_public.api_schemata IS E'@omit manyToMany';
22
+ -- COMMENT ON CONSTRAINT api_fkey ON services_public.api_schemata IS E'@omit manyToMany';
23
+ COMMENT ON CONSTRAINT db_fkey ON services_public.api_schemata IS E'@omit manyToMany';
24
+
25
+
26
+ CREATE INDEX api_schemata_database_id_idx ON services_public.api_schemata ( database_id );
27
+ CREATE INDEX api_schemata_schema_id_idx ON services_public.api_schemata ( schema_id );
28
+ CREATE INDEX api_schemata_api_id_idx ON services_public.api_schemata ( api_id );
29
+
30
+ COMMIT;
@@ -0,0 +1,26 @@
1
+ -- Deploy schemas/services_public/tables/apis/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/metaschema_public/tables/database/table
5
+
6
+ BEGIN;
7
+
8
+ CREATE TABLE services_public.apis (
9
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
10
+ database_id uuid NOT NULL,
11
+ name text NOT NULL,
12
+ dbname text NOT NULL DEFAULT current_database(),
13
+ role_name text NOT NULL DEFAULT 'authenticated',
14
+ anon_role text NOT NULL DEFAULT 'anonymous',
15
+ is_public boolean NOT NULL DEFAULT true,
16
+
17
+ --
18
+
19
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
20
+ UNIQUE(database_id, name)
21
+ );
22
+
23
+ COMMENT ON CONSTRAINT db_fkey ON services_public.apis IS E'@omit manyToMany';
24
+ CREATE INDEX apis_database_id_idx ON services_public.apis ( database_id );
25
+
26
+ COMMIT;
@@ -0,0 +1,34 @@
1
+ -- Deploy schemas/services_public/tables/apps/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/sites/table
5
+ -- requires: schemas/metaschema_public/tables/database/table
6
+
7
+ BEGIN;
8
+
9
+ CREATE TABLE services_public.apps (
10
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
11
+ database_id uuid NOT NULL,
12
+ site_id uuid NOT NULL,
13
+ name text,
14
+ app_image image,
15
+ app_store_link url,
16
+ app_store_id text,
17
+ app_id_prefix text,
18
+ play_store_link url,
19
+
20
+ --
21
+
22
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
23
+ UNIQUE ( site_id )
24
+ );
25
+
26
+ ALTER TABLE services_public.apps ADD CONSTRAINT apps_site_id_fkey FOREIGN KEY ( site_id ) REFERENCES services_public.sites ( id );
27
+ COMMENT ON CONSTRAINT apps_site_id_fkey ON services_public.apps IS E'@omit manyToMany';
28
+ CREATE INDEX apps_site_id_idx ON services_public.apps ( site_id );
29
+
30
+ COMMENT ON CONSTRAINT db_fkey ON services_public.apps IS E'@omit manyToMany';
31
+ CREATE INDEX apps_database_id_idx ON services_public.apps ( database_id );
32
+
33
+
34
+ COMMIT;
@@ -0,0 +1,41 @@
1
+ -- Deploy schemas/services_public/tables/domains/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/apis/table
5
+ -- requires: schemas/services_public/tables/sites/table
6
+ -- requires: schemas/metaschema_public/tables/database/table
7
+
8
+ BEGIN;
9
+
10
+ CREATE TABLE services_public.domains (
11
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
12
+ database_id uuid NOT NULL,
13
+
14
+ api_id uuid,
15
+ site_id uuid,
16
+
17
+ subdomain hostname,
18
+ domain hostname,
19
+
20
+ --
21
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
22
+ CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE,
23
+ CONSTRAINT site_fkey FOREIGN KEY (site_id) REFERENCES services_public.sites (id) ON DELETE CASCADE,
24
+ CONSTRAINT one_route_chk CHECK (
25
+ (api_id IS NULL AND site_id IS NULL) OR
26
+ (api_id IS NULL AND site_id IS NOT NULL) OR
27
+ (api_id IS NOT NULL AND site_id IS NULL)
28
+ ),
29
+ UNIQUE ( subdomain, domain )
30
+ );
31
+
32
+ COMMENT ON CONSTRAINT db_fkey ON services_public.domains IS E'@omit manyToMany';
33
+ CREATE INDEX domains_database_id_idx ON services_public.domains ( database_id );
34
+
35
+ COMMENT ON CONSTRAINT api_fkey ON services_public.domains IS E'@omit manyToMany';
36
+ CREATE INDEX domains_api_id_idx ON services_public.domains ( api_id );
37
+
38
+ COMMENT ON CONSTRAINT site_fkey ON services_public.domains IS E'@omit manyToMany';
39
+ CREATE INDEX domains_site_id_idx ON services_public.domains ( site_id );
40
+
41
+ COMMIT;
@@ -0,0 +1,33 @@
1
+ -- Deploy schemas/services_public/tables/site_metadata/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/sites/table
5
+ -- requires: schemas/metaschema_public/tables/database/table
6
+
7
+ BEGIN;
8
+
9
+ CREATE TABLE services_public.site_metadata (
10
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
11
+ database_id uuid NOT NULL,
12
+ site_id uuid NOT NULL,
13
+ title text,
14
+ description text,
15
+ og_image image,
16
+
17
+ --
18
+
19
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
20
+
21
+ CHECK ( character_length(title) <= 120 ),
22
+ CHECK ( character_length(description) <= 120 )
23
+ );
24
+
25
+
26
+ ALTER TABLE services_public.site_metadata ADD CONSTRAINT site_metadata_site_id_fkey FOREIGN KEY ( site_id ) REFERENCES services_public.sites ( id );
27
+ COMMENT ON CONSTRAINT site_metadata_site_id_fkey ON services_public.site_metadata IS E'@omit manyToMany';
28
+ CREATE INDEX site_metadata_site_id_idx ON services_public.site_metadata ( site_id );
29
+
30
+ COMMENT ON CONSTRAINT db_fkey ON services_public.site_metadata IS E'@omit manyToMany';
31
+ CREATE INDEX site_metadata_database_id_idx ON services_public.site_metadata ( database_id );
32
+
33
+ COMMIT;
@@ -0,0 +1,28 @@
1
+ -- Deploy schemas/services_public/tables/site_modules/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/sites/table
5
+ -- requires: schemas/metaschema_public/tables/database/table
6
+
7
+ BEGIN;
8
+
9
+ CREATE TABLE services_public.site_modules (
10
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
11
+ database_id uuid NOT NULL,
12
+ site_id uuid NOT NULL,
13
+ name text NOT NULL,
14
+ data json NOT NULL,
15
+
16
+ --
17
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE
18
+ );
19
+
20
+ ALTER TABLE services_public.site_modules ADD CONSTRAINT site_modules_site_id_fkey FOREIGN KEY ( site_id ) REFERENCES services_public.sites ( id );
21
+ COMMENT ON CONSTRAINT site_modules_site_id_fkey ON services_public.site_modules IS E'@omit manyToMany';
22
+ CREATE INDEX site_modules_site_id_idx ON services_public.site_modules ( site_id );
23
+
24
+ COMMENT ON CONSTRAINT db_fkey ON services_public.site_modules IS E'@omit manyToMany';
25
+ CREATE INDEX site_modules_database_id_idx ON services_public.site_modules ( database_id );
26
+
27
+
28
+ COMMIT;
@@ -0,0 +1,27 @@
1
+ -- Deploy schemas/services_public/tables/site_themes/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/services_public/tables/sites/table
5
+ -- requires: schemas/metaschema_public/tables/database/table
6
+
7
+ BEGIN;
8
+
9
+ CREATE TABLE services_public.site_themes (
10
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
11
+ database_id uuid NOT NULL,
12
+ site_id uuid NOT NULL,
13
+ theme jsonb NOT NULL,
14
+
15
+ --
16
+
17
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE
18
+ );
19
+
20
+ ALTER TABLE services_public.site_themes ADD CONSTRAINT site_themes_site_id_fkey FOREIGN KEY ( site_id ) REFERENCES services_public.sites ( id );
21
+ COMMENT ON CONSTRAINT site_themes_site_id_fkey ON services_public.site_themes IS E'@omit manyToMany';
22
+ CREATE INDEX site_themes_site_id_idx ON services_public.site_themes ( site_id );
23
+
24
+ COMMENT ON CONSTRAINT db_fkey ON services_public.site_themes IS E'@omit manyToMany';
25
+ CREATE INDEX site_themes_database_id_idx ON services_public.site_themes ( database_id );
26
+
27
+ COMMIT;
@@ -0,0 +1,30 @@
1
+ -- Deploy schemas/services_public/tables/sites/table to pg
2
+
3
+ -- requires: schemas/services_public/schema
4
+ -- requires: schemas/metaschema_public/tables/database/table
5
+
6
+ BEGIN;
7
+
8
+ CREATE TABLE services_public.sites (
9
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (),
10
+ database_id uuid NOT NULL,
11
+ title text,
12
+ description text,
13
+ og_image image,
14
+ favicon attachment,
15
+ apple_touch_icon image,
16
+ logo image,
17
+
18
+ -- do we need this?
19
+ dbname text NOT NULL DEFAULT current_database(),
20
+
21
+ --
22
+ CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE,
23
+ CONSTRAINT max_title CHECK ( character_length(title) <= 120 ),
24
+ CONSTRAINT max_descr CHECK ( character_length(description) <= 120 )
25
+ );
26
+
27
+ COMMENT ON CONSTRAINT db_fkey ON services_public.sites IS E'@omit manyToMany';
28
+ CREATE INDEX sites_database_id_idx ON services_public.sites ( database_id );
29
+
30
+ COMMIT;
package/jest.config.js ADDED
@@ -0,0 +1,15 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+
6
+ // Match both __tests__ and colocated test files
7
+ testMatch: ['**/?(*.)+(test|spec).{ts,tsx,js,jsx}'],
8
+
9
+ // Ignore build artifacts and type declarations
10
+ testPathIgnorePatterns: ['/dist/', '\\.d\\.ts$'],
11
+ modulePathIgnorePatterns: ['<rootDir>/dist/'],
12
+ watchPathIgnorePatterns: ['/dist/'],
13
+
14
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
15
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@pgpm/services",
3
+ "version": "0.16.0",
4
+ "description": "Services schemas for module registration and service configuration",
5
+ "author": "Dan Lynch <pyramation@gmail.com>",
6
+ "contributors": [
7
+ "Constructive <developers@constructive.io>"
8
+ ],
9
+ "keywords": [
10
+ "postgresql",
11
+ "pgpm",
12
+ "services",
13
+ "modules"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "scripts": {
19
+ "bundle": "pgpm package",
20
+ "test": "jest",
21
+ "test:watch": "jest --watch"
22
+ },
23
+ "dependencies": {
24
+ "@pgpm/metaschema-schema": "0.16.0",
25
+ "@pgpm/verify": "0.16.0"
26
+ },
27
+ "devDependencies": {
28
+ "pgpm": "^1.3.0"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/constructive-io/constructive-db"
33
+ },
34
+ "homepage": "https://github.com/constructive-io/constructive-db",
35
+ "bugs": {
36
+ "url": "https://github.com/constructive-io/constructive-db/issues"
37
+ },
38
+ "gitHead": "3b2260bf7640d7194f237d556c7e5033bc7a9405"
39
+ }
package/pgpm.plan ADDED
@@ -0,0 +1,16 @@
1
+ %syntax-version=1.0.0
2
+ %project=services
3
+ %uri=services
4
+
5
+ schemas/services_private/schema 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_private/schema
6
+ schemas/services_public/schema 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/schema
7
+ schemas/services_public/tables/apis/table [schemas/services_public/schema metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/apis/table
8
+ schemas/services_public/tables/api_extensions/table [schemas/services_public/schema schemas/services_public/tables/apis/table metaschema-schema:schemas/metaschema_public/tables/database_extension/table metaschema-schema:schemas/metaschema_public/tables/extension/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/api_extensions/table
9
+ schemas/services_public/tables/api_modules/table [schemas/services_public/schema schemas/services_public/tables/apis/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/api_modules/table
10
+ schemas/services_public/tables/api_schemata/table [schemas/services_public/schema] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/api_schemata/table
11
+ schemas/services_public/tables/sites/table [schemas/services_public/schema metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/sites/table
12
+ schemas/services_public/tables/apps/table [schemas/services_public/schema schemas/services_public/tables/sites/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/apps/table
13
+ schemas/services_public/tables/domains/table [schemas/services_public/schema schemas/services_public/tables/apis/table schemas/services_public/tables/sites/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/domains/table
14
+ schemas/services_public/tables/site_metadata/table [schemas/services_public/schema schemas/services_public/tables/sites/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/site_metadata/table
15
+ schemas/services_public/tables/site_modules/table [schemas/services_public/schema schemas/services_public/tables/sites/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/site_modules/table
16
+ schemas/services_public/tables/site_themes/table [schemas/services_public/schema schemas/services_public/tables/sites/table metaschema-schema:schemas/metaschema_public/tables/database/table] 2017-08-11T08:11:51Z skitch <skitch@5b0c196eeb62> # add schemas/services_public/tables/site_themes/table
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_private/schema from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP SCHEMA services_private;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/schema from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP SCHEMA services_public;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/api_extensions/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.api_extensions;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/api_modules/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.api_modules;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/api_schemata/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.api_schemata;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/apis/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.apis;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/apps/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.apps;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/domains/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.domains;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/site_metadata/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.site_metadata;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/site_modules/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.site_modules;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/site_themes/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.site_themes;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ -- Revert schemas/services_public/tables/sites/table from pg
2
+
3
+ BEGIN;
4
+
5
+ DROP TABLE services_public.sites;
6
+
7
+ COMMIT;
@@ -0,0 +1,7 @@
1
+ # services extension
2
+ comment = 'services extension - schemas for module registration and service configuration'
3
+ default_version = '0.1.0'
4
+ module_pathname = '$libdir/services'
5
+ requires = 'plpgsql,metaschema-schema,pgpm-verify'
6
+ relocatable = false
7
+ superuser = false