jinaga-server 1.0.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 (127) hide show
  1. package/LICENSE +22 -0
  2. package/dist/authentication/authentication-device.d.ts +20 -0
  3. package/dist/authentication/authentication-device.js +61 -0
  4. package/dist/authentication/authentication-device.js.map +1 -0
  5. package/dist/authentication/authentication-impl.d.ts +21 -0
  6. package/dist/authentication/authentication-impl.js +61 -0
  7. package/dist/authentication/authentication-impl.js.map +1 -0
  8. package/dist/authentication/authentication-session.d.ts +23 -0
  9. package/dist/authentication/authentication-session.js +85 -0
  10. package/dist/authentication/authentication-session.js.map +1 -0
  11. package/dist/authentication/authentication.d.ts +5 -0
  12. package/dist/authentication/authentication.js +3 -0
  13. package/dist/authentication/authentication.js.map +1 -0
  14. package/dist/authentication.d.ts +17 -0
  15. package/dist/authentication.js +52 -0
  16. package/dist/authentication.js.map +1 -0
  17. package/dist/authorization/authorization-keystore.d.ts +13 -0
  18. package/dist/authorization/authorization-keystore.js +61 -0
  19. package/dist/authorization/authorization-keystore.js.map +1 -0
  20. package/dist/http/node-http.d.ts +7 -0
  21. package/dist/http/node-http.js +126 -0
  22. package/dist/http/node-http.js.map +1 -0
  23. package/dist/http/router.d.ts +20 -0
  24. package/dist/http/router.js +223 -0
  25. package/dist/http/router.js.map +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/jinaga-server.d.ts +18 -0
  30. package/dist/jinaga-server.js +101 -0
  31. package/dist/jinaga-server.js.map +1 -0
  32. package/dist/keystore.d.ts +9 -0
  33. package/dist/keystore.js +3 -0
  34. package/dist/keystore.js.map +1 -0
  35. package/dist/memory/memory-keystore.d.ts +16 -0
  36. package/dist/memory/memory-keystore.js +86 -0
  37. package/dist/memory/memory-keystore.js.map +1 -0
  38. package/dist/postgres/connection.d.ts +12 -0
  39. package/dist/postgres/connection.js +83 -0
  40. package/dist/postgres/connection.js.map +1 -0
  41. package/dist/postgres/edge-record.d.ts +9 -0
  42. package/dist/postgres/edge-record.js +30 -0
  43. package/dist/postgres/edge-record.js.map +1 -0
  44. package/dist/postgres/maps.d.ts +21 -0
  45. package/dist/postgres/maps.js +86 -0
  46. package/dist/postgres/maps.js.map +1 -0
  47. package/dist/postgres/postgres-keystore.d.ts +20 -0
  48. package/dist/postgres/postgres-keystore.js +168 -0
  49. package/dist/postgres/postgres-keystore.js.map +1 -0
  50. package/dist/postgres/postgres-store.d.ts +20 -0
  51. package/dist/postgres/postgres-store.js +717 -0
  52. package/dist/postgres/postgres-store.js.map +1 -0
  53. package/dist/postgres/query-description-builder.d.ts +13 -0
  54. package/dist/postgres/query-description-builder.js +104 -0
  55. package/dist/postgres/query-description-builder.js.map +1 -0
  56. package/dist/postgres/query-description.d.ts +71 -0
  57. package/dist/postgres/query-description.js +256 -0
  58. package/dist/postgres/query-description.js.map +1 -0
  59. package/dist/postgres/specification-result-sql.d.ts +41 -0
  60. package/dist/postgres/specification-result-sql.js +260 -0
  61. package/dist/postgres/specification-result-sql.js.map +1 -0
  62. package/dist/postgres/specification-sql.d.ts +3 -0
  63. package/dist/postgres/specification-sql.js +119 -0
  64. package/dist/postgres/specification-sql.js.map +1 -0
  65. package/dist/postgres/sql.d.ts +10 -0
  66. package/dist/postgres/sql.js +396 -0
  67. package/dist/postgres/sql.js.map +1 -0
  68. package/dist/util/fn.d.ts +6 -0
  69. package/dist/util/fn.js +81 -0
  70. package/dist/util/fn.js.map +1 -0
  71. package/dist/util/promise.d.ts +1 -0
  72. package/dist/util/promise.js +10 -0
  73. package/dist/util/promise.js.map +1 -0
  74. package/docs/registrations.sql +22 -0
  75. package/docs/specification.txt +41 -0
  76. package/docs/sql-generator.gv +25 -0
  77. package/integration-test/docker-compose.yaml +13 -0
  78. package/integration-test/jinaga-test/Dockerfile +12 -0
  79. package/integration-test/jinaga-test/jinaga.test.js +425 -0
  80. package/integration-test/jinaga-test/package-lock.json +6767 -0
  81. package/integration-test/jinaga-test/package.json +25 -0
  82. package/integration-test/postgres/0-init-app-db.sh +16 -0
  83. package/integration-test/postgres/1-setup.sql +219 -0
  84. package/integration-test/postgres/2-grant.sh +17 -0
  85. package/integration-test/postgres/Dockerfile +5 -0
  86. package/integration-test/run.sh +17 -0
  87. package/integration-test/start_db.sh +2 -0
  88. package/integration-test/stop_db.sh +3 -0
  89. package/integration-test/test.sh +8 -0
  90. package/interactive/index.js +56 -0
  91. package/jest.config.js +12 -0
  92. package/package.json +51 -0
  93. package/scripts/combined.sql +46 -0
  94. package/scripts/cte.sql +55 -0
  95. package/scripts/separate.sql +27 -0
  96. package/setup.sh +34 -0
  97. package/setup.sql +329 -0
  98. package/src/authentication/authentication-device.ts +68 -0
  99. package/src/authentication/authentication-impl.ts +59 -0
  100. package/src/authentication/authentication-session.ts +95 -0
  101. package/src/authentication/authentication.ts +6 -0
  102. package/src/authentication.ts +45 -0
  103. package/src/authorization/authorization-keystore.ts +67 -0
  104. package/src/http/node-http.ts +106 -0
  105. package/src/http/router.ts +237 -0
  106. package/src/index.ts +1 -0
  107. package/src/jinaga-server.ts +125 -0
  108. package/src/keystore.ts +10 -0
  109. package/src/memory/memory-keystore.ts +93 -0
  110. package/src/postgres/connection.ts +73 -0
  111. package/src/postgres/edge-record.ts +36 -0
  112. package/src/postgres/maps.ts +89 -0
  113. package/src/postgres/postgres-keystore.ts +167 -0
  114. package/src/postgres/postgres-store.ts +874 -0
  115. package/src/postgres/query-description-builder.ts +116 -0
  116. package/src/postgres/query-description.ts +385 -0
  117. package/src/postgres/specification-result-sql.ts +362 -0
  118. package/src/postgres/specification-sql.ts +138 -0
  119. package/src/postgres/sql.ts +482 -0
  120. package/src/util/fn.ts +63 -0
  121. package/src/util/promise.ts +5 -0
  122. package/test/authorization/authorizationSpec.ts +209 -0
  123. package/test/postgres/postgresSpec.ts +385 -0
  124. package/test/postgres/postgresSpecificationSpec.ts +742 -0
  125. package/test/reporter.js +25 -0
  126. package/tsconfig.json +25 -0
  127. package/upgrade.sh +21 -0
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "jinaga-test",
3
+ "version": "1.0.0",
4
+ "description": "Integration tests for Jinaga.JS",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "jest --reporters jest-compact-reporter",
8
+ "test:verbose": "jest --silent=false --verbose false"
9
+ },
10
+ "jest": {
11
+ "verbose": false
12
+ },
13
+ "author": "Michael L Perry",
14
+ "license": "MIT",
15
+ "dependencies": {
16
+ "express": "^4.17.2",
17
+ "jest": "^28.1.0",
18
+ "jest-compact-reporter": "^1.2.9",
19
+ "node-forge": "^1.3.0",
20
+ "passport": "^0.5.2",
21
+ "pg": "^8.7.1",
22
+ "tweetnacl": "^1.0.3",
23
+ "tweetnacl-util": "^0.15.1"
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
5
+ SELECT '$APP_USERNAME';
6
+ CREATE USER $APP_USERNAME WITH
7
+ LOGIN
8
+ ENCRYPTED PASSWORD '$APP_PASSWORD'
9
+ NOSUPERUSER
10
+ INHERIT
11
+ NOCREATEDB
12
+ NOCREATEROLE
13
+ NOREPLICATION
14
+ VALID UNTIL 'infinity';
15
+ CREATE DATABASE $APP_DATABASE;
16
+ EOSQL
@@ -0,0 +1,219 @@
1
+ --
2
+ -- Create tables for a Jinaga database
3
+ --
4
+ -- Before executing, be sure you have created the database and the dev role.
5
+ --
6
+ -- CREATE DATABASE myapplication;
7
+ -- \connect myapplication
8
+ --
9
+ -- CREATE USER dev WITH
10
+ -- LOGIN
11
+ -- ENCRYPTED PASSWORD 'devpassword'
12
+ -- NOSUPERUSER
13
+ -- INHERIT
14
+ -- NOCREATEDB
15
+ -- NOCREATEROLE
16
+ -- NOREPLICATION
17
+ -- VALID UNTIL 'infinity';
18
+ --
19
+
20
+ \set appdatabase `echo "$APP_DATABASE"`
21
+
22
+ \connect :appdatabase
23
+
24
+ DO
25
+ $do$
26
+ BEGIN
27
+
28
+ CREATE EXTENSION IF NOT EXISTS intarray;
29
+
30
+ --
31
+ -- Fact Type
32
+ --
33
+
34
+ IF (SELECT to_regclass('public.fact_type')) IS NULL THEN
35
+
36
+ CREATE TABLE fact_type (
37
+ fact_type_id serial PRIMARY KEY,
38
+ name character varying(50) NOT NULL
39
+ );
40
+
41
+
42
+ ALTER TABLE public.fact_type OWNER TO postgres;
43
+
44
+ CREATE UNIQUE INDEX ux_fact_type ON fact_type (name);
45
+
46
+ END IF;
47
+
48
+ --
49
+ -- Role
50
+ --
51
+
52
+ IF (SELECT to_regclass('public.role')) IS NULL THEN
53
+
54
+ CREATE TABLE role (
55
+ role_id serial PRIMARY KEY,
56
+ defining_fact_type_id integer NOT NULL,
57
+ CONSTRAINT fk_defining_fact_type_id
58
+ FOREIGN KEY (defining_fact_type_id)
59
+ REFERENCES fact_type (fact_type_id),
60
+ name character varying(20) NOT NULL
61
+ );
62
+
63
+
64
+ ALTER TABLE public.role OWNER TO postgres;
65
+
66
+ CREATE UNIQUE INDEX ux_role ON public.role USING btree (defining_fact_type_id, name);
67
+
68
+ END IF;
69
+
70
+ --
71
+ -- Fact
72
+ --
73
+
74
+ IF (SELECT to_regclass('public.fact') IS NULL) THEN
75
+
76
+ CREATE TABLE public.fact (
77
+ fact_id SERIAL PRIMARY KEY,
78
+ fact_type_id integer NOT NULL,
79
+ CONSTRAINT fk_fact_type_id
80
+ FOREIGN KEY (fact_type_id)
81
+ REFERENCES fact_type (fact_type_id),
82
+ hash character varying(100),
83
+ data jsonb,
84
+ date_learned timestamp NOT NULL
85
+ DEFAULT (now() at time zone 'utc')
86
+ );
87
+
88
+
89
+ ALTER TABLE public.fact OWNER TO postgres;
90
+
91
+ CREATE UNIQUE INDEX ux_fact ON public.fact USING btree (hash, fact_type_id);
92
+
93
+ END IF;
94
+
95
+ --
96
+ -- Edge
97
+ --
98
+
99
+ IF (SELECT to_regclass('public.edge') IS NULL) THEN
100
+
101
+ CREATE TABLE public.edge (
102
+ role_id integer NOT NULL,
103
+ CONSTRAINT fk_role_id
104
+ FOREIGN KEY (role_id)
105
+ REFERENCES role (role_id),
106
+ successor_fact_id integer NOT NULL,
107
+ CONSTRAINT fk_successor_fact_id
108
+ FOREIGN KEY (successor_fact_id)
109
+ REFERENCES fact (fact_id),
110
+ predecessor_fact_id integer NOT NULL,
111
+ CONSTRAINT fk_predecessor_fact_id
112
+ FOREIGN KEY (predecessor_fact_id)
113
+ REFERENCES fact (fact_id)
114
+ );
115
+
116
+
117
+ ALTER TABLE public.edge OWNER TO postgres;
118
+
119
+ -- Most unique first, for fastest uniqueness check on insert.
120
+ CREATE UNIQUE INDEX ux_edge ON public.edge USING btree (successor_fact_id, predecessor_fact_id, role_id);
121
+ -- Covering index based on successor, favoring most likely members of WHERE clause.
122
+ CREATE INDEX ix_successor ON public.edge USING btree (successor_fact_id, role_id, predecessor_fact_id);
123
+ -- Covering index based on predecessor, favoring most likely members of WHERE clause.
124
+ CREATE INDEX ix_predecessor ON public.edge USING btree (predecessor_fact_id, role_id, successor_fact_id);
125
+
126
+ END IF;
127
+
128
+ --
129
+ -- Ancestor
130
+ --
131
+
132
+ IF (SELECT to_regclass('public.ancestor') IS NULL) THEN
133
+
134
+ CREATE TABLE public.ancestor (
135
+ fact_id integer NOT NULL,
136
+ CONSTRAINT fk_fact_id
137
+ FOREIGN KEY (fact_id)
138
+ REFERENCES fact (fact_id),
139
+ ancestor_fact_id integer NOT NULL,
140
+ CONSTRAINT fk_ancestor_fact_id
141
+ FOREIGN KEY (ancestor_fact_id)
142
+ REFERENCES fact (fact_id)
143
+ );
144
+
145
+
146
+ ALTER TABLE public.ancestor OWNER TO postgres;
147
+
148
+ CREATE UNIQUE INDEX ux_ancestor ON public.ancestor USING btree (fact_id, ancestor_fact_id);
149
+
150
+ END IF;
151
+
152
+ --
153
+ -- Public Key
154
+ --
155
+
156
+ IF (SELECT to_regclass('public.public_key') IS NULL) THEN
157
+
158
+ CREATE TABLE public.public_key (
159
+ public_key_id serial PRIMARY KEY,
160
+ public_key character varying(500) NOT NULL
161
+ );
162
+
163
+
164
+ ALTER TABLE public.public_key OWNER TO postgres;
165
+
166
+ CREATE UNIQUE INDEX ux_public_key ON public.public_key (public_key);
167
+
168
+ END IF;
169
+
170
+ --
171
+ -- Signature
172
+ --
173
+
174
+ IF (SELECT to_regclass('public.signature') IS NULL) THEN
175
+
176
+ CREATE TABLE public."signature" (
177
+ fact_id integer NOT NULL,
178
+ CONSTRAINT fk_fact_id
179
+ FOREIGN KEY (fact_id)
180
+ REFERENCES fact (fact_id),
181
+ public_key_id integer NOT NULL,
182
+ CONSTRAINT fk_public_key_id
183
+ FOREIGN KEY (public_key_id)
184
+ REFERENCES public_key (public_key_id),
185
+ signature character varying(400),
186
+ date_learned timestamp NOT NULL
187
+ DEFAULT (now() at time zone 'utc')
188
+ );
189
+
190
+
191
+ ALTER TABLE public."signature" OWNER TO postgres;
192
+
193
+ CREATE UNIQUE INDEX ux_signature ON public."signature" USING btree (fact_id, public_key_id);
194
+
195
+ END IF;
196
+
197
+ --
198
+ -- User
199
+ --
200
+
201
+ IF (SELECT to_regclass('public.user') IS NULL) THEN
202
+
203
+ CREATE TABLE public."user" (
204
+ provider character varying(100),
205
+ user_identifier character varying(50),
206
+ private_key character varying(1800),
207
+ public_key character varying(500)
208
+ );
209
+
210
+
211
+ ALTER TABLE public."user" OWNER TO postgres;
212
+
213
+ CREATE UNIQUE INDEX ux_user ON public."user" USING btree (user_identifier, provider);
214
+ CREATE UNIQUE INDEX ux_user_public_key ON public."user" (public_key);
215
+
216
+ END IF;
217
+
218
+ END
219
+ $do$
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$APP_DATABASE" <<-EOSQL
5
+ GRANT SELECT,INSERT ON TABLE public.fact_type TO $APP_USERNAME;
6
+ GRANT SELECT, USAGE ON SEQUENCE fact_type_fact_type_id_seq TO $APP_USERNAME;
7
+ GRANT SELECT,INSERT ON TABLE public.role TO $APP_USERNAME;
8
+ GRANT SELECT, USAGE ON SEQUENCE role_role_id_seq TO $APP_USERNAME;
9
+ GRANT SELECT,INSERT ON TABLE public.fact TO $APP_USERNAME;
10
+ GRANT SELECT, USAGE ON SEQUENCE fact_fact_id_seq TO $APP_USERNAME;
11
+ GRANT SELECT,INSERT ON TABLE public.edge TO $APP_USERNAME;
12
+ GRANT SELECT,INSERT ON TABLE public.ancestor TO $APP_USERNAME;
13
+ GRANT SELECT,INSERT ON TABLE public.public_key TO $APP_USERNAME;
14
+ GRANT SELECT, USAGE ON SEQUENCE public_key_public_key_id_seq TO $APP_USERNAME;
15
+ GRANT SELECT,INSERT ON TABLE public.signature TO $APP_USERNAME;
16
+ GRANT SELECT,INSERT ON TABLE public.user TO $APP_USERNAME;
17
+ EOSQL
@@ -0,0 +1,5 @@
1
+ FROM postgres:14.2-alpine
2
+
3
+ COPY ./0-init-app-db.sh /docker-entrypoint-initdb.d/
4
+ COPY ./1-setup.sql /docker-entrypoint-initdb.d/
5
+ COPY ./2-grant.sh /docker-entrypoint-initdb.d/
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ docker build -t jinaga-postgres-fact-keystore ./postgres
5
+
6
+ mkdir -p ./jinaga-test/jinaga
7
+ cp -R ../dist ./jinaga-test/jinaga/dist
8
+ cp ../package.json ./jinaga-test/jinaga/package.json
9
+ docker build -t jinaga-test ./jinaga-test
10
+
11
+ cleanup() {
12
+ docker compose down -v
13
+ }
14
+
15
+ trap cleanup EXIT
16
+
17
+ docker compose up --exit-code-from jinaga-test --renew-anon-volumes
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ docker run -d --name jinaga-postgres -p5432:5432 -e POSTGRES_PASSWORD=superuser -e APP_USERNAME=dev -e APP_PASSWORD=devpw -e APP_DATABASE=integrationtest jinaga-postgres-fact-keystore
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ docker stop jinaga-postgres
3
+ docker rm jinaga-postgres
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ npm run build
3
+
4
+ cp ./dist/index.js ./integration-test/jinaga-test/jinaga.js
5
+ cp ./dist/index.js.map ./integration-test/jinaga-test/
6
+
7
+ npm --prefix ./integration-test/jinaga-test install
8
+ npm --prefix ./integration-test/jinaga-test run test:verbose
@@ -0,0 +1,56 @@
1
+ const { SpecificationParser } = require("../dist/specification/specification-parser");
2
+ const { dehydrateFact } = require("../dist/fact/hydrate");
3
+ const { PostgresStore } = require("../dist/postgres/postgres-store")
4
+ const fs = require("fs");
5
+
6
+ var user = {"publicKey":"-----BEGIN RSA PUBLIC KEY-----\nMIGJAoGBAIBsKomutukULWw2zoTW2ECMrM8VmD2xvfpl3R4qh1whzuXV+A4EfRKMb/UAjEfw\n5nBmWvcObGyYUgygKrlNeOhf3MnDj706rej6ln9cKGL++ZNsJgJsogaAtmkPihWVGi908fdP\nLQrWTF5be0b/ZP258Zs3CTpcRTpTvhzS5TC1AgMBAAE=\n-----END RSA PUBLIC KEY-----\n","type":"Jinaga.User"};
7
+
8
+ async function run() {
9
+ try {
10
+ var postgresStore = new PostgresStore("postgresql://dev:devpw@localhost:5432/improvingu");
11
+ try {
12
+ var input = fs.readFileSync(0, 'utf-8');
13
+ const parser = new SpecificationParser(input);
14
+ parser.skipWhitespace();
15
+ const userRecord = dehydrateFact(user)[0];
16
+ const knownFacts = {
17
+ me: {
18
+ fact: userRecord,
19
+ reference: {
20
+ type: userRecord.type,
21
+ hash: userRecord.hash
22
+ }
23
+ }
24
+ };
25
+ var declaration = parser.parseDeclaration(knownFacts);
26
+ var specification = parser.parseSpecification();
27
+
28
+ // Select starting facts that match the inputs
29
+ const start = specification.given.map(input => {
30
+ const fact = declaration[input.name];
31
+ if (!fact) {
32
+ throw new Error(`No fact named ${input.name} was declared`);
33
+ }
34
+ return fact.reference;
35
+ });
36
+
37
+ const args = process.argv.slice(2);
38
+ const produceResults = args.includes("--results");
39
+ if (produceResults) {
40
+ const results = await postgresStore.resultsFromSpecification(start, specification);
41
+ console.log(JSON.stringify(results, null, 2));
42
+ }
43
+ else {
44
+ const streams = await postgresStore.streamsFromSpecification(start, [], 3, specification);
45
+ console.log(JSON.stringify(streams, null, 2));
46
+ }
47
+ }
48
+ finally {
49
+ postgresStore.close();
50
+ }
51
+ } catch (e) {
52
+ console.error(e);
53
+ }
54
+ }
55
+
56
+ run();
package/jest.config.js ADDED
@@ -0,0 +1,12 @@
1
+ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ testMatch: [
6
+ '**/test/**/*Spec.ts',
7
+ ],
8
+ reporters:
9
+ [
10
+ './test/reporter.js',
11
+ ],
12
+ };
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "jinaga-server",
3
+ "version": "1.0.0",
4
+ "description": "Application-agnostic back end for web applications",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "clean": "rimraf dist/ && rimraf integration-test/jinaga-test/jinaga/ && rimraf integration-test/jinaga-test/node_modules/",
9
+ "build": "tsc",
10
+ "test": "jest",
11
+ "test:watch": "jest --watch",
12
+ "prepublishOnly": "npm run clean && npm run build && npm run test",
13
+ "integration": "npm run build && cd ./integration-test && ./run.sh",
14
+ "interactive": "nodemon -w docs/specification.txt -x \"cat docs/specification.txt | node interactive\"",
15
+ "interactive:results": "nodemon -w docs/specification.txt -x \"cat docs/specification.txt | node interactive --results\""
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/jinaga/jinaga-server.git"
20
+ },
21
+ "keywords": [
22
+ "messaging"
23
+ ],
24
+ "author": "Michael L Perry",
25
+ "license": "MIT",
26
+ "bugs": {
27
+ "url": "https://github.com/jinaga/jinaga-server/issues"
28
+ },
29
+ "homepage": "https://jinaga.com",
30
+ "devDependencies": {
31
+ "@types/express": "^4.17.13",
32
+ "@types/jest": "^27.5.1",
33
+ "@types/node-forge": "^0.10.10",
34
+ "@types/passport": "^1.0.7",
35
+ "@types/pg": "^8.6.1",
36
+ "jest": "^28.1.0",
37
+ "nodemon": "^2.0.15",
38
+ "rimraf": "^3.0.2",
39
+ "source-map-support": "^0.5.21",
40
+ "ts-jest": "^28.0.3",
41
+ "ts-node": "^10.8.0",
42
+ "typescript": "^4.7.2"
43
+ },
44
+ "dependencies": {
45
+ "express": "^4.18.1",
46
+ "jinaga": "^4.0.1",
47
+ "node-forge": "^1.3.1",
48
+ "passport": "^0.6.0",
49
+ "pg": "^8.7.1"
50
+ }
51
+ }
@@ -0,0 +1,46 @@
1
+ BEGIN TRANSACTION;
2
+
3
+
4
+ INSERT INTO public.fact (hash, fact_type_id, data)
5
+ VALUES ('hash1', 1, '{ "data": 1 }'::jsonb), ('hash2', 2, '{ "data": 2 }'::jsonb)
6
+ ON CONFLICT DO NOTHING;
7
+
8
+
9
+ INSERT INTO public.edge
10
+ (role_id, successor_fact_id, predecessor_fact_id)
11
+ SELECT v.role_id, successor.fact_id, predecessor.fact_id
12
+ FROM (VALUES ('hash2', 2, 'hash1', 1, 1)) AS v (successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id, role_id)
13
+ JOIN public.fact AS successor
14
+ ON successor.hash = v.successor_hash AND successor.fact_type_id = v.successor_fact_type_id
15
+ JOIN public.fact AS predecessor
16
+ ON predecessor.hash = v.predecessor_hash AND predecessor.fact_type_id = v.predecessor_fact_type_id
17
+ ON CONFLICT DO NOTHING;
18
+
19
+
20
+ WITH e AS (
21
+ SELECT successor.fact_id AS successor_fact_id, predecessor.fact_id AS predecessor_fact_id
22
+ FROM (VALUES ('hash2', 2, 'hash1', 1)) AS v (successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id)
23
+ JOIN public.fact AS successor
24
+ ON successor.hash = v.successor_hash AND successor.fact_type_id = v.successor_fact_type_id
25
+ JOIN public.fact AS predecessor
26
+ ON predecessor.hash = v.predecessor_hash AND predecessor.fact_type_id = v.predecessor_fact_type_id
27
+ )
28
+ INSERT INTO public.ancestor
29
+ (fact_id, ancestor_fact_id)
30
+ SELECT e.successor_fact_id, e.predecessor_fact_id
31
+ FROM e
32
+ UNION ALL
33
+ SELECT e.successor_fact_id, ancestor_fact_id
34
+ FROM e
35
+ JOIN public.ancestor
36
+ ON ancestor.fact_id = e.predecessor_fact_id
37
+ ON CONFLICT DO NOTHING;
38
+
39
+
40
+ SELECT fact.fact_id, v.fact_type_id, v.hash
41
+ FROM public.fact
42
+ JOIN (VALUES ('hash1', 1), ('hash2', 2)) AS v (hash, fact_type_id)
43
+ ON fact.hash = v.hash AND fact.fact_type_id = v.fact_type_id;
44
+
45
+
46
+ ROLLBACK TRANSACTION;
@@ -0,0 +1,55 @@
1
+ WITH new_fact AS (
2
+ SELECT hash, fact_type_id, data
3
+ FROM (VALUES ($1, $2::integer, $3::jsonb))
4
+ AS fv (hash, fact_type_id, data)
5
+ ),
6
+ new_edge AS (
7
+ SELECT successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id, role_id
8
+ FROM (VALUES ($4, $5::integer, $6, $7::integer, $8::integer))
9
+ AS ev (successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id, role_id)
10
+ ),
11
+ inserted_fact AS (
12
+ INSERT INTO public.fact (hash, fact_type_id, data)
13
+ SELECT hash, fact_type_id, data
14
+ FROM new_fact
15
+ RETURNING fact_id, fact_type_id, hash
16
+ ),
17
+ edge_id AS (
18
+ SELECT
19
+ new_edge.role_id,
20
+ successor.fact_id AS successor_fact_id,
21
+ predecessor.fact_id AS predecessor_fact_id
22
+ FROM new_edge
23
+ JOIN inserted_fact AS successor
24
+ ON successor.hash = new_edge.successor_hash
25
+ AND successor.fact_type_id = new_edge.successor_fact_type_id
26
+ JOIN (
27
+ SELECT fact_id, fact_type_id, hash
28
+ FROM inserted_fact
29
+ UNION ALL
30
+ SELECT fact_id, fact_type_id, hash
31
+ FROM public.fact
32
+ ) AS predecessor
33
+ ON predecessor.hash = new_edge.predecessor_hash
34
+ AND predecessor.fact_type_id = new_edge.predecessor_fact_type_id
35
+ ),
36
+ inserted_edge AS (
37
+ INSERT INTO public.edge
38
+ (role_id, successor_fact_id, predecessor_fact_id)
39
+ SELECT role_id, successor_fact_id, predecessor_fact_id
40
+ FROM edge_id ON CONFLICT DO NOTHING
41
+ ),
42
+ inserted_ancestor AS (
43
+ INSERT INTO public.ancestor
44
+ (fact_id, ancestor_fact_id)
45
+ SELECT edge_id.successor_fact_id, edge_id.predecessor_fact_id
46
+ FROM edge_id
47
+ UNION ALL
48
+ SELECT edge_id.successor_fact_id, ancestor_fact_id
49
+ FROM edge_id
50
+ JOIN public.ancestor
51
+ ON ancestor.fact_id = edge_id.predecessor_fact_id
52
+ ON CONFLICT DO NOTHING
53
+ )
54
+ SELECT fact_id, fact_type_id, hash
55
+ FROM inserted_fact;
@@ -0,0 +1,27 @@
1
+ BEGIN TRANSACTION;
2
+
3
+ INSERT INTO public.fact (hash, fact_type_id, data)
4
+ (SELECT hash, fact_type_id, data
5
+ FROM (VALUES ('hash1', 1, '{ "data": 1 }'::jsonb), ('hash2', 2, '{ "data": 2 }'::jsonb)) AS v (hash, fact_type_id, data))
6
+ RETURNING fact_id, fact_type_id, hash;
7
+
8
+
9
+ INSERT INTO public.edge
10
+ (role_id, successor_fact_id, predecessor_fact_id)
11
+ (VALUES (1, 2, 3), (4, 5, 6))
12
+ ON CONFLICT DO NOTHING;
13
+
14
+
15
+ INSERT INTO public.ancestor
16
+ (fact_id, ancestor_fact_id)
17
+ SELECT 3, predecessor_fact_id
18
+ FROM (VALUES (1), (2)) AS v (predecessor_fact_id)
19
+ UNION ALL
20
+ SELECT 1, ancestor_fact_id
21
+ FROM (VALUES (1), (2)) AS v (predecessor_fact_id)
22
+ JOIN public.ancestor
23
+ ON ancestor.fact_id = predecessor_fact_id
24
+ ON CONFLICT DO NOTHING;
25
+
26
+
27
+ ROLLBACK TRANSACTION;
package/setup.sh ADDED
@@ -0,0 +1,34 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ JINAGA_ADMIN_CONNECTION_STRING=postgresql://$JINAGA_POSTGRES_ADMIN_USER:$JINAGA_POSTGRES_ADMIN_PASSWORD@$JINAGA_POSTGRES_HOST:$JINAGA_POSTGRES_PORT/$JINAGA_POSTGRES_APP_DATABASE
5
+
6
+ psql -v ON_ERROR_STOP=1 $JINAGA_ADMIN_CONNECTION_STRING <<-EOSQL
7
+ CREATE USER $JINAGA_POSTGRES_APP_USER WITH
8
+ LOGIN
9
+ ENCRYPTED PASSWORD '$JINAGA_POSTGRES_APP_PASSWORD'
10
+ NOSUPERUSER
11
+ INHERIT
12
+ NOCREATEDB
13
+ NOCREATEROLE
14
+ NOREPLICATION
15
+ VALID UNTIL 'infinity';
16
+ CREATE DATABASE $JINAGA_POSTGRES_APP_DATABASE;
17
+ EOSQL
18
+
19
+ cat ./setup.sql | psql -v ON_ERROR_STOP=1 $JINAGA_ADMIN_CONNECTION_STRING
20
+
21
+ psql -v ON_ERROR_STOP=1 $JINAGA_ADMIN_CONNECTION_STRING <<-EOSQL
22
+ GRANT SELECT,INSERT ON TABLE public.fact_type TO $JINAGA_POSTGRES_APP_USER;
23
+ GRANT SELECT, USAGE ON SEQUENCE fact_type_fact_type_id_seq TO $JINAGA_POSTGRES_APP_USER;
24
+ GRANT SELECT,INSERT ON TABLE public.role TO $JINAGA_POSTGRES_APP_USER;
25
+ GRANT SELECT, USAGE ON SEQUENCE role_role_id_seq TO $JINAGA_POSTGRES_APP_USER;
26
+ GRANT SELECT,INSERT ON TABLE public.fact TO $JINAGA_POSTGRES_APP_USER;
27
+ GRANT SELECT, USAGE ON SEQUENCE fact_fact_id_seq TO $JINAGA_POSTGRES_APP_USER;
28
+ GRANT SELECT,INSERT ON TABLE public.edge TO $JINAGA_POSTGRES_APP_USER;
29
+ GRANT SELECT,INSERT ON TABLE public.ancestor TO $JINAGA_POSTGRES_APP_USER;
30
+ GRANT SELECT,INSERT ON TABLE public.public_key TO $JINAGA_POSTGRES_APP_USER;
31
+ GRANT SELECT, USAGE ON SEQUENCE public_key_public_key_id_seq TO $JINAGA_POSTGRES_APP_USER;
32
+ GRANT SELECT,INSERT ON TABLE public.signature TO $JINAGA_POSTGRES_APP_USER;
33
+ GRANT SELECT,INSERT ON TABLE public.user TO $JINAGA_POSTGRES_APP_USER;
34
+ EOSQL