@shushed/helpers 0.0.27 → 0.0.29

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/dist/index.d.ts CHANGED
@@ -2,9 +2,11 @@ import { JSONSchemaType } from 'ajv';
2
2
  import { DeepRedact } from '@hackylabs/deep-redact';
3
3
  import { Firestore, DocumentReference } from '@google-cloud/firestore';
4
4
  import { PubSub, Topic, Subscription } from '@google-cloud/pubsub';
5
+ import { Context } from 'co-body';
5
6
  import * as _google_cloud_scheduler_build_protos_protos from '@google-cloud/scheduler/build/protos/protos';
6
7
  import { CloudSchedulerClient } from '@google-cloud/scheduler';
7
8
  import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
9
+ import { BigQuery } from '@google-cloud/bigquery';
8
10
 
9
11
  declare const schema$l: {
10
12
  readonly $schema: "http://json-schema.org/draft-07/schema#";
@@ -28720,6 +28722,8 @@ declare const isCronMessage: (headers: Record<string, string>) => boolean;
28720
28722
  declare const validateGoogleAuth: (opts: Opts & {
28721
28723
  serviceAccount?: string | null;
28722
28724
  }, headers: Record<string, string>, firestore: Firestore) => Promise<void>;
28725
+ declare const parseDateOrDefault: (date: string | null | Date, defaultValue?: Date | null) => Date | null;
28726
+ declare function getEventTime(x: any, defaultValue: Date | null): Date | null;
28723
28727
 
28724
28728
  type Level = 'env' | 'workflow' | 'trigger';
28725
28729
  declare class EnvEngine extends Runtime {
@@ -28737,18 +28741,48 @@ declare class EnvEngine extends Runtime {
28737
28741
  get(key: string, level?: Level, decryptWithValue?: string): Promise<string>;
28738
28742
  }
28739
28743
 
28744
+ type Message = {
28745
+ buildshipId: string;
28746
+ body: string;
28747
+ sourceSystem: string;
28748
+ targetSystem: string;
28749
+ processStartedAt: Date | null;
28750
+ recordModifiedAt: Date | null;
28751
+ originalPublishTime: Date | null;
28752
+ publishTime: Date | null;
28753
+ };
28754
+ type LastModifiedKeys = 'last_modified_date_time' | 'last_modified_date' | 'last_modified_datetime' | 'record_modified_at' | 'lastModifiedDateTime' | 'lastModifiedAt' | 'last_modified_at' | 'SystemModifiedAt' | 'system_modified_at' | 'lastUpdatedAt' | 'modified_at' | 'last_updated_at' | 'modifiedAt';
28755
+ type AtLeastOne<T, Keys extends keyof T = keyof T> = Partial<T> & {
28756
+ [K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, never>>;
28757
+ }[Keys];
28758
+ type MessageBody = {
28759
+ [K in LastModifiedKeys]?: Date | string;
28760
+ } & {
28761
+ [key: string]: any;
28762
+ };
28740
28763
  declare class PubSubHelper extends Runtime {
28741
28764
  private pubSub;
28742
28765
  constructor(opts: Opts, pubSub: PubSub);
28766
+ static decodeMessageFromRequest(req: Context): Promise<Message>;
28767
+ publish(options: Partial<Message> & {
28768
+ topicName: string;
28769
+ sourceSystem: string;
28770
+ }, payload: AtLeastOne<MessageBody, LastModifiedKeys>[], orgMessage?: Message): Promise<string[]>;
28771
+ publish(options: Partial<Message> & {
28772
+ topicName: string;
28773
+ sourceSystem: string;
28774
+ }, payload: AtLeastOne<MessageBody, LastModifiedKeys>, orgMessage?: Message): Promise<string[]>;
28743
28775
  createOrUpdate(opts: {
28744
28776
  topicName: string;
28745
28777
  dlq: boolean;
28778
+ bigQueryTableId?: string | null;
28746
28779
  retryLimit: number;
28747
28780
  retryDelay: number;
28748
28781
  ackDeadline: number;
28749
28782
  }): Promise<{
28750
28783
  topic: Topic;
28751
28784
  dlqTopic: Topic | null;
28785
+ bqSubscription: Subscription | null;
28752
28786
  dlqSubscription: Subscription | null;
28753
28787
  subscription: Subscription;
28754
28788
  }>;
@@ -28799,7 +28833,7 @@ declare class SchedulerHelper extends Runtime {
28799
28833
  timezone: string;
28800
28834
  }): Promise<{
28801
28835
  status: _google_cloud_scheduler_build_protos_protos.google.rpc.IStatus | null | undefined;
28802
- state: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.Job.State | "STATE_UNSPECIFIED" | "ENABLED" | "PAUSED" | "DISABLED" | "UPDATE_FAILED" | null | undefined;
28836
+ state: "STATE_UNSPECIFIED" | _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.Job.State | "ENABLED" | "PAUSED" | "DISABLED" | "UPDATE_FAILED" | null | undefined;
28803
28837
  name: string | null | undefined;
28804
28838
  httpTarget: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.IHttpTarget | null | undefined;
28805
28839
  pubsubTarget: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.IPubsubTarget | null | undefined;
@@ -28809,7 +28843,7 @@ declare class SchedulerHelper extends Runtime {
28809
28843
  timezone: string;
28810
28844
  }): Promise<{
28811
28845
  status: _google_cloud_scheduler_build_protos_protos.google.rpc.IStatus | null | undefined;
28812
- state: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.Job.State | "STATE_UNSPECIFIED" | "ENABLED" | "PAUSED" | "DISABLED" | "UPDATE_FAILED" | null | undefined;
28846
+ state: "STATE_UNSPECIFIED" | _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.Job.State | "ENABLED" | "PAUSED" | "DISABLED" | "UPDATE_FAILED" | null | undefined;
28813
28847
  name: string | null | undefined;
28814
28848
  httpTarget: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.IHttpTarget | null | undefined;
28815
28849
  pubsubTarget: _google_cloud_scheduler_build_protos_protos.google.cloud.scheduler.v1.IPubsubTarget | null | undefined;
@@ -28833,6 +28867,21 @@ declare class JWKSHelper extends Runtime {
28833
28867
  private fetchJWKS;
28834
28868
  }
28835
28869
 
28870
+ interface ColumnSchema {
28871
+ name: string;
28872
+ type: string;
28873
+ mode?: string;
28874
+ }
28875
+ declare class BigQueryHelper extends Runtime {
28876
+ private bigQuery;
28877
+ constructor(opts: Opts, bigQuery: BigQuery);
28878
+ createOrUpdate(opts: {
28879
+ datasetId: string;
28880
+ tableName: string;
28881
+ incomingSchema: ColumnSchema[];
28882
+ }): Promise<string>;
28883
+ }
28884
+
28836
28885
  type TriggerOnExecuteOptions = {
28837
28886
  req: {
28838
28887
  status?: number;
@@ -28979,6 +29028,8 @@ type TriggerOnCreateOptions = {
28979
29028
  };
28980
29029
  };
28981
29030
 
29031
+ type index_BigQueryHelper = BigQueryHelper;
29032
+ declare const index_BigQueryHelper: typeof BigQueryHelper;
28982
29033
  type index_EnvEngine = EnvEngine;
28983
29034
  declare const index_EnvEngine: typeof EnvEngine;
28984
29035
  type index_JWKSHelper = JWKSHelper;
@@ -28993,14 +29044,16 @@ type index_Secrets = Secrets;
28993
29044
  declare const index_Secrets: typeof Secrets;
28994
29045
  type index_TriggerOnCreateOptions = TriggerOnCreateOptions;
28995
29046
  type index_TriggerOnExecuteOptions = TriggerOnExecuteOptions;
29047
+ declare const index_getEventTime: typeof getEventTime;
28996
29048
  declare const index_isCronMessage: typeof isCronMessage;
28997
29049
  declare const index_isPubSubRequest: typeof isPubSubRequest;
29050
+ declare const index_parseDateOrDefault: typeof parseDateOrDefault;
28998
29051
  declare const index_sanitize: typeof sanitize;
28999
29052
  declare const index_sanitizeToString: typeof sanitizeToString;
29000
29053
  declare const index_validate: typeof validate;
29001
29054
  declare const index_validateGoogleAuth: typeof validateGoogleAuth;
29002
29055
  declare namespace index {
29003
- export { index_EnvEngine as EnvEngine, index_JWKSHelper as JWKSHelper, index_PubSubHelper as PubSubHelper, index_Runtime as Runtime, index_SchedulerHelper as SchedulerHelper, index_Secrets as Secrets, type index_TriggerOnCreateOptions as TriggerOnCreateOptions, type index_TriggerOnExecuteOptions as TriggerOnExecuteOptions, index_isCronMessage as isCronMessage, index_isPubSubRequest as isPubSubRequest, index_sanitize as sanitize, index_sanitizeToString as sanitizeToString, index_validate as validate, index_validateGoogleAuth as validateGoogleAuth };
29056
+ export { index_BigQueryHelper as BigQueryHelper, index_EnvEngine as EnvEngine, index_JWKSHelper as JWKSHelper, index_PubSubHelper as PubSubHelper, index_Runtime as Runtime, index_SchedulerHelper as SchedulerHelper, index_Secrets as Secrets, type index_TriggerOnCreateOptions as TriggerOnCreateOptions, type index_TriggerOnExecuteOptions as TriggerOnExecuteOptions, index_getEventTime as getEventTime, index_isCronMessage as isCronMessage, index_isPubSubRequest as isPubSubRequest, index_parseDateOrDefault as parseDateOrDefault, index_sanitize as sanitize, index_sanitizeToString as sanitizeToString, index_validate as validate, index_validateGoogleAuth as validateGoogleAuth };
29004
29057
  }
29005
29058
 
29006
29059
  export { index as lib, index$9 as schema, index$1 as types };
package/dist/index.js CHANGED
@@ -280,14 +280,17 @@ var shipped_exports2 = {};
280
280
  // src-public/index.ts
281
281
  var src_public_exports = {};
282
282
  __export(src_public_exports, {
283
+ BigQueryHelper: () => bigquery_default,
283
284
  EnvEngine: () => env_default,
284
285
  JWKSHelper: () => jwks_default,
285
286
  PubSubHelper: () => pubsub_default,
286
287
  Runtime: () => Runtime,
287
288
  SchedulerHelper: () => scheduler_default,
288
289
  Secrets: () => secret_default,
290
+ getEventTime: () => getEventTime,
289
291
  isCronMessage: () => isCronMessage,
290
292
  isPubSubRequest: () => isPubSubRequest,
293
+ parseDateOrDefault: () => parseDateOrDefault,
291
294
  sanitize: () => sanitize,
292
295
  sanitizeToString: () => sanitizeToString,
293
296
  validate: () => validate,
@@ -485,6 +488,49 @@ var validateGoogleAuth = async (opts, headers, firestore) => {
485
488
  throw new Error("Invalid authorization header " + err.message);
486
489
  }
487
490
  };
491
+ var parseDateOrDefault = (date, defaultValue = null) => {
492
+ if (!date) {
493
+ return defaultValue;
494
+ }
495
+ if (date instanceof Date) {
496
+ if (isNaN(date.getTime())) {
497
+ return defaultValue;
498
+ }
499
+ return date;
500
+ }
501
+ const dateObj = new Date(date);
502
+ if (isNaN(dateObj.getTime())) {
503
+ return defaultValue;
504
+ }
505
+ return dateObj;
506
+ };
507
+ function getEventTime(x, defaultValue) {
508
+ const possibleKeys = [
509
+ "last_modified_date_time",
510
+ "record_modified_at",
511
+ "last_modified_date",
512
+ "last_modified_datetime",
513
+ "last_modified_date_time",
514
+ "lastModifiedDateTime",
515
+ "lastModifiedAt",
516
+ "last_modified_at",
517
+ "SystemModifiedAt",
518
+ "system_modified_at",
519
+ "lastUpdatedAt",
520
+ "modified_at",
521
+ "last_updated_at",
522
+ "modifiedAt"
523
+ ];
524
+ for (let i = 0; i < possibleKeys.length; i++) {
525
+ if (x[possibleKeys[i]]) {
526
+ const possibleDateTime = new Date(x[possibleKeys[i]]);
527
+ if (!isNaN(possibleDateTime.getTime())) {
528
+ return possibleDateTime;
529
+ }
530
+ }
531
+ }
532
+ return defaultValue;
533
+ }
488
534
 
489
535
  // src-public/env.ts
490
536
  var crypto = __toESM(require("crypto"));
@@ -631,11 +677,69 @@ var AES256GCM = class {
631
677
  var env_default = EnvEngine;
632
678
 
633
679
  // src-public/pubsub.ts
680
+ var import_co_body = __toESM(require("co-body"));
681
+ function isSubscriptionOptionsPush(opts) {
682
+ return "endpointUrl" in opts;
683
+ }
634
684
  var PubSubHelper = class extends Runtime {
635
685
  constructor(opts, pubSub) {
636
686
  super(opts);
637
687
  this.pubSub = pubSub;
638
688
  }
689
+ static async decodeMessageFromRequest(req) {
690
+ const rawMessage = await import_co_body.default.json(req);
691
+ const rawMessageText = Buffer.from(rawMessage.message?.data, "base64").toString("utf-8");
692
+ let messageBody;
693
+ try {
694
+ messageBody = JSON.parse(rawMessageText);
695
+ } catch (err) {
696
+ throw new Error("Could not parse the message body. Original body: " + rawMessageText + " . Error: " + err.message);
697
+ }
698
+ const message = {
699
+ sourceSystem: rawMessage.attributes?.source_system || "unknown",
700
+ targetSystem: rawMessage.attributes?.target_system || "*",
701
+ processStartedAt: parseDateOrDefault(rawMessage.attributes?.process_started_at),
702
+ recordModifiedAt: parseDateOrDefault(getEventTime(messageBody, rawMessage.attributes?.record_modified_at)),
703
+ originalPublishTime: parseDateOrDefault(rawMessage.attributes?.original_publish_time, parseDateOrDefault(rawMessage.publish_time)),
704
+ buildshipId: rawMessage.attributes?.buildship_id || "unknown",
705
+ publishTime: parseDateOrDefault(rawMessage.publish_time),
706
+ body: messageBody
707
+ };
708
+ return message;
709
+ }
710
+ async publish(options, payload, orgMessage) {
711
+ const topic = this.pubSub.topic(options.topicName, {
712
+ batching: {
713
+ maxMessages: 20,
714
+ maxMilliseconds: 2 * 1e3
715
+ }
716
+ });
717
+ let normPayloads = [];
718
+ if (!Array.isArray(payload)) {
719
+ normPayloads = [payload];
720
+ } else {
721
+ normPayloads = payload;
722
+ }
723
+ const promises = [];
724
+ for (let i = 0; i < normPayloads.length; i++) {
725
+ const normPayload = normPayloads[i];
726
+ promises.push((async () => {
727
+ const result = await topic.publishMessage({
728
+ data: Buffer.from(JSON.stringify(normPayload)),
729
+ attributes: {
730
+ source_system: options.sourceSystem,
731
+ target_system: options.targetSystem || orgMessage?.targetSystem || "*",
732
+ process_started_at: (options.processStartedAt || orgMessage?.processStartedAt || /* @__PURE__ */ new Date()).toISOString(),
733
+ record_modified_at: (getEventTime(normPayload, null) || /* @__PURE__ */ new Date()).toISOString(),
734
+ original_publish_time: (orgMessage?.originalPublishTime || orgMessage?.publishTime || /* @__PURE__ */ new Date())?.toDateString() || "",
735
+ buildship_id: this.systemEnvName + "-" + this.workflowId + "-" + this.triggerId
736
+ }
737
+ });
738
+ return result;
739
+ })());
740
+ }
741
+ return Promise.all(promises);
742
+ }
639
743
  async createOrUpdate(opts) {
640
744
  const subscriptionName = `${this.envName === "prod" ? "" : `${this.envName}---`}${this.triggerId}`;
641
745
  const topic = await this.ensureTopicExists(opts.topicName);
@@ -648,6 +752,18 @@ var PubSubHelper = class extends Runtime {
648
752
  dlqSubscription = await this.ensureDLQSubscriptionExists(dlqSubscriptionName, {
649
753
  topic: dlqTopic
650
754
  });
755
+ } else {
756
+ await this.deleteSubscription(`${subscriptionName}-dlq`);
757
+ }
758
+ let bqSubscription = null;
759
+ if (opts.bigQueryTableId) {
760
+ const bigQuerySubscriptionName = `${subscriptionName}-bq`;
761
+ bqSubscription = await this.ensureSubscribtionExists(bigQuerySubscriptionName, {
762
+ topic,
763
+ tableId: opts.bigQueryTableId
764
+ });
765
+ } else {
766
+ await this.deleteSubscription(`${subscriptionName}-bq`);
651
767
  }
652
768
  const subscription = await this.ensureSubscribtionExists(subscriptionName, {
653
769
  topic,
@@ -661,6 +777,7 @@ var PubSubHelper = class extends Runtime {
661
777
  return {
662
778
  topic,
663
779
  dlqTopic,
780
+ bqSubscription,
664
781
  dlqSubscription,
665
782
  subscription
666
783
  };
@@ -689,40 +806,58 @@ var PubSubHelper = class extends Runtime {
689
806
  let subscription = subscriptions.find((subscription2) => this.getNameFromFullyQualifiedName(subscription2.name) === subscriptionName);
690
807
  let endpointHasChanged = false;
691
808
  let retryLimitHasChanged = false;
809
+ let ackDeadlineHasChanged = false;
692
810
  let retryDelayHasChanged = false;
693
811
  let shouldRecreate = false;
694
812
  let dlqHasChanged = false;
813
+ let tableIdHasChanged = false;
695
814
  if (subscription) {
696
815
  const [subscriptionMetaData] = await subscription.getMetadata();
697
- endpointHasChanged = subscriptionMetaData.pushConfig?.pushEndpoint != opts.endpointUrl;
698
- retryDelayHasChanged = subscriptionMetaData.retryPolicy?.minimumBackoff?.seconds != opts.retryMinDelay;
699
- retryLimitHasChanged = subscriptionMetaData.deadLetterPolicy?.maxDeliveryAttempts != opts.retryLimit;
700
- dlqHasChanged = !subscriptionMetaData.deadLetterPolicy && !!opts.dlqTopic || !!subscriptionMetaData.deadLetterPolicy?.deadLetterTopic && !opts.dlqTopic;
701
- shouldRecreate = endpointHasChanged || retryDelayHasChanged || retryLimitHasChanged || dlqHasChanged;
816
+ if (!isSubscriptionOptionsPush(opts)) {
817
+ tableIdHasChanged = (subscriptionMetaData.bigqueryConfig?.table || null) !== (opts.tableId || null);
818
+ } else {
819
+ endpointHasChanged = subscriptionMetaData.pushConfig?.pushEndpoint != opts.endpointUrl;
820
+ dlqHasChanged = !subscriptionMetaData.deadLetterPolicy && !!opts.dlqTopic || !!subscriptionMetaData.deadLetterPolicy?.deadLetterTopic && !opts.dlqTopic;
821
+ retryDelayHasChanged = subscriptionMetaData.retryPolicy?.minimumBackoff?.seconds != opts.retryMinDelay;
822
+ retryLimitHasChanged = subscriptionMetaData.deadLetterPolicy?.maxDeliveryAttempts != opts.retryLimit;
823
+ ackDeadlineHasChanged = subscriptionMetaData.ackDeadlineSeconds !== (opts.ackDeadline || 90);
824
+ }
825
+ shouldRecreate = endpointHasChanged || retryDelayHasChanged || retryLimitHasChanged || dlqHasChanged || tableIdHasChanged || ackDeadlineHasChanged;
702
826
  }
703
827
  if (subscription && shouldRecreate) {
704
828
  await subscription.delete();
705
829
  }
706
- if (!subscription || shouldRecreate) {
707
- await opts.topic.createSubscription(subscriptionName, Object.assign({
708
- ackDeadlineSeconds: opts.ackDeadline || 90,
709
- pushConfig: {
710
- pushEndpoint: opts.endpointUrl,
711
- oidcToken: {
712
- serviceAccountEmail: `runtime@${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`,
713
- audience: process.env.GCLOUD_PROJECT + "/" + this.triggerId
714
- }
715
- },
716
- retryPolicy: {
717
- minimumBackoff: { seconds: opts.retryMinDelay },
718
- maximumBackoff: { seconds: opts.retryMaxDelay }
830
+ const payload = {};
831
+ if (!isSubscriptionOptionsPush(opts)) {
832
+ payload.ackDeadlineSeconds = 60;
833
+ payload.bigqueryConfig = {
834
+ table: opts.tableId,
835
+ writeMetadata: true,
836
+ dropUnknownFields: true,
837
+ useTableSchema: true
838
+ };
839
+ } else {
840
+ payload.ackDeadlineSeconds = opts.ackDeadline || 90;
841
+ payload.pushConfig = {
842
+ pushEndpoint: opts.endpointUrl,
843
+ oidcToken: {
844
+ serviceAccountEmail: `runtime@${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`,
845
+ audience: process.env.GCLOUD_PROJECT + "/" + this.triggerId
719
846
  }
720
- }, opts.dlqTopic ? {
721
- deadLetterPolicy: {
847
+ };
848
+ payload.retryPolicy = {
849
+ minimumBackoff: { seconds: opts.retryMinDelay },
850
+ maximumBackoff: { seconds: opts.retryMaxDelay }
851
+ };
852
+ if (opts.dlqTopic) {
853
+ payload.deadLetterPolicy = {
722
854
  deadLetterTopic: opts.dlqTopic.name,
723
855
  maxDeliveryAttempts: opts.retryLimit
724
- }
725
- } : {}));
856
+ };
857
+ }
858
+ }
859
+ if (!subscription || shouldRecreate) {
860
+ await opts.topic.createSubscription(subscriptionName, payload);
726
861
  [subscriptions] = await opts.topic.getSubscriptions();
727
862
  subscription = subscriptions.find((subscription2) => this.getNameFromFullyQualifiedName(subscription2.name) === subscriptionName);
728
863
  }
@@ -942,6 +1077,64 @@ var Secrets = class extends Runtime {
942
1077
  }
943
1078
  };
944
1079
  var secret_default = Secrets;
1080
+
1081
+ // src-public/bigquery.ts
1082
+ var BigQueryHelper = class extends Runtime {
1083
+ constructor(opts, bigQuery) {
1084
+ super(opts);
1085
+ this.bigQuery = bigQuery;
1086
+ }
1087
+ async createOrUpdate(opts) {
1088
+ const { datasetId, tableName, incomingSchema } = opts;
1089
+ const dataset = this.bigQuery.dataset(datasetId);
1090
+ const table = dataset.table(tableName);
1091
+ const fullTableId = `${this.bigQuery.projectId}.${datasetId}.${tableName}`;
1092
+ const [tableExists] = await table.exists();
1093
+ if (!tableExists) {
1094
+ throw new Error(`Table ${fullTableId} does not exist.`);
1095
+ }
1096
+ const [metadata] = await table.getMetadata();
1097
+ const existingSchema = metadata.schema.fields;
1098
+ const alterStatements = [];
1099
+ const existingColumnsMap = new Map(
1100
+ existingSchema.map((col) => [col.name.toLowerCase(), col])
1101
+ );
1102
+ const incomingColumnsMap = new Map(
1103
+ incomingSchema.map((col) => [col.name.toLowerCase(), col])
1104
+ );
1105
+ const currentDate = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
1106
+ for (const incomingCol of incomingSchema) {
1107
+ const existingCol = existingColumnsMap.get(incomingCol.name.toLowerCase());
1108
+ if (!existingCol) {
1109
+ alterStatements.push(
1110
+ `ALTER TABLE \`${fullTableId}\` ADD COLUMN \`${incomingCol.name}\` ${incomingCol.type}${incomingCol.mode === "REPEATED" ? " REPEATED" : ""};`
1111
+ );
1112
+ } else if (existingCol.type !== incomingCol.type || incomingCol.mode && existingCol.mode !== incomingCol.mode) {
1113
+ const renamed = `${incomingCol.name}${currentDate}`;
1114
+ alterStatements.push(
1115
+ `ALTER TABLE \`${fullTableId}\` RENAME COLUMN \`${incomingCol.name}\` TO \`${renamed}\`;`
1116
+ );
1117
+ alterStatements.push(
1118
+ `ALTER TABLE \`${fullTableId}\` ADD COLUMN \`${incomingCol.name}\` ${incomingCol.type}${incomingCol.mode === "REPEATED" ? " REPEATED" : ""};`
1119
+ );
1120
+ }
1121
+ }
1122
+ for (const existingCol of existingSchema) {
1123
+ if (!incomingColumnsMap.has(existingCol.name.toLowerCase())) {
1124
+ const renamed = `${existingCol.name}${currentDate}`;
1125
+ alterStatements.push(
1126
+ `ALTER TABLE \`${fullTableId}\` RENAME COLUMN \`${existingCol.name}\` TO \`${renamed}\`;`
1127
+ );
1128
+ }
1129
+ }
1130
+ for (const sql of alterStatements) {
1131
+ console.log(`Executing SQL: ${sql}`);
1132
+ await this.bigQuery.query({ query: sql });
1133
+ }
1134
+ return fullTableId;
1135
+ }
1136
+ };
1137
+ var bigquery_default = BigQueryHelper;
945
1138
  // Annotate the CommonJS export names for ESM import in node:
946
1139
  0 && (module.exports = {
947
1140
  lib,
package/dist/package.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "@hackylabs/deep-redact": "^2.2.1",
9
9
  "ajv": "^8.17.1",
10
10
  "ajv-formats": "^3.0.1",
11
+ "co-body": "^6.2.0",
11
12
  "jose": "^6.0.11",
12
13
  "lodash.clonedeep": "^4.5.0"
13
14
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shushed/helpers",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "author": "",
5
5
  "license": "UNLICENSED",
6
6
  "description": "",
@@ -8,6 +8,7 @@
8
8
  "@hackylabs/deep-redact": "^2.2.1",
9
9
  "ajv": "^8.17.1",
10
10
  "ajv-formats": "^3.0.1",
11
+ "co-body": "^6.2.0",
11
12
  "jose": "^6.0.11",
12
13
  "lodash.clonedeep": "^4.5.0"
13
14
  },