node-s3tables 0.0.13 → 0.0.15

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
@@ -27,6 +27,7 @@ interface ManifestListRecord {
27
27
  existing_rows_count: bigint;
28
28
  deleted_rows_count: bigint;
29
29
  partitions?: PartitionSummary[] | null;
30
+ key_metadata?: Buffer | null;
30
31
  }
31
32
 
32
33
  type IcebergTransform = 'identity' | 'year' | 'month' | 'day' | 'hour' | `bucket[${number}]` | `truncate[${number}]`;
package/dist/index.js CHANGED
@@ -622,6 +622,13 @@ const ManifestListType = avsc__namespace.Type.forSchema({
622
622
  default: null,
623
623
  'field-id': 507,
624
624
  },
625
+ {
626
+ name: 'key_metadata',
627
+ type: ['null', 'bytes'],
628
+ doc: 'Encryption key metadata blob',
629
+ default: null,
630
+ 'field-id': 519,
631
+ },
625
632
  ],
626
633
  }, { registry: { ...AvroRegistry } });
627
634
 
@@ -776,6 +783,149 @@ function makeBounds(partitions, spec, schema) {
776
783
  });
777
784
  }
778
785
 
786
+ function isRawRecordSchema(schema) {
787
+ return (typeof schema === 'object' &&
788
+ schema !== null &&
789
+ 'type' in schema &&
790
+ schema.type === 'record' &&
791
+ 'fields' in schema);
792
+ }
793
+ function isRawArraySchema(schema) {
794
+ return (typeof schema === 'object' &&
795
+ schema !== null &&
796
+ 'type' in schema &&
797
+ schema.type === 'array');
798
+ }
799
+ function isRawMapSchema(schema) {
800
+ return (typeof schema === 'object' &&
801
+ schema !== null &&
802
+ 'type' in schema &&
803
+ schema.type === 'map');
804
+ }
805
+ function isRawUnionSchema(schema) {
806
+ return Array.isArray(schema);
807
+ }
808
+ function translateRecord(sourceSchema, targetSchema, record) {
809
+ return translateValue(sourceSchema, targetSchema, record);
810
+ }
811
+ function translateValue(sourceSchema, targetSchema, value) {
812
+ if (value === null || value === undefined) {
813
+ return value;
814
+ }
815
+ // Handle unions
816
+ if (isRawUnionSchema(targetSchema)) {
817
+ for (const targetBranch of targetSchema) {
818
+ if (isRawUnionSchema(sourceSchema)) {
819
+ for (const sourceBranch of sourceSchema) {
820
+ try {
821
+ return translateValue(sourceBranch, targetBranch, value);
822
+ }
823
+ catch {
824
+ // Try next branch
825
+ }
826
+ }
827
+ }
828
+ else {
829
+ try {
830
+ return translateValue(sourceSchema, targetBranch, value);
831
+ }
832
+ catch {
833
+ // Try next branch
834
+ }
835
+ }
836
+ }
837
+ return value;
838
+ }
839
+ if (isRawUnionSchema(sourceSchema)) {
840
+ for (const sourceBranch of sourceSchema) {
841
+ try {
842
+ return translateValue(sourceBranch, targetSchema, value);
843
+ }
844
+ catch {
845
+ // Try next branch
846
+ }
847
+ }
848
+ }
849
+ // Handle primitives
850
+ if (typeof sourceSchema === 'string' && typeof targetSchema === 'string') {
851
+ return value;
852
+ }
853
+ // Handle records
854
+ if (isRawRecordSchema(sourceSchema) && isRawRecordSchema(targetSchema)) {
855
+ return translateRecordValue(sourceSchema, targetSchema, value);
856
+ }
857
+ // Handle arrays
858
+ if (isRawArraySchema(sourceSchema) && isRawArraySchema(targetSchema)) {
859
+ if (!Array.isArray(value)) {
860
+ return value;
861
+ }
862
+ return value.map((item) => translateValue(sourceSchema.items, targetSchema.items, item));
863
+ }
864
+ // Handle maps
865
+ if (isRawMapSchema(sourceSchema) && isRawMapSchema(targetSchema)) {
866
+ if (typeof value !== 'object') {
867
+ return value;
868
+ }
869
+ const result = {};
870
+ for (const [key, val] of Object.entries(value)) {
871
+ result[key] = translateValue(sourceSchema.values, targetSchema.values, val);
872
+ }
873
+ return result;
874
+ }
875
+ return value;
876
+ }
877
+ function translateRecordValue(sourceSchema, targetSchema, record) {
878
+ if (typeof record !== 'object' || record === null) {
879
+ return record;
880
+ }
881
+ const sourceRecord = record;
882
+ const result = {};
883
+ // Build field maps from source
884
+ const sourceFieldById = new Map();
885
+ const sourceFieldByName = new Map();
886
+ for (const field of sourceSchema.fields) {
887
+ if (field['field-id'] !== undefined) {
888
+ sourceFieldById.set(field['field-id'], field);
889
+ }
890
+ sourceFieldByName.set(field.name, field);
891
+ }
892
+ // Translate each target field
893
+ for (const targetField of targetSchema.fields) {
894
+ let sourceField;
895
+ let sourceValue;
896
+ // Match by field-id first
897
+ if (targetField['field-id'] !== undefined) {
898
+ sourceField = sourceFieldById.get(targetField['field-id']);
899
+ if (sourceField) {
900
+ sourceValue = sourceRecord[sourceField.name];
901
+ }
902
+ }
903
+ // Fall back to name match
904
+ if (sourceField === undefined) {
905
+ sourceField = sourceFieldByName.get(targetField.name);
906
+ if (sourceField) {
907
+ sourceValue = sourceRecord[sourceField.name];
908
+ }
909
+ }
910
+ // Handle missing source field or value
911
+ if (sourceField === undefined) {
912
+ if ('default' in targetField) {
913
+ result[targetField.name] = targetField.default;
914
+ }
915
+ }
916
+ else if (sourceValue === undefined) {
917
+ if ('default' in targetField) {
918
+ result[targetField.name] = targetField.default;
919
+ }
920
+ }
921
+ else {
922
+ // Translate the value
923
+ result[targetField.name] = translateValue(sourceField.type, targetField.type, sourceValue);
924
+ }
925
+ }
926
+ return result;
927
+ }
928
+
779
929
  const S3_REGEX = /^s3:\/\/([^/]+)\/(.+)$/;
