@haathie/pgmb 0.2.7 → 0.2.9

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/README.md CHANGED
@@ -513,17 +513,13 @@ PGMB relies on 2 functions that need to be run periodically & only once globally
513
513
  It's okay if this runs simultaneously in multiple processes, but that can create unnecessary contention on the `unread_events` table, which can bubble up to other tables.
514
514
  2. `maintain_events_table()` -- removes old partitions & creates new partitions for the events table. It's also okay if this runs simultaneously in multiple processes, as it has advisory locks to ensure only a single process is maintaining the events table at any time, but running this too frequently can cause unnecessary overhead.
515
515
 
516
- If you're only running a single instance of your service, you can simply run these functions in the same process as your PGMB client (default behaviour).
517
- However, for larger deployments with multiple instances of your service, it's recommended to run these functions in a separate process to avoid contention, and disable polling & table maintainence:
518
- ``` ts
519
- const pgmb = new PgmbClient({
520
- pollEventsIntervalMs: 0,
521
- tableMaintainanceMs: 0,
522
- ...otherOpts
523
- })
524
- ```
516
+ If you have the `pg_cron` extension installed, `pgmb` will automatically setup these functions to run periodically via `pg_cron` on initialization. The default intervals are:
517
+ - `poll_for_events()` -- every `1 second`
518
+ - `maintain_events_table()` -- on every `30th minute`
519
+
520
+ These can be easily configured by changing the values in the `config` table in the `pgmb` schema. Changes automatically get applied to the underlying cron jobs via triggers.
525
521
 
526
- Something like [pg_cron](https://github.com/citusdata/pg_cron) is a good option.
522
+ If you do not have `pg_cron` installed, PGMB will run these functions in the same process as the client itself, at the above intervals. This is okay for development & small deployments.
527
523
 
528
524
  ## General Notes
529
525
 
package/lib/client.js CHANGED
@@ -63,24 +63,31 @@ class PgmbClient extends batcher_ts_1.PGMBEventBatcher {
63
63
  if ('connect' in this.client) {
64
64
  this.client.on('remove', this.#onPoolClientRemoved);
65
65
  }
66
- // maintain event table
67
- await queries_ts_1.maintainEventsTable.run(undefined, this.client);
68
- this.logger.debug('maintained events table');
66
+ const [pgCronRslt] = await queries_ts_1.getConfigValue
67
+ .run({ key: 'use_pg_cron' }, this.client);
68
+ const isPgCronEnabled = pgCronRslt?.value === 'true';
69
+ if (!isPgCronEnabled) {
70
+ // maintain event table
71
+ await queries_ts_1.maintainEventsTable.run(undefined, this.client);
72
+ this.logger.debug('maintained events table');
73
+ if (this.pollEventsIntervalMs) {
74
+ this.#pollTask = this.#startLoop(queries_ts_1.pollForEvents.run.bind(queries_ts_1.pollForEvents, undefined, this.client), this.pollEventsIntervalMs);
75
+ }
76
+ if (this.tableMaintenanceMs) {
77
+ this.#tableMaintainTask = this.#startLoop(queries_ts_1.maintainEventsTable.run
78
+ .bind(queries_ts_1.maintainEventsTable, undefined, this.client), this.tableMaintenanceMs);
79
+ }
80
+ }
69
81
  await queries_ts_1.assertGroup.run({ id: this.groupId }, this.client);
70
82
  this.logger.debug({ groupId: this.groupId }, 'asserted group exists');
71
83
  // clean up expired subscriptions on start
72
84
  const [{ deleted }] = await queries_ts_1.removeExpiredSubscriptions.run({ groupId: this.groupId, activeIds: [] }, this.client);
73
85
  this.logger.debug({ deleted }, 'removed expired subscriptions');
74
86
  this.#readTask = this.#startLoop(this.readChanges.bind(this), this.readEventsIntervalMs);
75
- if (this.pollEventsIntervalMs) {
76
- this.#pollTask = this.#startLoop(queries_ts_1.pollForEvents.run.bind(queries_ts_1.pollForEvents, undefined, this.client), this.pollEventsIntervalMs);
77
- }
78
87
  if (this.subscriptionMaintenanceMs) {
79
88
  this.#subMaintainTask = this.#startLoop(this.#maintainSubscriptions, this.subscriptionMaintenanceMs);
80
89
  }
81
- if (this.tableMaintenanceMs) {
82
- this.#tableMaintainTask = this.#startLoop(queries_ts_1.maintainEventsTable.run.bind(queries_ts_1.maintainEventsTable, undefined, this.client), this.tableMaintenanceMs);
83
- }
90
+ this.logger.info({ isPgCronEnabled }, 'pgmb client initialised');
84
91
  }
85
92
  async end() {
86
93
  await super.end();
package/lib/queries.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.maintainEventsTable = exports.removeExpiredSubscriptions = exports.findEvents = exports.scheduleEventRetry = exports.writeScheduledEvents = exports.writeEvents = exports.releaseGroupLock = exports.setGroupCursor = exports.replayEvents = exports.readNextEventsText = exports.readNextEvents = exports.pollForEvents = exports.markSubscriptionsActive = exports.deleteSubscriptions = exports.assertSubscription = exports.assertGroup = void 0;
3
+ exports.maintainEventsTable = exports.updateConfigValue = exports.getConfigValue = exports.removeExpiredSubscriptions = exports.findEvents = exports.scheduleEventRetry = exports.writeScheduledEvents = exports.writeEvents = exports.releaseGroupLock = exports.setGroupCursor = exports.replayEvents = exports.readNextEventsText = exports.readNextEvents = exports.pollForEvents = exports.markSubscriptionsActive = exports.deleteSubscriptions = exports.assertSubscription = exports.assertGroup = void 0;
4
4
  /** Types generated for queries found in "sql/queries.sql" */
5
5
  const runtime_1 = require("@pgtyped/runtime");
6
6
  const assertGroupIR = { "usedParamSet": { "id": true }, "params": [{ "name": "id", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 50, "b": 53 }] }], "statement": "INSERT INTO pgmb.subscription_groups (id)\nVALUES (:id!)\nON CONFLICT DO NOTHING" };