780
930
  function parseS3Url(url) {
781
931
  const match = S3_REGEX.exec(url);
@@ -846,9 +996,15 @@ async function updateManifestList(params) {
846
996
  throw new Error('failed to get source manifest list');
847
997
  }
848
998
  const passthrough = new node_stream.PassThrough();
999
+ let sourceSchema;
849
1000
  const decoder = new avsc__namespace.streams.BlockDecoder({
850
1001
  codecs: { deflate: zlib__namespace.inflateRaw },
851
- parseHook: () => ManifestListType,
1002
+ parseHook(schema) {
1003
+ sourceSchema = schema;
1004
+ return avsc__namespace.Type.forSchema(schema, {
1005
+ registry: { ...AvroRegistry },
1006
+ });
1007
+ },
852
1008
  });
853
1009
  const encoder = new avsc__namespace.streams.BlockEncoder(ManifestListType, {
854
1010
  codec: 'deflate',
@@ -877,7 +1033,8 @@ async function updateManifestList(params) {
877
1033
  reject(err);
878
1034
  });
879
1035
  decoder.on('data', (record) => {
880
- if (!encoder.write(record)) {
1036
+ const translated = translateRecord(sourceSchema, ManifestListType.schema(), record);
1037
+ if (!encoder.write(translated)) {
881
1038
  decoder.pause();
882
1039
  encoder.once('drain', () => decoder.resume());
883
1040
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-s3tables",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "node api for dealing with s3tables",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",