@@ -225,6 +225,25 @@ const removeExpiredSubscriptionsIR = { "usedParamSet": { "groupId": true, "activ
225
225
  * ```
226
226
  */
227
227
  exports.removeExpiredSubscriptions = new runtime_1.PreparedQuery(removeExpiredSubscriptionsIR);
228
+ const getConfigValueIR = { "usedParamSet": { "key": true }, "params": [{ "name": "key", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 29, "b": 33 }] }], "statement": "SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS \"value\"" };
229
+ /**
230
+ * Query generated from SQL:
231
+ * ```
232
+ * SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value"
233
+ * ```
234
+ */
235
+ exports.getConfigValue = new runtime_1.PreparedQuery(getConfigValueIR);
236
+ const updateConfigValueIR = { "usedParamSet": { "value": true, "key": true }, "params": [{ "name": "value", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 31, "b": 37 }] }, { "name": "key", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 56, "b": 60 }] }], "statement": "UPDATE pgmb.config\nSET value = :value!::TEXT\nWHERE id = :key!::pgmb.config_type\nRETURNING 1 AS \"updated!\"" };
237
+ /**
238
+ * Query generated from SQL:
239
+ * ```
240
+ * UPDATE pgmb.config
241
+ * SET value = :value!::TEXT
242
+ * WHERE id = :key!::pgmb.config_type
243
+ * RETURNING 1 AS "updated!"
244
+ * ```
245
+ */
246
+ exports.updateConfigValue = new runtime_1.PreparedQuery(updateConfigValueIR);
228
247
  const maintainEventsTableIR = { "usedParamSet": {}, "params": [], "statement": "SELECT pgmb.maintain_events_table()" };
229
248
  /**
230
249
  * Query generated from SQL:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haathie/pgmb",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "PG message broker, with a type-safe typescript client with built-in webhook & SSE support.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -21,7 +21,7 @@
21
21
  "lint": "eslint ./ --ext .js,.ts,.jsx,.tsx",
22
22
  "lint:fix": "eslint ./ --fix --ext .js,.ts,.jsx,.tsx",
23
23
  "benchmark": "TZ=utc node --env-file ./.env.test src/benchmark/run.ts",
24
- "gen:pgtyped": "pgtyped --config ./pgtyped.config.json"
24
+ "pg:typegen": "pgtyped --config ./pgtyped.config.json"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@adiwajshing/eslint-config": "git+https://github.com/adiwajshing/eslint-config",
@@ -0,0 +1,80 @@
1
+ SET search_path TO pgmb;
2
+
3
+ ALTER TYPE config_type ADD VALUE 'use_pg_cron';
4
+ ALTER TYPE config_type ADD VALUE 'pg_cron_poll_for_events_cron';
5
+ ALTER TYPE config_type ADD VALUE 'pg_cron_partition_maintenance_cron';
6
+
7
+ INSERT INTO config(id, value) VALUES
8
+ ('pg_cron_poll_for_events_cron', '1 second'),
9
+ -- every 30 minutes
10
+ ('pg_cron_partition_maintenance_cron', '*/30 * * * *');
11
+
12
+ CREATE OR REPLACE FUNCTION manage_cron_jobs_trigger_fn()
13
+ RETURNS TRIGGER AS $$
14
+ DECLARE
15
+ poll_job_name CONSTANT TEXT := 'pgmb_poll';
16
+ maintain_job_name CONSTANT TEXT := 'pgmb_maintain_table_partitions';
17
+ BEGIN
18
+ IF get_config_value('use_pg_cron') = 'true' THEN
19
+ -- Schedule/update event polling job
20
+ PERFORM cron.schedule(
21
+ poll_job_name,
22
+ get_config_value('pg_cron_poll_for_events_cron'),
23
+ $CMD$
24
+ -- ensure we don't accidentally run for too long
25
+ SET SESSION statement_timeout = '10s';
26
+ SELECT pgmb.poll_for_events();
27
+ $CMD$
28
+ );
29
+ RAISE LOG 'Scheduled pgmb polling job: %', poll_job_name;
30
+
31
+ -- Schedule/update partition maintenance job
32
+ PERFORM cron.schedule(
33
+ 'pgmb_maintain_table_partitions',
34
+ get_config_value('pg_cron_partition_maintenance_cron'),
35
+ $CMD$ SELECT pgmb.maintain_events_table(); $CMD$
36
+ );
37
+
38
+ RAISE LOG 'Scheduled pgmb partition maintenance job: %',
39
+ maintain_job_name;
40
+ ELSIF (SELECT 1 FROM pg_namespace WHERE nspname = 'cron') THEN
41
+ RAISE LOG 'Unscheduling pgmb cron jobs.';
42
+ -- Unschedule jobs. cron.unschedule does not fail if job does not exist.
43
+ PERFORM cron.unschedule(poll_job_name);
44
+ PERFORM cron.unschedule(maintain_job_name);
45
+ END IF;
46
+
47
+ RETURN NULL;
48
+ END;
49
+ $$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE SECURITY DEFINER
50
+ SET search_path TO pgmb;
51
+
52
+ CREATE TRIGGER manage_cron_jobs_trigger
53
+ AFTER INSERT OR UPDATE OF value ON config
54
+ FOR EACH ROW
55
+ WHEN (
56
+ NEW.id IN (
57
+ 'use_pg_cron',
58
+ 'pg_cron_poll_for_events_cron',
59
+ 'pg_cron_partition_maintenance_cron'
60
+ )
61
+ )
62
+ EXECUTE FUNCTION manage_cron_jobs_trigger_fn();
63
+
64
+ DO $$
65
+ BEGIN
66
+ IF (
67
+ SELECT EXISTS (
68
+ SELECT 1
69
+ FROM pg_available_extensions
70
+ WHERE name = 'pg_cron'
71
+ )
72
+ ) THEN
73
+ CREATE EXTENSION IF NOT EXISTS pg_cron;
74
+ INSERT INTO config(id, value) VALUES ('use_pg_cron', 'true');
75
+ ELSE
76
+ RAISE LOG 'pg_cron extension not available. Skipping pg_cron setup.';
77
+ INSERT INTO config(id, value) VALUES ('use_pg_cron', 'false');
78
+ END IF;
79
+ END
80
+ $$;
package/sql/pgmb.sql CHANGED
@@ -22,7 +22,10 @@ CREATE TYPE config_type AS ENUM(
22
22
  -- how far into the future to create partitions
23
23
  'future_intervals_to_create',
24
24
  'partition_interval',
25
- 'poll_chunk_size'
25
+ 'poll_chunk_size',
26
+ 'use_pg_cron',
27
+ 'pg_cron_poll_for_events_cron',
28
+ 'pg_cron_partition_maintenance_cron'
26
29
  );
27
30
 
28
31
  CREATE TABLE IF NOT EXISTS config(
@@ -37,13 +40,15 @@ CREATE OR REPLACE FUNCTION get_config_value(
37
40
  SELECT value FROM config WHERE id = config_id
38
41
  $$ LANGUAGE sql STRICT STABLE PARALLEL SAFE SET SEARCH_PATH TO pgmb;
39
42
 
40
- INSERT INTO config(id, value)
41
- VALUES
42
- ('plugin_version', '0.2.0'),
43
- ('partition_retention_period', '60 minutes'),
44
- ('future_intervals_to_create', '120 minutes'),
45
- ('partition_interval', '30 minutes'),
46
- ('poll_chunk_size', '10000');
43
+ INSERT INTO config(id, value) VALUES
44
+ ('plugin_version', '0.2.0'),
45
+ ('partition_retention_period', '60 minutes'),
46
+ ('future_intervals_to_create', '120 minutes'),
47
+ ('partition_interval', '30 minutes'),
48
+ ('poll_chunk_size', '10000'),
49
+ ('pg_cron_poll_for_events_cron', '1 second'),
50
+ -- every 30 minutes
51
+ ('pg_cron_partition_maintenance_cron', '*/30 * * * *');
47
52
 
48
53
  -- we'll create the events table next & its functions ---------------
49
54
 
@@ -365,33 +370,11 @@ CREATE INDEX ON subscriptions(
365
370
  add_interval_imm(last_active_at, expiry_interval)
366
371
  ) WHERE expiry_interval IS NOT NULL;
367
372
 
368
- DO $$
369
- DECLARE
370
- has_btree_gin BOOLEAN;
371
- BEGIN
372
- has_btree_gin := (
373
- SELECT EXISTS (
374
- SELECT 1
375
- FROM pg_available_extensions
376
- WHERE name = 'btree_gin'
377
- )
378
- );
379
- -- create btree_gin extension if not exists, if the extension
380
- -- is not available, we create a simpler regular GIN index instead.
381
- IF has_btree_gin THEN
382
- CREATE EXTENSION IF NOT EXISTS btree_gin;
383
- -- fastupdate=false, slows down subscription creation, but ensures the costlier
384
- -- "poll_for_events" function is executed faster.
385
- CREATE INDEX "sub_gin" ON subscriptions USING GIN(conditions_sql, params)
386
- WITH (fastupdate = false);
387
- ELSE
388
- RAISE NOTICE 'btree_gin extension is not available, using
389
- regular GIN index for subscriptions.params';
390
- CREATE INDEX "sub_gin" ON subscriptions USING GIN(params)
391
- WITH (fastupdate = false);
392
- END IF;
393
- END
394
- $$;
373
+ -- fastupdate=false, slows down subscription creation, but ensures the costlier
374
+ -- "poll_for_events" function is executed faster.
375
+ CREATE EXTENSION IF NOT EXISTS btree_gin;
376
+ CREATE INDEX "sub_gin" ON subscriptions
377
+ USING GIN(conditions_sql, params) WITH (fastupdate = false);
395
378
 
396
379
  -- materialized view to hold distinct conditions_sql statements.
397
380
  -- We utilise changes in this view to determine when to prepare the
@@ -863,6 +846,78 @@ SET search_path TO pgmb;
863
846
  -- create the initial partitions
864
847
  SELECT maintain_events_table();
865
848
 
849
+ -- setup pg_cron if it's available ----------------
850
+
851
+ CREATE OR REPLACE FUNCTION manage_cron_jobs_trigger_fn()
852
+ RETURNS TRIGGER AS $$
853
+ DECLARE
854
+ poll_job_name CONSTANT TEXT := 'pgmb_poll';
855
+ maintain_job_name CONSTANT TEXT := 'pgmb_maintain_table_partitions';
856
+ BEGIN
857
+ IF get_config_value('use_pg_cron') = 'true' THEN
858
+ -- Schedule/update event polling job
859
+ PERFORM cron.schedule(
860
+ poll_job_name,
861
+ get_config_value('pg_cron_poll_for_events_cron'),
862
+ $CMD$
863
+ -- ensure we don't accidentally run for too long
864
+ SET SESSION statement_timeout = '10s';
865
+ SELECT pgmb.poll_for_events();
866
+ $CMD$
867
+ );
868
+ RAISE LOG 'Scheduled pgmb polling job: %', poll_job_name;
869
+
870
+ -- Schedule/update partition maintenance job
871
+ PERFORM cron.schedule(
872
+ 'pgmb_maintain_table_partitions',
873
+ get_config_value('pg_cron_partition_maintenance_cron'),
874
+ $CMD$ SELECT pgmb.maintain_events_table(); $CMD$
875
+ );
876
+
877
+ RAISE LOG 'Scheduled pgmb partition maintenance job: %',
878
+ maintain_job_name;
879
+ ELSIF (SELECT 1 FROM pg_namespace WHERE nspname = 'cron') THEN
880
+ RAISE LOG 'Unscheduling pgmb cron jobs.';
881
+ -- Unschedule jobs. cron.unschedule does not fail if job does not exist.
882
+ PERFORM cron.unschedule(poll_job_name);
883
+ PERFORM cron.unschedule(maintain_job_name);
884
+ END IF;
885
+
886
+ RETURN NULL;
887
+ END;
888
+ $$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE SECURITY DEFINER
889
+ SET search_path TO pgmb;
890
+
891
+ CREATE TRIGGER manage_cron_jobs_trigger
892
+ AFTER INSERT OR UPDATE OF value ON config
893
+ FOR EACH ROW
894
+ WHEN (
895
+ NEW.id IN (
896
+ 'use_pg_cron',
897
+ 'pg_cron_poll_for_events_cron',
898
+ 'pg_cron_partition_maintenance_cron'
899
+ )
900
+ )
901
+ EXECUTE FUNCTION manage_cron_jobs_trigger_fn();
902
+
903
+ DO $$
904
+ BEGIN
905
+ IF (
906
+ SELECT EXISTS (
907
+ SELECT 1
908
+ FROM pg_available_extensions
909
+ WHERE name = 'pg_cron'
910
+ )
911
+ ) THEN
912
+ CREATE EXTENSION IF NOT EXISTS pg_cron;
913
+ INSERT INTO config(id, value) VALUES ('use_pg_cron', 'true');
914
+ ELSE
915
+ RAISE LOG 'pg_cron extension not available. Skipping pg_cron setup.';
916
+ INSERT INTO config(id, value) VALUES ('use_pg_cron', 'false');
917
+ END IF;
918
+ END
919
+ $$;
920
+
866
921
  -- triggers to add events for specific tables ---------------------------
867
922
 
868
923
  -- Function to create a topic string for subscriptions.
package/sql/queries.sql CHANGED
@@ -150,5 +150,14 @@ WITH deleted AS (
150
150
  )
151
151
  SELECT COUNT(*) AS "deleted!" FROM deleted;
152
152
 
153
+ /* @name getConfigValue */
154
+ SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value";
155
+
156
+ /* @name updateConfigValue */
157
+ UPDATE pgmb.config
158
+ SET value = :value!::TEXT
159
+ WHERE id = :key!::pgmb.config_type
160
+ RETURNING 1 AS "updated!";
161
+
153
162
  /* @name maintainEventsTable */
154
163
  SELECT pgmb.maintain_events_table();
package/src/client.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  assertGroup,
8
8
  assertSubscription,
9
9
  deleteSubscriptions,
10
+ getConfigValue,
10
11
  maintainEventsTable,
11
12
  markSubscriptionsActive,
12
13
  pollForEvents,
@@ -151,9 +152,29 @@ export class PgmbClient<
151
152
  this.client.on('remove', this.#onPoolClientRemoved)
152
153
  }
153
154
 
154
- // maintain event table
155
- await maintainEventsTable.run(undefined, this.client)
156
- this.logger.debug('maintained events table')
155
+ const [pgCronRslt] = await getConfigValue
156
+ .run({ key: 'use_pg_cron' }, this.client)
157
+ const isPgCronEnabled = pgCronRslt?.value === 'true'
158
+ if(!isPgCronEnabled) {
159
+ // maintain event table
160
+ await maintainEventsTable.run(undefined, this.client)
161
+ this.logger.debug('maintained events table')
162
+
163
+ if(this.pollEventsIntervalMs) {
164
+ this.#pollTask = this.#startLoop(
165
+ pollForEvents.run.bind(pollForEvents, undefined, this.client),
166
+ this.pollEventsIntervalMs,
167
+ )
168
+ }
169
+
170
+ if(this.tableMaintenanceMs) {
171
+ this.#tableMaintainTask = this.#startLoop(
172
+ maintainEventsTable.run
173
+ .bind(maintainEventsTable, undefined, this.client),
174
+ this.tableMaintenanceMs,
175
+ )
176
+ }
177
+ }
157
178
 
158
179
  await assertGroup.run({ id: this.groupId }, this.client)
159
180
  this.logger.debug({ groupId: this.groupId }, 'asserted group exists')
@@ -169,13 +190,6 @@ export class PgmbClient<
169
190
  this.readEventsIntervalMs,
170
191
  )
171
192
 
172
- if(this.pollEventsIntervalMs) {
173
- this.#pollTask = this.#startLoop(
174
- pollForEvents.run.bind(pollForEvents, undefined, this.client),
175
- this.pollEventsIntervalMs,
176
- )
177
- }
178
-
179
193
  if(this.subscriptionMaintenanceMs) {
180
194
  this.#subMaintainTask = this.#startLoop(
181
195
  this.#maintainSubscriptions,
@@ -183,16 +197,7 @@ export class PgmbClient<
183
197
  )
184
198
  }
185
199
 
186
- if(this.tableMaintenanceMs) {
187
- this.#tableMaintainTask = this.#startLoop(
188
- maintainEventsTable.run.bind(
189
- maintainEventsTable,
190
- undefined,
191
- this.client,
192
- ),
193
- this.tableMaintenanceMs,
194
- )
195
- }
200
+ this.logger.info({ isPgCronEnabled }, 'pgmb client initialised')
196
201
  }
197
202
 
198
203
  async end() {
package/src/queries.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /** Types generated for queries found in "sql/queries.sql" */
2
2
  import { PreparedQuery } from '@pgtyped/runtime';
3
3
 
4
+ export type config_type = 'future_intervals_to_create' | 'partition_interval' | 'partition_retention_period' | 'pg_cron_partition_maintenance_cron' | 'pg_cron_poll_for_events_cron' | 'plugin_version' | 'poll_chunk_size' | 'use_pg_cron';
5
+
4
6
  export type DateOrString = Date | string;
5
7
 
6
8
  export type DateOrStringArray = (DateOrString)[];
@@ -543,6 +545,64 @@ const removeExpiredSubscriptionsIR: any = {"usedParamSet":{"groupId":true,"activ
543
545
  export const removeExpiredSubscriptions = new PreparedQuery<IRemoveExpiredSubscriptionsParams,IRemoveExpiredSubscriptionsResult>(removeExpiredSubscriptionsIR);
544
546
 
545
547
 
548
+ /** 'GetConfigValue' parameters type */
549
+ export interface IGetConfigValueParams {
550
+ key: config_type;
551
+ }
552
+
553
+ /** 'GetConfigValue' return type */
554
+ export interface IGetConfigValueResult {
555
+ value: string | null;
556
+ }
557
+
558
+ /** 'GetConfigValue' query type */
559
+ export interface IGetConfigValueQuery {
560
+ params: IGetConfigValueParams;
561
+ result: IGetConfigValueResult;
562
+ }
563
+
564
+ const getConfigValueIR: any = {"usedParamSet":{"key":true},"params":[{"name":"key","required":true,"transform":{"type":"scalar"},"locs":[{"a":29,"b":33}]}],"statement":"SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS \"value\""};
565
+
566
+ /**
567
+ * Query generated from SQL:
568
+ * ```
569
+ * SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value"
570
+ * ```
571
+ */
572
+ export const getConfigValue = new PreparedQuery<IGetConfigValueParams,IGetConfigValueResult>(getConfigValueIR);
573
+
574
+
575
+ /** 'UpdateConfigValue' parameters type */
576
+ export interface IUpdateConfigValueParams {
577
+ key: config_type;
578
+ value: string;
579
+ }
580
+
581
+ /** 'UpdateConfigValue' return type */
582
+ export interface IUpdateConfigValueResult {
583
+ updated: number;
584
+ }
585
+
586
+ /** 'UpdateConfigValue' query type */
587
+ export interface IUpdateConfigValueQuery {
588
+ params: IUpdateConfigValueParams;
589
+ result: IUpdateConfigValueResult;
590
+ }
591
+
592
+ const updateConfigValueIR: any = {"usedParamSet":{"value":true,"key":true},"params":[{"name":"value","required":true,"transform":{"type":"scalar"},"locs":[{"a":31,"b":37}]},{"name":"key","required":true,"transform":{"type":"scalar"},"locs":[{"a":56,"b":60}]}],"statement":"UPDATE pgmb.config\nSET value = :value!::TEXT\nWHERE id = :key!::pgmb.config_type\nRETURNING 1 AS \"updated!\""};
593
+
594
+ /**
595
+ * Query generated from SQL:
596
+ * ```
597
+ * UPDATE pgmb.config
598
+ * SET value = :value!::TEXT
599
+ * WHERE id = :key!::pgmb.config_type
600
+ * RETURNING 1 AS "updated!"
601
+ * ```
602
+ */
603
+ export const updateConfigValue = new PreparedQuery<IUpdateConfigValueParams,IUpdateConfigValueResult>(updateConfigValueIR);
604
+
605
+
546
606
  /** 'MaintainEventsTable' parameters type */
547
607
  export type IMaintainEventsTableParams = void;
548
608