@fluentcommerce/fc-connect-sdk 0.1.54 → 0.1.56
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/CHANGELOG.md +12 -0
- package/README.md +11 -0
- package/dist/cjs/clients/fluent-client.js +13 -6
- package/dist/cjs/utils/pagination-helpers.js +38 -2
- package/dist/cjs/versori/fluent-versori-client.js +11 -5
- package/dist/esm/clients/fluent-client.js +13 -6
- package/dist/esm/utils/pagination-helpers.js +38 -2
- package/dist/esm/versori/fluent-versori-client.js +11 -5
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/docs/00-START-HERE/EXPORT-VALIDATION.md +158 -158
- package/docs/00-START-HERE/cli-analyze-source-structure-guide.md +655 -655
- package/docs/00-START-HERE/cli-documentation-index.md +202 -202
- package/docs/00-START-HERE/cli-quick-reference.md +252 -252
- package/docs/00-START-HERE/decision-tree.md +552 -552
- package/docs/00-START-HERE/getting-started.md +1070 -1070
- package/docs/00-START-HERE/mapper-quick-decision-guide.md +235 -235
- package/docs/00-START-HERE/readme.md +237 -237
- package/docs/00-START-HERE/retailerid-configuration.md +404 -404
- package/docs/00-START-HERE/sdk-philosophy.md +794 -794
- package/docs/00-START-HERE/troubleshooting-quick-reference.md +1086 -1086
- package/docs/01-TEMPLATES/faq.md +686 -686
- package/docs/01-TEMPLATES/patterns/pattern-templates-guide.md +68 -68
- package/docs/01-TEMPLATES/patterns/patterns-csv-schema-validation-and-rejection-report.md +233 -233
- package/docs/01-TEMPLATES/patterns/patterns-custom-resolvers.md +407 -407
- package/docs/01-TEMPLATES/patterns/patterns-error-handling-retry.md +511 -511
- package/docs/01-TEMPLATES/patterns/patterns-field-mapping-universal.md +701 -701
- package/docs/01-TEMPLATES/patterns/patterns-large-file-splitting.md +1430 -1430
- package/docs/01-TEMPLATES/patterns/patterns-master-data-etl.md +2399 -2399
- package/docs/01-TEMPLATES/patterns/patterns-pagination-streaming.md +447 -447
- package/docs/01-TEMPLATES/patterns/patterns-state-duplicate-prevention.md +385 -385
- package/docs/01-TEMPLATES/readme.md +957 -957
- package/docs/01-TEMPLATES/standalone/standalone-asn-inbound-processing.md +1209 -1209
- package/docs/01-TEMPLATES/standalone/standalone-graphql-query-export.md +1140 -1140
- package/docs/01-TEMPLATES/standalone/standalone-graphql-to-parquet-partitioned-s3.md +432 -432
- package/docs/01-TEMPLATES/standalone/standalone-multi-channel-inventory-sync.md +1185 -1185
- package/docs/01-TEMPLATES/standalone/standalone-multi-source-aggregation.md +1462 -1462
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-batch-api.md +1390 -1390
- package/docs/01-TEMPLATES/standalone/standalone-s3-csv-inventory-to-batch.md +330 -330
- package/docs/01-TEMPLATES/standalone/standalone-scripts-guide.md +87 -87
- package/docs/01-TEMPLATES/standalone/standalone-sftp-xml-graphql.md +1444 -1444
- package/docs/01-TEMPLATES/standalone/standalone-webhook-payload-processing.md +688 -688
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-dropship-order-routing.md +193 -193
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-graphql-parquet-extraction.md +518 -518
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-inter-location-transfers.md +2162 -2162
- package/docs/01-TEMPLATES/versori/business-examples/business-examples-pre-order-allocation.md +2226 -2226
- package/docs/01-TEMPLATES/versori/business-examples/business-scenarios-guide.md +87 -87
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-connection-validation-pattern.md +656 -656
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-dual-workflow-connector.md +835 -835
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-guide.md +108 -108
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-kv-state-management.md +1533 -1533
- package/docs/01-TEMPLATES/versori/patterns/versori-patterns-xml-response-patterns.md +1160 -1160
- package/docs/01-TEMPLATES/versori/versori-platform-guide.md +201 -201
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-asn-purchase-order.md +1906 -1906
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-dropship-routing.md +1074 -1074
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-flash-sale-reserve.md +1395 -1395
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-generic-xml-order.md +888 -888
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-payment-gateway-integration.md +2478 -2478
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-rma-returns-comprehensive.md +2240 -2240
- package/docs/01-TEMPLATES/versori/webhooks/template-webhook-xml-order-ingestion.md +2029 -2029
- package/docs/01-TEMPLATES/versori/webhooks/webhook-templates-guide.md +140 -140
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/inventory-mapping.json +20 -20
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/products_2025-01-22.csv +11 -11
- package/docs/01-TEMPLATES/versori/workflows/_examples/sample-data/sample-data-guide.md +34 -34
- package/docs/01-TEMPLATES/versori/workflows/_examples/workflow-examples-guide.md +36 -36
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-modes-guide.md +1038 -1038
- package/docs/01-TEMPLATES/versori/workflows/extraction/extraction-workflows-guide.md +138 -138
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/graphql-extraction-guide.md +63 -63
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-csv.md +2062 -2062
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-fulfillments-to-sftp-xml.md +2294 -2294
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-s3-csv.md +2461 -2461
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-positions-to-sftp-xml.md +2529 -2529
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-csv.md +2464 -2464
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-inventory-quantities-to-s3-json.md +1959 -1959
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-s3-csv.md +1953 -1953
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-orders-to-sftp-xml.md +2541 -2541
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-s3-json.md +2384 -2384
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-products-to-sftp-xml.md +2445 -2445
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-csv.md +2355 -2355
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-s3-json.md +2042 -2042
- package/docs/01-TEMPLATES/versori/workflows/extraction/graphql-queries/template-extraction-virtual-positions-to-sftp-xml.md +2726 -2726
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/batch-api-guide.md +206 -206
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-cycle-count-reconciliation.md +2030 -2030
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-multi-channel-inventory-sync.md +1882 -1882
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-csv-inventory-batch.md +2827 -2827
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-json-inventory-batch.md +1952 -1952
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-s3-xml-inventory-batch.md +3289 -3289
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-csv-inventory-batch.md +3064 -3064
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-json-inventory-batch.md +3238 -3238
- package/docs/01-TEMPLATES/versori/workflows/ingestion/batch-api/template-ingestion-sftp-xml-inventory-batch.md +2977 -2977
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/event-api-guide.md +321 -321
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-json-order-cancel-event.md +959 -959
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-payload-xml-order-cancel-event.md +1170 -1170
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-csv-product-event.md +2312 -2312
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-json-product-event.md +2999 -2999
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-parquet-product-event.md +2836 -2836
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-s3-xml-product-event.md +2395 -2395
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-csv-product-event.md +2295 -2295
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-json-product-event.md +2602 -2602
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-parquet-product-event.md +2589 -2589
- package/docs/01-TEMPLATES/versori/workflows/ingestion/event-api/template-ingestion-sftp-xml-product-event.md +3578 -3578
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/graphql-mutations-guide.md +93 -93
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-json-order-update-graphql.md +1260 -1260
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-payload-xml-order-update-graphql.md +1472 -1472
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-control-graphql.md +2417 -2417
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-location-graphql.md +2811 -2811
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-csv-price-graphql.md +2619 -2619
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-json-location-graphql.md +2807 -2807
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-s3-xml-location-graphql.md +2373 -2373
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-control-graphql.md +2740 -2740
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-csv-location-graphql.md +2760 -2760
- package/docs/01-TEMPLATES/versori/workflows/ingestion/graphql-mutations/template-ingestion-sftp-json-location-graphql.md +1710 -1710
- package/docs/01-TEMPLATES/versori/workflows/ingestion/ingestion-workflows-guide.md +136 -136
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/rubix-webhooks-guide.md +520 -520
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-inline.md +1418 -1418
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-fulfilment-to-sftp-xml-universal-mapper.md +1785 -1785
- package/docs/01-TEMPLATES/versori/workflows/rubix-webhooks/template-webhook-rubix-order-attribute-update.md +824 -824
- package/docs/01-TEMPLATES/versori/workflows/workflows-overview-guide.md +646 -646
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-batch-archival.md +724 -724
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-job-tracker.md +627 -627
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-partial-batch-recovery.md +561 -561
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-quick-reference.md +367 -367
- package/docs/02-CORE-GUIDES/advanced-services/advanced-services-readme.md +407 -407
- package/docs/02-CORE-GUIDES/advanced-services/readme.md +49 -49
- package/docs/02-CORE-GUIDES/api-reference/api-reference-quick-reference.md +548 -548
- package/docs/02-CORE-GUIDES/api-reference/event-api-input-output-reference.md +702 -1171
- package/docs/02-CORE-GUIDES/api-reference/examples/client-initialization.ts +286 -286
- package/docs/02-CORE-GUIDES/api-reference/graphql-error-classification.md +337 -337
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-01-client-api.md +399 -520
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-03-authentication.md +199 -199
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-04-graphql-mapping.md +925 -925
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-05-services.md +1198 -1198
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-06-data-sources.md +1083 -1083
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-07-parsers.md +1097 -1097
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-pagination.md +513 -513
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-08-types.md +545 -597
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-error-handling.md +527 -527
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-09-webhook-validation.md +514 -514
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-extraction.md +557 -557
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-10-utilities.md +412 -412
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-cli-tools.md +423 -423
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-11-error-handling.md +716 -716
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-analyze-source-structure.md +518 -518
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-partial-responses.md +212 -212
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-12-testing.md +300 -300
- package/docs/02-CORE-GUIDES/api-reference/modules/api-reference-13-resolver-builder.md +322 -322
- package/docs/02-CORE-GUIDES/api-reference/readme.md +279 -279
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-quick-reference.md +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/auto-pagination-readme.md +277 -277
- package/docs/02-CORE-GUIDES/auto-pagination/examples/auto-pagination-readme.md +178 -178
- package/docs/02-CORE-GUIDES/auto-pagination/examples/common-patterns.ts +351 -351
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-products.ts +384 -384
- package/docs/02-CORE-GUIDES/auto-pagination/examples/paginate-virtual-positions.ts +308 -308
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-01-foundations.md +470 -470
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-02-quick-start.md +713 -713
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-03-configuration.md +754 -754
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-04-advanced-patterns.md +732 -732
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-05-sdk-integration.md +847 -847
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-06-troubleshooting.md +359 -359
- package/docs/02-CORE-GUIDES/auto-pagination/modules/auto-pagination-07-api-reference.md +462 -462
- package/docs/02-CORE-GUIDES/auto-pagination/readme.md +54 -54
- package/docs/02-CORE-GUIDES/data-sources/data-sources-file-operations-error-handling.md +1487 -1487
- package/docs/02-CORE-GUIDES/data-sources/data-sources-quick-reference.md +836 -836
- package/docs/02-CORE-GUIDES/data-sources/data-sources-readme.md +276 -276
- package/docs/02-CORE-GUIDES/data-sources/data-sources-sftp-credential-access-security.md +553 -553
- package/docs/02-CORE-GUIDES/data-sources/examples/common-patterns.ts +409 -409
- package/docs/02-CORE-GUIDES/data-sources/examples/data-sources-readme.md +178 -178
- package/docs/02-CORE-GUIDES/data-sources/examples/s3-operations.ts +308 -308
- package/docs/02-CORE-GUIDES/data-sources/examples/sftp-operations.ts +371 -371
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-01-foundations.md +735 -735
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-02-s3-operations.md +1302 -1302
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-03-sftp-operations.md +1379 -1379
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-04-file-patterns.md +941 -941
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-05-advanced-topics.md +813 -813
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-06-integration-patterns.md +486 -486
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-07-troubleshooting.md +387 -387
- package/docs/02-CORE-GUIDES/data-sources/modules/data-sources-08-api-reference.md +417 -417
- package/docs/02-CORE-GUIDES/data-sources/readme.md +77 -77
- package/docs/02-CORE-GUIDES/error-handling-guide.md +936 -936
- package/docs/02-CORE-GUIDES/extraction/examples/02-core-guides-extraction-readme.md +116 -116
- package/docs/02-CORE-GUIDES/extraction/examples/common-patterns.ts +428 -428
- package/docs/02-CORE-GUIDES/extraction/examples/extract-inventory-basic.ts +187 -187
- package/docs/02-CORE-GUIDES/extraction/extraction-quick-reference.md +596 -596
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-01-foundations.md +514 -514
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-02-basic-extraction.md +823 -823
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md +507 -507
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-04-data-enrichment.md +546 -546
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-05-transformation.md +494 -494
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-export-formats.md +458 -458
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-06-performance.md +138 -138
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-api-reference.md +148 -148
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-07-optimization.md +692 -692
- package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-08-extraction-orchestrator.md +1008 -1008
- package/docs/02-CORE-GUIDES/extraction/readme.md +151 -151
- package/docs/02-CORE-GUIDES/ingestion/examples/_simple-kv-store.ts +40 -40
- package/docs/02-CORE-GUIDES/ingestion/examples/error-recovery.ts +728 -728
- package/docs/02-CORE-GUIDES/ingestion/examples/event-driven.ts +501 -501
- package/docs/02-CORE-GUIDES/ingestion/examples/local-file-ingestion.ts +88 -88
- package/docs/02-CORE-GUIDES/ingestion/examples/parquet-ingestion.ts +117 -117
- package/docs/02-CORE-GUIDES/ingestion/examples/performance-optimized.ts +647 -647
- package/docs/02-CORE-GUIDES/ingestion/examples/s3-csv-ingestion.ts +169 -169
- package/docs/02-CORE-GUIDES/ingestion/examples/sftp-csv-ingestion.ts +134 -134
- package/docs/02-CORE-GUIDES/ingestion/ingestion-quick-reference.md +546 -546
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-01-introduction.md +626 -626
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-02-quick-start.md +658 -658
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-03-data-sources.md +1052 -1052
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-04-field-mapping.md +763 -763
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-05-advanced-parsers.md +676 -676
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-06-batch-api.md +1295 -1295
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-api-reference.md +138 -138
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-07-state-management.md +1037 -1037
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-08-performance-optimization.md +1349 -1349
- package/docs/02-CORE-GUIDES/ingestion/modules/02-core-guides-ingestion-09-best-practices.md +1893 -1893
- package/docs/02-CORE-GUIDES/ingestion/readme.md +160 -160
- package/docs/02-CORE-GUIDES/logging-guide.md +585 -585
- package/docs/02-CORE-GUIDES/mapping/error-handling-patterns.md +401 -401
- package/docs/02-CORE-GUIDES/mapping/examples/02-core-guides-mapping-readme.md +128 -128
- package/docs/02-CORE-GUIDES/mapping/examples/common-patterns.ts +273 -273
- package/docs/02-CORE-GUIDES/mapping/examples/csv-location-ingestion.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/csv-mapping.ts +242 -242
- package/docs/02-CORE-GUIDES/mapping/examples/graphql-to-parquet-extraction.json +36 -36
- package/docs/02-CORE-GUIDES/mapping/examples/json-mapping.ts +213 -213
- package/docs/02-CORE-GUIDES/mapping/examples/json-product-to-mutation.json +48 -48
- package/docs/02-CORE-GUIDES/mapping/examples/xml-mapping.ts +291 -291
- package/docs/02-CORE-GUIDES/mapping/examples/xml-order-to-mutation.json +45 -45
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-quick-reference.md +463 -463
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/graphql-mutation-mapping-readme.md +227 -227
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-01-introduction.md +222 -222
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-02-quick-start.md +351 -351
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-03-schema-validation.md +569 -569
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-04-mapping-patterns.md +471 -471
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-05-configuration-reference.md +611 -611
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-advanced-xpath.md +148 -148
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-06-path-syntax.md +464 -464
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-api-reference.md +94 -94
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-07-array-handling.md +307 -307
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-08-custom-resolvers.md +544 -544
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-09-advanced-patterns.md +427 -427
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-10-hooks-and-variables.md +336 -336
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-11-error-handling.md +488 -488
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-12-arguments-vs-nodes.md +383 -383
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/modules/graphql-mutation-mapping-13-best-practices.md +477 -477
- package/docs/02-CORE-GUIDES/mapping/graphql-mutation-mapping/readme.md +62 -62
- package/docs/02-CORE-GUIDES/mapping/mapping-format-decision-tree.md +480 -480
- package/docs/02-CORE-GUIDES/mapping/mapping-graphql-alias-batching-guide.md +820 -820
- package/docs/02-CORE-GUIDES/mapping/mapping-javascript-objects.md +2369 -2369
- package/docs/02-CORE-GUIDES/mapping/mapping-mapper-comparison-guide.md +682 -682
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-07-api-reference.md +1327 -1327
- package/docs/02-CORE-GUIDES/mapping/modules/02-core-guides-mapping-08-error-handling.md +1142 -1142
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-04-use-cases.md +891 -891
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-helpers-resolvers.md +1126 -1126
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-06-sdk-resolvers.md +199 -199
- package/docs/02-CORE-GUIDES/mapping/modules/mapping-07-api-reference.md +1319 -1319
- package/docs/02-CORE-GUIDES/mapping/readme.md +178 -178
- package/docs/02-CORE-GUIDES/mapping/resolver-registration.md +410 -410
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/common-patterns.ts +226 -226
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/custom-resolvers.ts +227 -227
- package/docs/02-CORE-GUIDES/mapping/resolvers/examples/sdk-resolvers-usage.ts +203 -203
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-readme.md +274 -274
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-api-reference.md +679 -679
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-cookbook.md +826 -826
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-guide.md +1330 -1330
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-helpers-reference.md +1437 -1437
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-parameters-reference.md +553 -553
- package/docs/02-CORE-GUIDES/mapping/resolvers/mapping-resolvers-resolver-troubleshooting.md +854 -854
- package/docs/02-CORE-GUIDES/mapping/resolvers/readme.md +75 -75
- package/docs/02-CORE-GUIDES/parsers/examples/02-core-guides-parsers-readme.md +161 -161
- package/docs/02-CORE-GUIDES/parsers/examples/csv-parser-examples.ts +110 -110
- package/docs/02-CORE-GUIDES/parsers/examples/json-parser-examples.ts +33 -33
- package/docs/02-CORE-GUIDES/parsers/examples/parquet-parser-examples.ts +47 -47
- package/docs/02-CORE-GUIDES/parsers/examples/xml-parser-examples.ts +38 -38
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-01-foundations.md +355 -355
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-02-csv-parser.md +772 -772
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-03-json-parser.md +789 -789
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-04-xml-parser.md +857 -857
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-05-parquet-parser.md +603 -603
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-integration-patterns.md +702 -702
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-06-streaming.md +121 -121
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-api-reference.md +89 -89
- package/docs/02-CORE-GUIDES/parsers/modules/02-core-guides-parsers-07-troubleshooting.md +727 -727
- package/docs/02-CORE-GUIDES/parsers/parsers-quick-reference.md +482 -482
- package/docs/02-CORE-GUIDES/parsers/parsers-readme.md +258 -258
- package/docs/02-CORE-GUIDES/parsers/readme.md +65 -65
- package/docs/02-CORE-GUIDES/readme.md +194 -194
- package/docs/02-CORE-GUIDES/webhook-validation/examples/basic-validation.ts +108 -108
- package/docs/02-CORE-GUIDES/webhook-validation/examples/common-patterns.ts +316 -316
- package/docs/02-CORE-GUIDES/webhook-validation/examples/webhook-validation-readme.md +61 -61
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-01-foundations.md +440 -440
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-02-quick-start.md +525 -525
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-03-versori-integration.md +741 -741
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-04-platform-integration.md +629 -629
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-05-configuration.md +535 -535
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-error-handling.md +611 -611
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-06-troubleshooting.md +124 -124
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-07-api-reference.md +511 -511
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-08-rubix-webhooks.md +590 -590
- package/docs/02-CORE-GUIDES/webhook-validation/modules/webhook-validation-09-rubix-event-vs-http-call.md +432 -432
- package/docs/02-CORE-GUIDES/webhook-validation/readme.md +239 -239
- package/docs/02-CORE-GUIDES/webhook-validation/webhook-validation-quick-reference.md +392 -392
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-quick-reference.md +498 -498
- package/docs/03-PATTERN-GUIDES/connector-scenarios/connector-scenarios-readme.md +313 -313
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/common-patterns.ts +612 -612
- package/docs/03-PATTERN-GUIDES/connector-scenarios/examples/connector-scenarios-readme.md +253 -253
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-01-foundations.md +452 -452
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-02-simple-scenarios.md +681 -681
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-03-intermediate-scenarios.md +637 -637
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-04-advanced-scenarios.md +650 -650
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-05-bidirectional-sync.md +233 -233
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-06-production-patterns.md +442 -442
- package/docs/03-PATTERN-GUIDES/connector-scenarios/modules/connector-scenarios-07-reference.md +445 -445
- package/docs/03-PATTERN-GUIDES/connector-scenarios/readme.md +31 -31
- package/docs/03-PATTERN-GUIDES/enterprise-integration-patterns.md +1528 -1528
- package/docs/03-PATTERN-GUIDES/error-handling/comprehensive-error-handling-guide.md +1437 -1437
- package/docs/03-PATTERN-GUIDES/error-handling/error-handling-quick-reference.md +390 -390
- package/docs/03-PATTERN-GUIDES/error-handling/examples/common-patterns.ts +438 -438
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-01-foundations.md +362 -362
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-02-error-types.md +850 -850
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-03-utf8-handling.md +456 -456
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-04-error-scenarios.md +658 -658
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-05-calling-patterns.md +671 -671
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-06-retry-strategies.md +1034 -1034
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-07-monitoring.md +653 -653
- package/docs/03-PATTERN-GUIDES/error-handling/modules/error-handling-08-api-reference.md +847 -847
- package/docs/03-PATTERN-GUIDES/error-handling/readme.md +36 -36
- package/docs/03-PATTERN-GUIDES/examples/__tests__/readme.md +40 -40
- package/docs/03-PATTERN-GUIDES/examples/__tests__/resolver-examples.test.js +282 -282
- package/docs/03-PATTERN-GUIDES/examples/test-data/03-pattern-guides-readme.md +110 -110
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-inventory.json +123 -123
- package/docs/03-PATTERN-GUIDES/examples/test-data/canonical-order.json +171 -171
- package/docs/03-PATTERN-GUIDES/examples/test-data/readme.md +28 -28
- package/docs/03-PATTERN-GUIDES/extraction/extraction-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/extraction/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/file-operations/examples/common-patterns.ts +407 -407
- package/docs/03-PATTERN-GUIDES/file-operations/examples/file-operations-readme.md +142 -142
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-quick-reference.md +462 -462
- package/docs/03-PATTERN-GUIDES/file-operations/file-operations-readme.md +379 -379
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-01-foundations.md +430 -430
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-02-quick-start.md +484 -484
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-03-s3-operations.md +507 -507
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-04-sftp-operations.md +963 -963
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-05-streaming-performance.md +503 -503
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-archive-patterns.md +386 -386
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-06-error-handling.md +117 -117
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-api-reference.md +78 -78
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-07-testing-troubleshooting.md +567 -567
- package/docs/03-PATTERN-GUIDES/file-operations/modules/file-operations-08-api-reference.md +1055 -1055
- package/docs/03-PATTERN-GUIDES/file-operations/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/ingestion/ingestion-readme.md +15 -15
- package/docs/03-PATTERN-GUIDES/ingestion/readme.md +25 -25
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/batch-processing.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/common-patterns.ts +360 -360
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/delta-sync.ts +130 -130
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/integration-patterns-readme.md +100 -100
- package/docs/03-PATTERN-GUIDES/integration-patterns/examples/real-time-webhook.ts +398 -398
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-quick-reference.md +962 -962
- package/docs/03-PATTERN-GUIDES/integration-patterns/integration-patterns-readme.md +134 -134
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-01-real-time-processing.md +991 -991
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-02-batch-processing.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-03-delta-sync.md +1108 -1108
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-04-webhook-patterns.md +1181 -1181
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-05-error-handling.md +1061 -1061
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-advanced-integration-services.md +1547 -1547
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-06-performance.md +109 -109
- package/docs/03-PATTERN-GUIDES/integration-patterns/modules/integration-patterns-07-api-reference.md +34 -34
- package/docs/03-PATTERN-GUIDES/integration-patterns/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/logging-minimal-mode.md +128 -128
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/common-patterns.ts +380 -380
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/multiple-connections-readme.md +139 -139
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/parallel-root-connections.ts +149 -149
- package/docs/03-PATTERN-GUIDES/multiple-connections/examples/real-world-scenarios.ts +405 -405
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-01-foundations.md +378 -378
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-02-quick-start.md +566 -566
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-03-targeting-connections.md +659 -659
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-04-parallel-queries.md +656 -656
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-05-best-practices.md +624 -624
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-api-reference.md +824 -824
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-06-versori.md +119 -119
- package/docs/03-PATTERN-GUIDES/multiple-connections/modules/multiple-connections-07-api-reference.md +87 -87
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-quick-reference.md +353 -353
- package/docs/03-PATTERN-GUIDES/multiple-connections/multiple-connections-readme.md +270 -270
- package/docs/03-PATTERN-GUIDES/multiple-connections/readme.md +30 -30
- package/docs/03-PATTERN-GUIDES/pagination/pagination-readme.md +14 -14
- package/docs/03-PATTERN-GUIDES/pagination/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/parquet/examples/common-patterns.ts +180 -180
- package/docs/03-PATTERN-GUIDES/parquet/examples/read-parquet.ts +48 -48
- package/docs/03-PATTERN-GUIDES/parquet/examples/write-parquet.ts +65 -65
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-01-introduction.md +393 -393
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-02-quick-start.md +572 -572
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-03-reading-parquet.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-04-writing-parquet.md +554 -554
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-05-graphql-extraction.md +405 -405
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-performance.md +104 -104
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-06-s3-integration.md +511 -511
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-api-reference.md +90 -90
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-07-performance-optimization.md +525 -525
- package/docs/03-PATTERN-GUIDES/parquet/modules/03-pattern-guides-parquet-08-best-practices.md +712 -712
- package/docs/03-PATTERN-GUIDES/parquet/parquet-quick-reference.md +683 -683
- package/docs/03-PATTERN-GUIDES/parquet/parquet-readme.md +248 -248
- package/docs/03-PATTERN-GUIDES/parquet/readme.md +32 -32
- package/docs/03-PATTERN-GUIDES/parsers/parsers-readme.md +12 -12
- package/docs/03-PATTERN-GUIDES/parsers/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/readme.md +159 -159
- package/docs/03-PATTERN-GUIDES/webhooks/readme.md +24 -24
- package/docs/03-PATTERN-GUIDES/webhooks/webhooks-readme.md +8 -8
- package/docs/04-REFERENCE/architecture/architecture-01-overview.md +427 -427
- package/docs/04-REFERENCE/architecture/architecture-02-client-architecture.md +424 -424
- package/docs/04-REFERENCE/architecture/architecture-03-data-flow.md +690 -690
- package/docs/04-REFERENCE/architecture/architecture-04-service-layer.md +834 -834
- package/docs/04-REFERENCE/architecture/architecture-05-integration-architecture.md +655 -655
- package/docs/04-REFERENCE/architecture/architecture-06-state-management.md +653 -653
- package/docs/04-REFERENCE/architecture/architecture-adding-new-data-sources.md +686 -686
- package/docs/04-REFERENCE/architecture/readme.md +279 -279
- package/docs/04-REFERENCE/platforms/deno/readme.md +117 -117
- package/docs/04-REFERENCE/platforms/nodejs/readme.md +146 -146
- package/docs/04-REFERENCE/platforms/readme.md +135 -135
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-01-introduction.md +398 -398
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-02-quick-start.md +560 -560
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-03-authentication.md +757 -757
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-04-workflows.md +2476 -2476
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-05-connections.md +1167 -1167
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-kv-storage.md +990 -990
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-06-state-management.md +121 -121
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-api-reference.md +68 -68
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-07-deployment.md +731 -731
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-08-best-practices.md +1111 -1111
- package/docs/04-REFERENCE/platforms/versori/modules/platforms-versori-09-signature-reference.md +766 -766
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-readme.md +299 -299
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-s3-sftp-configuration-guide.md +1425 -1425
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-api-key-security.md +816 -816
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-webhook-connection-security.md +681 -681
- package/docs/04-REFERENCE/platforms/versori/platforms-versori-workflow-task-types.md +708 -708
- package/docs/04-REFERENCE/platforms/versori/readme.md +108 -108
- package/docs/04-REFERENCE/readme.md +148 -148
- package/docs/04-REFERENCE/resolver-signature/examples/advanced-resolvers.ts +482 -482
- package/docs/04-REFERENCE/resolver-signature/examples/async-resolvers.ts +496 -496
- package/docs/04-REFERENCE/resolver-signature/examples/basic-resolvers.ts +343 -343
- package/docs/04-REFERENCE/resolver-signature/examples/resolver-signature-readme.md +188 -188
- package/docs/04-REFERENCE/resolver-signature/examples/testing-resolvers.ts +463 -463
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-01-foundations.md +286 -286
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-02-parameter-reference.md +643 -643
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-03-basic-examples.md +521 -521
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-04-advanced-patterns.md +739 -739
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-05-sdk-resolvers.md +531 -531
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-migration-guide.md +650 -650
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-06-testing.md +125 -125
- package/docs/04-REFERENCE/resolver-signature/modules/resolver-signature-07-api-reference.md +794 -794
- package/docs/04-REFERENCE/resolver-signature/readme.md +64 -64
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-quick-reference.md +270 -270
- package/docs/04-REFERENCE/resolver-signature/resolver-signature-readme.md +351 -351
- package/docs/04-REFERENCE/schema/fluent-commerce-schema.json +764 -764
- package/docs/04-REFERENCE/schema/readme.md +141 -141
- package/docs/04-REFERENCE/testing/examples/04-reference-testing-readme.md +158 -158
- package/docs/04-REFERENCE/testing/examples/fluent-testing.ts +62 -62
- package/docs/04-REFERENCE/testing/examples/health-check.ts +155 -155
- package/docs/04-REFERENCE/testing/examples/integration-test.ts +119 -119
- package/docs/04-REFERENCE/testing/examples/performance-test.ts +183 -183
- package/docs/04-REFERENCE/testing/examples/s3-testing.ts +127 -127
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-01-foundations.md +267 -267
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-02-s3-testing.md +599 -599
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-03-fluent-testing.md +589 -589
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-04-integration-testing.md +699 -699
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-05-debugging.md +478 -478
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-cicd-integration.md +463 -463
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-06-preflight-validation.md +131 -131
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-best-practices.md +499 -499
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-07-coverage-ci.md +165 -165
- package/docs/04-REFERENCE/testing/modules/04-reference-testing-08-api-reference.md +634 -634
- package/docs/04-REFERENCE/testing/readme.md +86 -86
- package/docs/04-REFERENCE/testing/testing-quick-reference.md +667 -667
- package/docs/04-REFERENCE/testing/testing-readme.md +286 -286
- package/docs/04-REFERENCE/troubleshooting/readme.md +144 -144
- package/docs/04-REFERENCE/troubleshooting/troubleshooting-deno-sftp-compatibility.md +392 -392
- package/docs/template-loading-matrix.md +242 -242
- package/package.json +5 -3
- package/docs/02-CORE-GUIDES/api-reference/cli-profile-integration.md +0 -377
package/docs/02-CORE-GUIDES/extraction/modules/02-core-guides-extraction-03-parquet-processing.md
CHANGED
|
@@ -1,507 +1,507 @@
|
|
|
1
|
-
# Module 3: Parquet Processing
|
|
2
|
-
|
|
3
|
-
**Level:** Intermediate
|
|
4
|
-
**Estimated Time:** 25 minutes
|
|
5
|
-
|
|
6
|
-
## Overview
|
|
7
|
-
|
|
8
|
-
This module covers reading and writing Parquet files using the SDK's `ParquetParserService`, including S3 integration, streaming for large files, and validation.
|
|
9
|
-
|
|
10
|
-
## Learning Objectives
|
|
11
|
-
|
|
12
|
-
By the end of this module, you will:
|
|
13
|
-
|
|
14
|
-
- ✅ Read Parquet files from S3 using `ParquetParserService`
|
|
15
|
-
- ✅ Stream large Parquet files with batching
|
|
16
|
-
- ✅ Validate Parquet data and handle statistics
|
|
17
|
-
- ✅ Combine Parquet data with GraphQL enrichment
|
|
18
|
-
- ✅ Write transformed data back to Parquet format
|
|
19
|
-
|
|
20
|
-
## What is Parquet?
|
|
21
|
-
|
|
22
|
-
**Apache Parquet** is a columnar storage format optimized for:
|
|
23
|
-
|
|
24
|
-
- **Analytics workloads**: Efficient column scanning
|
|
25
|
-
- **Compression**: Smaller file sizes
|
|
26
|
-
- **Schema evolution**: Add/remove columns over time
|
|
27
|
-
- **Interoperability**: Supported by Spark, Athena, BigQuery, etc.
|
|
28
|
-
|
|
29
|
-
**Common use cases:**
|
|
30
|
-
|
|
31
|
-
- Data lake storage
|
|
32
|
-
- ETL pipelines
|
|
33
|
-
- Analytics exports
|
|
34
|
-
- Backup archives
|
|
35
|
-
|
|
36
|
-
## Reading Parquet Files
|
|
37
|
-
|
|
38
|
-
### Basic Parquet Reading
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
import {
|
|
42
|
-
ParquetParserService,
|
|
43
|
-
createConsoleLogger,
|
|
44
|
-
toStructuredLogger
|
|
45
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
46
|
-
|
|
47
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
48
|
-
const parser = new ParquetParserService(logger);
|
|
49
|
-
|
|
50
|
-
// Parse Parquet file
|
|
51
|
-
const arrayBuffer = ... // Load file into ArrayBuffer
|
|
52
|
-
const { records, stats } = await parser.parse(
|
|
53
|
-
arrayBuffer,
|
|
54
|
-
'inventory.parquet'
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
console.log(`Parsed ${stats.totalRecords} records in ${stats.processingTimeMs}ms`);
|
|
58
|
-
console.log(`Columns: ${Object.keys(stats.columnStats).join(', ')}`);
|
|
59
|
-
|
|
60
|
-
// Process records
|
|
61
|
-
for (const record of records) {
|
|
62
|
-
console.log(record);
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Reading from S3
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
import {
|
|
70
|
-
S3DataSource,
|
|
71
|
-
ParquetParserService,
|
|
72
|
-
createConsoleLogger,
|
|
73
|
-
toStructuredLogger
|
|
74
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
75
|
-
|
|
76
|
-
async function readParquetFromS3(bucket: string, key: string) {
|
|
77
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
78
|
-
const s3 = new S3DataSource(
|
|
79
|
-
{
|
|
80
|
-
type: 'S3_PARQUET',
|
|
81
|
-
connectionId: 's3-parquet-read',
|
|
82
|
-
name: 'S3 Parquet Read',
|
|
83
|
-
s3Config: {
|
|
84
|
-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
85
|
-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
86
|
-
region: process.env.AWS_REGION!,
|
|
87
|
-
bucket: process.env.S3_BUCKET!,
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
logger
|
|
91
|
-
);
|
|
92
|
-
const parser = new ParquetParserService(logger);
|
|
93
|
-
|
|
94
|
-
// Download from S3
|
|
95
|
-
const buffer = await s3.downloadFile(key, { encoding: 'binary' });
|
|
96
|
-
|
|
97
|
-
// Convert Buffer to ArrayBuffer
|
|
98
|
-
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
99
|
-
|
|
100
|
-
// Parse Parquet
|
|
101
|
-
const { records, stats } = await parser.parse(arrayBuffer, key);
|
|
102
|
-
|
|
103
|
-
console.log(`Loaded ${records.length} records from s3://${bucket}/${key}`);
|
|
104
|
-
|
|
105
|
-
return records;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Usage
|
|
109
|
-
const records = await readParquetFromS3('my-bucket', 'exports/inventory.parquet');
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Parquet Validation
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
const { records, stats } = await parser.parse(arrayBuffer, 'inventory.parquet', {
|
|
116
|
-
validation: {
|
|
117
|
-
enabled: true,
|
|
118
|
-
requiredColumns: ['id', 'ref', 'productRef', 'qty'],
|
|
119
|
-
allowExtraColumns: true,
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Check for validation errors
|
|
124
|
-
if (stats.validationErrors && stats.validationErrors.length > 0) {
|
|
125
|
-
console.error('Validation errors:', stats.validationErrors);
|
|
126
|
-
throw new Error('Parquet validation failed');
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Understanding Parquet Statistics
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
const { records, stats } = await parser.parse(arrayBuffer, 'data.parquet');
|
|
134
|
-
|
|
135
|
-
console.log('=== Parquet Statistics ===');
|
|
136
|
-
console.log(`Total records: ${stats.totalRecords}`);
|
|
137
|
-
console.log(`Processing time: ${stats.processingTimeMs}ms`);
|
|
138
|
-
console.log(`Records/sec: ${stats.recordsPerSecond}`);
|
|
139
|
-
|
|
140
|
-
// Column-level statistics
|
|
141
|
-
for (const [columnName, columnStats] of Object.entries(stats.columnStats)) {
|
|
142
|
-
console.log(`\nColumn: ${columnName}`);
|
|
143
|
-
console.log(` Type: ${columnStats.type}`);
|
|
144
|
-
console.log(` Nulls: ${columnStats.nullCount}`);
|
|
145
|
-
console.log(` Unique: ${columnStats.uniqueValues}`);
|
|
146
|
-
console.log(` Min: ${columnStats.minValue}`);
|
|
147
|
-
console.log(` Max: ${columnStats.maxValue}`);
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Streaming Large Parquet Files
|
|
152
|
-
|
|
153
|
-
### Streaming API
|
|
154
|
-
|
|
155
|
-
For very large Parquet files, use streaming to avoid loading all data into memory:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
async function streamLargeParquet(arrayBuffer: ArrayBuffer) {
|
|
159
|
-
const parser = new ParquetParserService(logger, {
|
|
160
|
-
batchSize: 5000,
|
|
161
|
-
enableStreaming: true,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const streamResult = await parser.parseStreaming(arrayBuffer, 'large_file.parquet', {
|
|
165
|
-
batchSize: 5000,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
let totalProcessed = 0;
|
|
169
|
-
|
|
170
|
-
for await (const batch of streamResult.records) {
|
|
171
|
-
// Process each batch
|
|
172
|
-
for (const record of batch) {
|
|
173
|
-
await processRecord(record);
|
|
174
|
-
totalProcessed++;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
console.log(`Processed ${totalProcessed} records so far...`);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Get final statistics
|
|
181
|
-
const stats = await streamResult.stats;
|
|
182
|
-
console.log(`\nCompleted: ${stats.totalRecords} total records`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async function processRecord(record: any) {
|
|
186
|
-
// Apply transformations, validations, etc.
|
|
187
|
-
return {
|
|
188
|
-
...record,
|
|
189
|
-
processedAt: new Date().toISOString(),
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Batch Processing
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
async function batchProcessParquet(arrayBuffer: ArrayBuffer) {
|
|
198
|
-
const parser = new ParquetParserService(logger);
|
|
199
|
-
const streamResult = await parser.parseStreaming(arrayBuffer, 'data.parquet', {
|
|
200
|
-
batchSize: 1000,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
const processedBatches = [];
|
|
204
|
-
|
|
205
|
-
for await (const batch of streamResult.records) {
|
|
206
|
-
// Transform entire batch at once
|
|
207
|
-
const transformed = transformBatch(batch);
|
|
208
|
-
|
|
209
|
-
// Validate batch
|
|
210
|
-
const valid = validateBatch(transformed);
|
|
211
|
-
|
|
212
|
-
if (valid) {
|
|
213
|
-
processedBatches.push(transformed);
|
|
214
|
-
|
|
215
|
-
// Write batch to destination
|
|
216
|
-
await writeBatchToS3(transformed);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return processedBatches;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function transformBatch(batch: any[]): any[] {
|
|
224
|
-
return batch.map(record => ({
|
|
225
|
-
sku: record.productRef,
|
|
226
|
-
warehouse: record.locationRef,
|
|
227
|
-
quantity: parseInt(record.qty) || 0,
|
|
228
|
-
status: record.status?.toLowerCase(),
|
|
229
|
-
}));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function validateBatch(batch: any[]): boolean {
|
|
233
|
-
return batch.every(record => record.sku && record.warehouse && record.quantity >= 0);
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Combining Parquet with GraphQL Enrichment
|
|
238
|
-
|
|
239
|
-
### Extract from Parquet, Enrich with GraphQL
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
import {
|
|
243
|
-
createClient,
|
|
244
|
-
S3DataSource,
|
|
245
|
-
ParquetParserService,
|
|
246
|
-
createConsoleLogger,
|
|
247
|
-
toStructuredLogger
|
|
248
|
-
} from '@fluentcommerce/fc-connect-sdk';
|
|
249
|
-
|
|
250
|
-
async function extractAndEnrichFromParquet() {
|
|
251
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
252
|
-
const client = await createClient({ config });
|
|
253
|
-
const s3 = new S3DataSource(
|
|
254
|
-
{
|
|
255
|
-
type: 'S3_PARQUET',
|
|
256
|
-
connectionId: 's3-parquet-extract',
|
|
257
|
-
name: 'S3 Parquet Extract',
|
|
258
|
-
s3Config: s3Config,
|
|
259
|
-
},
|
|
260
|
-
logger
|
|
261
|
-
);
|
|
262
|
-
const parser = new ParquetParserService(logger);
|
|
263
|
-
|
|
264
|
-
// Step 1: Load Parquet file from S3
|
|
265
|
-
const buffer = await s3.downloadFile('inventory.parquet', { encoding: 'binary' });
|
|
266
|
-
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
267
|
-
|
|
268
|
-
const { records } = await parser.parse(arrayBuffer, 'inventory.parquet');
|
|
269
|
-
logger.info(`Loaded ${records.length} records from Parquet`);
|
|
270
|
-
|
|
271
|
-
// Step 2: Enrich with GraphQL data
|
|
272
|
-
const enriched = await enrichWithProductDetails(client, records);
|
|
273
|
-
logger.info(`Enriched ${enriched.length} records`);
|
|
274
|
-
|
|
275
|
-
return enriched;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
async function enrichWithProductDetails(client: any, records: any[]) {
|
|
279
|
-
const batchSize = 50;
|
|
280
|
-
const enriched = [];
|
|
281
|
-
|
|
282
|
-
for (let i = 0; i < records.length; i += batchSize) {
|
|
283
|
-
const batch = records.slice(i, i + batchSize);
|
|
284
|
-
const productRefs = batch.map(r => r.productRef);
|
|
285
|
-
|
|
286
|
-
// Batch query for product details
|
|
287
|
-
const result = await client.graphql({
|
|
288
|
-
query: `
|
|
289
|
-
query GetProducts($refs: [String!]!) {
|
|
290
|
-
products(filter: { ref: { in: $refs } }, first: ${batchSize}) {
|
|
291
|
-
edges {
|
|
292
|
-
node {
|
|
293
|
-
ref
|
|
294
|
-
name
|
|
295
|
-
gtin
|
|
296
|
-
catalogue { ref name }
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
`,
|
|
302
|
-
variables: { refs: productRefs },
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// Map products to records
|
|
306
|
-
const productMap = new Map(result.data.products.edges.map(e => [e.node.ref, e.node]));
|
|
307
|
-
|
|
308
|
-
for (const record of batch) {
|
|
309
|
-
enriched.push({
|
|
310
|
-
...record,
|
|
311
|
-
product: productMap.get(record.productRef) || null,
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return enriched;
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### Complete Workflow Example
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
async function parquetToJsonWorkflow() {
|
|
324
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
325
|
-
const client = await createClient({ config });
|
|
326
|
-
const sourceS3 = new S3DataSource(
|
|
327
|
-
{
|
|
328
|
-
type: 'S3_PARQUET',
|
|
329
|
-
connectionId: 's3-source-parquet',
|
|
330
|
-
name: 'S3 Source Parquet',
|
|
331
|
-
s3Config: sourceConfig,
|
|
332
|
-
},
|
|
333
|
-
logger
|
|
334
|
-
);
|
|
335
|
-
const targetS3 = new S3DataSource(
|
|
336
|
-
{
|
|
337
|
-
type: 'S3_JSON',
|
|
338
|
-
connectionId: 's3-target-json',
|
|
339
|
-
name: 'S3 Target JSON',
|
|
340
|
-
s3Config: targetConfig,
|
|
341
|
-
},
|
|
342
|
-
logger
|
|
343
|
-
);
|
|
344
|
-
const parser = new ParquetParserService(logger);
|
|
345
|
-
|
|
346
|
-
// Load all Parquet files
|
|
347
|
-
const files = await sourceS3.listFiles({ prefix: 'exports/' });
|
|
348
|
-
logger.info(`Found ${files.length} Parquet files`);
|
|
349
|
-
|
|
350
|
-
for (const file of files) {
|
|
351
|
-
if (!file.path.endsWith('.parquet')) continue;
|
|
352
|
-
|
|
353
|
-
logger.info(`Processing ${file.path}...`);
|
|
354
|
-
|
|
355
|
-
// Load and parse
|
|
356
|
-
const buffer = await sourceS3.downloadFile(file.path, { encoding: 'binary' }) as Buffer;
|
|
357
|
-
const arrayBuffer = buffer.buffer.slice(
|
|
358
|
-
buffer.byteOffset,
|
|
359
|
-
buffer.byteOffset + buffer.byteLength
|
|
360
|
-
);
|
|
361
|
-
const { records } = await parser.parse(arrayBuffer, file.path);
|
|
362
|
-
|
|
363
|
-
// Enrich
|
|
364
|
-
const enriched = await enrichWithProductDetails(client, records);
|
|
365
|
-
|
|
366
|
-
// Transform (flatten structure)
|
|
367
|
-
const transformed = enriched.map(record => ({
|
|
368
|
-
sku: record.productRef,
|
|
369
|
-
productName: record.product?.name || 'Unknown',
|
|
370
|
-
warehouse: record.locationRef,
|
|
371
|
-
quantity: parseInt(record.qty) || 0,
|
|
372
|
-
status: record.status?.toLowerCase(),
|
|
373
|
-
lastUpdated: record.updatedOn,
|
|
374
|
-
}));
|
|
375
|
-
|
|
376
|
-
// Export as JSON
|
|
377
|
-
const outputPath = file.path.replace('.parquet', '.json');
|
|
378
|
-
await targetS3.uploadFile(outputPath, JSON.stringify(transformed, null, 2), {
|
|
379
|
-
contentType: 'application/json',
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
logger.info(`Exported ${transformed.length} records to ${outputPath}`);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
## Writing Parquet Files
|
|
388
|
-
|
|
389
|
-
While the SDK focuses on reading Parquet, you can write Parquet using the `parquetjs` library:
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
import { ParquetWriter, ParquetSchema } from 'parquetjs';
|
|
393
|
-
|
|
394
|
-
async function writeParquetFile(records: any[], outputPath: string) {
|
|
395
|
-
// Define schema
|
|
396
|
-
const schema = new ParquetSchema({
|
|
397
|
-
sku: { type: 'UTF8' },
|
|
398
|
-
warehouse: { type: 'UTF8' },
|
|
399
|
-
quantity: { type: 'INT32' },
|
|
400
|
-
status: { type: 'UTF8' },
|
|
401
|
-
lastUpdated: { type: 'UTF8' },
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
// Create writer
|
|
405
|
-
const writer = await ParquetWriter.openFile(schema, outputPath);
|
|
406
|
-
|
|
407
|
-
// Write records
|
|
408
|
-
for (const record of records) {
|
|
409
|
-
await writer.appendRow(record);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Close file
|
|
413
|
-
await writer.close();
|
|
414
|
-
|
|
415
|
-
console.log(`Wrote ${records.length} records to ${outputPath}`);
|
|
416
|
-
}
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
## Practice Exercise
|
|
420
|
-
|
|
421
|
-
**Goal**: Load inventory from Parquet, enrich with location details, export to JSON
|
|
422
|
-
|
|
423
|
-
**Requirements:**
|
|
424
|
-
|
|
425
|
-
1. Read Parquet file from S3
|
|
426
|
-
2. Validate required columns: `id`, `productRef`, `locationRef`, `qty`
|
|
427
|
-
3. Enrich with location details via GraphQL
|
|
428
|
-
4. Transform to external format
|
|
429
|
-
5. Write to S3 as JSON
|
|
430
|
-
|
|
431
|
-
**Solution:**
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
async function enrichInventoryFromParquet() {
|
|
435
|
-
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
436
|
-
const client = await createClient({ config });
|
|
437
|
-
const s3 = new S3DataSource(
|
|
438
|
-
{
|
|
439
|
-
type: 'S3_PARQUET',
|
|
440
|
-
connectionId: 's3-parquet-enrich',
|
|
441
|
-
name: 'S3 Parquet Enrich',
|
|
442
|
-
s3Config: s3Config,
|
|
443
|
-
},
|
|
444
|
-
logger
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
// Load Parquet
|
|
448
|
-
const buffer = await s3.downloadFile('inventory.parquet', { encoding: 'binary' });
|
|
449
|
-
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
450
|
-
|
|
451
|
-
const { records, stats } = await parser.parse(arrayBuffer, 'inventory.parquet', {
|
|
452
|
-
validation: {
|
|
453
|
-
enabled: true,
|
|
454
|
-
requiredColumns: ['id', 'productRef', 'locationRef', 'qty'],
|
|
455
|
-
},
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
logger.info(`Loaded ${records.length} records`);
|
|
459
|
-
|
|
460
|
-
// Enrich with locations (batch query)
|
|
461
|
-
const locationRefs = [...new Set(records.map(r => r.locationRef))];
|
|
462
|
-
const locationResult = await client.graphql({
|
|
463
|
-
query: `
|
|
464
|
-
query GetLocations($refs: [String!]!) {
|
|
465
|
-
locations(filter: { ref: { in: $refs } }, first: 1000) {
|
|
466
|
-
edges {
|
|
467
|
-
node { ref name type }
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
`,
|
|
472
|
-
variables: { refs: locationRefs },
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
const locationMap = new Map(locationResult.data.locations.edges.map(e => [e.node.ref, e.node]));
|
|
476
|
-
|
|
477
|
-
// Transform
|
|
478
|
-
const transformed = records.map(record => ({
|
|
479
|
-
sku: record.productRef,
|
|
480
|
-
warehouse: record.locationRef,
|
|
481
|
-
warehouseName: locationMap.get(record.locationRef)?.name || 'Unknown',
|
|
482
|
-
warehouseType: locationMap.get(record.locationRef)?.type || 'Unknown',
|
|
483
|
-
quantity: parseInt(record.qty) || 0,
|
|
484
|
-
}));
|
|
485
|
-
|
|
486
|
-
// Export
|
|
487
|
-
await s3.uploadFile('enriched_inventory.json', JSON.stringify(transformed, null, 2), {
|
|
488
|
-
contentType: 'application/json',
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
logger.info('Export complete');
|
|
492
|
-
}
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
## Key Takeaways
|
|
496
|
-
|
|
497
|
-
- 🎯 Use `ParquetParserService` for reading Parquet files
|
|
498
|
-
- 🎯 Convert S3 Buffer to ArrayBuffer before parsing
|
|
499
|
-
- 🎯 Use streaming for large files to avoid memory issues
|
|
500
|
-
- 🎯 Validate Parquet structure with required columns
|
|
501
|
-
- 🎯 Combine Parquet base data with GraphQL enrichment
|
|
502
|
-
- 🎯 Check statistics for data quality insights
|
|
503
|
-
- 🎯 Use batch queries for efficient enrichment
|
|
504
|
-
|
|
505
|
-
## Next Steps
|
|
506
|
-
|
|
507
|
-
Continue to [Module 4: Data Enrichment](./02-core-guides-extraction-04-data-enrichment.md) to learn advanced GraphQL enrichment patterns.
|
|
1
|
+
# Module 3: Parquet Processing
|
|
2
|
+
|
|
3
|
+
**Level:** Intermediate
|
|
4
|
+
**Estimated Time:** 25 minutes
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
This module covers reading and writing Parquet files using the SDK's `ParquetParserService`, including S3 integration, streaming for large files, and validation.
|
|
9
|
+
|
|
10
|
+
## Learning Objectives
|
|
11
|
+
|
|
12
|
+
By the end of this module, you will:
|
|
13
|
+
|
|
14
|
+
- ✅ Read Parquet files from S3 using `ParquetParserService`
|
|
15
|
+
- ✅ Stream large Parquet files with batching
|
|
16
|
+
- ✅ Validate Parquet data and handle statistics
|
|
17
|
+
- ✅ Combine Parquet data with GraphQL enrichment
|
|
18
|
+
- ✅ Write transformed data back to Parquet format
|
|
19
|
+
|
|
20
|
+
## What is Parquet?
|
|
21
|
+
|
|
22
|
+
**Apache Parquet** is a columnar storage format optimized for:
|
|
23
|
+
|
|
24
|
+
- **Analytics workloads**: Efficient column scanning
|
|
25
|
+
- **Compression**: Smaller file sizes
|
|
26
|
+
- **Schema evolution**: Add/remove columns over time
|
|
27
|
+
- **Interoperability**: Supported by Spark, Athena, BigQuery, etc.
|
|
28
|
+
|
|
29
|
+
**Common use cases:**
|
|
30
|
+
|
|
31
|
+
- Data lake storage
|
|
32
|
+
- ETL pipelines
|
|
33
|
+
- Analytics exports
|
|
34
|
+
- Backup archives
|
|
35
|
+
|
|
36
|
+
## Reading Parquet Files
|
|
37
|
+
|
|
38
|
+
### Basic Parquet Reading
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import {
|
|
42
|
+
ParquetParserService,
|
|
43
|
+
createConsoleLogger,
|
|
44
|
+
toStructuredLogger
|
|
45
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
46
|
+
|
|
47
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
48
|
+
const parser = new ParquetParserService(logger);
|
|
49
|
+
|
|
50
|
+
// Parse Parquet file
|
|
51
|
+
const arrayBuffer = ... // Load file into ArrayBuffer
|
|
52
|
+
const { records, stats } = await parser.parse(
|
|
53
|
+
arrayBuffer,
|
|
54
|
+
'inventory.parquet'
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
console.log(`Parsed ${stats.totalRecords} records in ${stats.processingTimeMs}ms`);
|
|
58
|
+
console.log(`Columns: ${Object.keys(stats.columnStats).join(', ')}`);
|
|
59
|
+
|
|
60
|
+
// Process records
|
|
61
|
+
for (const record of records) {
|
|
62
|
+
console.log(record);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Reading from S3
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import {
|
|
70
|
+
S3DataSource,
|
|
71
|
+
ParquetParserService,
|
|
72
|
+
createConsoleLogger,
|
|
73
|
+
toStructuredLogger
|
|
74
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
75
|
+
|
|
76
|
+
async function readParquetFromS3(bucket: string, key: string) {
|
|
77
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
78
|
+
const s3 = new S3DataSource(
|
|
79
|
+
{
|
|
80
|
+
type: 'S3_PARQUET',
|
|
81
|
+
connectionId: 's3-parquet-read',
|
|
82
|
+
name: 'S3 Parquet Read',
|
|
83
|
+
s3Config: {
|
|
84
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
85
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
86
|
+
region: process.env.AWS_REGION!,
|
|
87
|
+
bucket: process.env.S3_BUCKET!,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
logger
|
|
91
|
+
);
|
|
92
|
+
const parser = new ParquetParserService(logger);
|
|
93
|
+
|
|
94
|
+
// Download from S3
|
|
95
|
+
const buffer = await s3.downloadFile(key, { encoding: 'binary' });
|
|
96
|
+
|
|
97
|
+
// Convert Buffer to ArrayBuffer
|
|
98
|
+
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
99
|
+
|
|
100
|
+
// Parse Parquet
|
|
101
|
+
const { records, stats } = await parser.parse(arrayBuffer, key);
|
|
102
|
+
|
|
103
|
+
console.log(`Loaded ${records.length} records from s3://${bucket}/${key}`);
|
|
104
|
+
|
|
105
|
+
return records;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Usage
|
|
109
|
+
const records = await readParquetFromS3('my-bucket', 'exports/inventory.parquet');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Parquet Validation
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const { records, stats } = await parser.parse(arrayBuffer, 'inventory.parquet', {
|
|
116
|
+
validation: {
|
|
117
|
+
enabled: true,
|
|
118
|
+
requiredColumns: ['id', 'ref', 'productRef', 'qty'],
|
|
119
|
+
allowExtraColumns: true,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Check for validation errors
|
|
124
|
+
if (stats.validationErrors && stats.validationErrors.length > 0) {
|
|
125
|
+
console.error('Validation errors:', stats.validationErrors);
|
|
126
|
+
throw new Error('Parquet validation failed');
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Understanding Parquet Statistics
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const { records, stats } = await parser.parse(arrayBuffer, 'data.parquet');
|
|
134
|
+
|
|
135
|
+
console.log('=== Parquet Statistics ===');
|
|
136
|
+
console.log(`Total records: ${stats.totalRecords}`);
|
|
137
|
+
console.log(`Processing time: ${stats.processingTimeMs}ms`);
|
|
138
|
+
console.log(`Records/sec: ${stats.recordsPerSecond}`);
|
|
139
|
+
|
|
140
|
+
// Column-level statistics
|
|
141
|
+
for (const [columnName, columnStats] of Object.entries(stats.columnStats)) {
|
|
142
|
+
console.log(`\nColumn: ${columnName}`);
|
|
143
|
+
console.log(` Type: ${columnStats.type}`);
|
|
144
|
+
console.log(` Nulls: ${columnStats.nullCount}`);
|
|
145
|
+
console.log(` Unique: ${columnStats.uniqueValues}`);
|
|
146
|
+
console.log(` Min: ${columnStats.minValue}`);
|
|
147
|
+
console.log(` Max: ${columnStats.maxValue}`);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Streaming Large Parquet Files
|
|
152
|
+
|
|
153
|
+
### Streaming API
|
|
154
|
+
|
|
155
|
+
For very large Parquet files, use streaming to avoid loading all data into memory:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
async function streamLargeParquet(arrayBuffer: ArrayBuffer) {
|
|
159
|
+
const parser = new ParquetParserService(logger, {
|
|
160
|
+
batchSize: 5000,
|
|
161
|
+
enableStreaming: true,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const streamResult = await parser.parseStreaming(arrayBuffer, 'large_file.parquet', {
|
|
165
|
+
batchSize: 5000,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
let totalProcessed = 0;
|
|
169
|
+
|
|
170
|
+
for await (const batch of streamResult.records) {
|
|
171
|
+
// Process each batch
|
|
172
|
+
for (const record of batch) {
|
|
173
|
+
await processRecord(record);
|
|
174
|
+
totalProcessed++;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
console.log(`Processed ${totalProcessed} records so far...`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Get final statistics
|
|
181
|
+
const stats = await streamResult.stats;
|
|
182
|
+
console.log(`\nCompleted: ${stats.totalRecords} total records`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function processRecord(record: any) {
|
|
186
|
+
// Apply transformations, validations, etc.
|
|
187
|
+
return {
|
|
188
|
+
...record,
|
|
189
|
+
processedAt: new Date().toISOString(),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Batch Processing
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
async function batchProcessParquet(arrayBuffer: ArrayBuffer) {
|
|
198
|
+
const parser = new ParquetParserService(logger);
|
|
199
|
+
const streamResult = await parser.parseStreaming(arrayBuffer, 'data.parquet', {
|
|
200
|
+
batchSize: 1000,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const processedBatches = [];
|
|
204
|
+
|
|
205
|
+
for await (const batch of streamResult.records) {
|
|
206
|
+
// Transform entire batch at once
|
|
207
|
+
const transformed = transformBatch(batch);
|
|
208
|
+
|
|
209
|
+
// Validate batch
|
|
210
|
+
const valid = validateBatch(transformed);
|
|
211
|
+
|
|
212
|
+
if (valid) {
|
|
213
|
+
processedBatches.push(transformed);
|
|
214
|
+
|
|
215
|
+
// Write batch to destination
|
|
216
|
+
await writeBatchToS3(transformed);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return processedBatches;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function transformBatch(batch: any[]): any[] {
|
|
224
|
+
return batch.map(record => ({
|
|
225
|
+
sku: record.productRef,
|
|
226
|
+
warehouse: record.locationRef,
|
|
227
|
+
quantity: parseInt(record.qty) || 0,
|
|
228
|
+
status: record.status?.toLowerCase(),
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function validateBatch(batch: any[]): boolean {
|
|
233
|
+
return batch.every(record => record.sku && record.warehouse && record.quantity >= 0);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Combining Parquet with GraphQL Enrichment
|
|
238
|
+
|
|
239
|
+
### Extract from Parquet, Enrich with GraphQL
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import {
|
|
243
|
+
createClient,
|
|
244
|
+
S3DataSource,
|
|
245
|
+
ParquetParserService,
|
|
246
|
+
createConsoleLogger,
|
|
247
|
+
toStructuredLogger
|
|
248
|
+
} from '@fluentcommerce/fc-connect-sdk';
|
|
249
|
+
|
|
250
|
+
async function extractAndEnrichFromParquet() {
|
|
251
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
252
|
+
const client = await createClient({ config });
|
|
253
|
+
const s3 = new S3DataSource(
|
|
254
|
+
{
|
|
255
|
+
type: 'S3_PARQUET',
|
|
256
|
+
connectionId: 's3-parquet-extract',
|
|
257
|
+
name: 'S3 Parquet Extract',
|
|
258
|
+
s3Config: s3Config,
|
|
259
|
+
},
|
|
260
|
+
logger
|
|
261
|
+
);
|
|
262
|
+
const parser = new ParquetParserService(logger);
|
|
263
|
+
|
|
264
|
+
// Step 1: Load Parquet file from S3
|
|
265
|
+
const buffer = await s3.downloadFile('inventory.parquet', { encoding: 'binary' });
|
|
266
|
+
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
267
|
+
|
|
268
|
+
const { records } = await parser.parse(arrayBuffer, 'inventory.parquet');
|
|
269
|
+
logger.info(`Loaded ${records.length} records from Parquet`);
|
|
270
|
+
|
|
271
|
+
// Step 2: Enrich with GraphQL data
|
|
272
|
+
const enriched = await enrichWithProductDetails(client, records);
|
|
273
|
+
logger.info(`Enriched ${enriched.length} records`);
|
|
274
|
+
|
|
275
|
+
return enriched;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function enrichWithProductDetails(client: any, records: any[]) {
|
|
279
|
+
const batchSize = 50;
|
|
280
|
+
const enriched = [];
|
|
281
|
+
|
|
282
|
+
for (let i = 0; i < records.length; i += batchSize) {
|
|
283
|
+
const batch = records.slice(i, i + batchSize);
|
|
284
|
+
const productRefs = batch.map(r => r.productRef);
|
|
285
|
+
|
|
286
|
+
// Batch query for product details
|
|
287
|
+
const result = await client.graphql({
|
|
288
|
+
query: `
|
|
289
|
+
query GetProducts($refs: [String!]!) {
|
|
290
|
+
products(filter: { ref: { in: $refs } }, first: ${batchSize}) {
|
|
291
|
+
edges {
|
|
292
|
+
node {
|
|
293
|
+
ref
|
|
294
|
+
name
|
|
295
|
+
gtin
|
|
296
|
+
catalogue { ref name }
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
`,
|
|
302
|
+
variables: { refs: productRefs },
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Map products to records
|
|
306
|
+
const productMap = new Map(result.data.products.edges.map(e => [e.node.ref, e.node]));
|
|
307
|
+
|
|
308
|
+
for (const record of batch) {
|
|
309
|
+
enriched.push({
|
|
310
|
+
...record,
|
|
311
|
+
product: productMap.get(record.productRef) || null,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return enriched;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Complete Workflow Example
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
async function parquetToJsonWorkflow() {
|
|
324
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
325
|
+
const client = await createClient({ config });
|
|
326
|
+
const sourceS3 = new S3DataSource(
|
|
327
|
+
{
|
|
328
|
+
type: 'S3_PARQUET',
|
|
329
|
+
connectionId: 's3-source-parquet',
|
|
330
|
+
name: 'S3 Source Parquet',
|
|
331
|
+
s3Config: sourceConfig,
|
|
332
|
+
},
|
|
333
|
+
logger
|
|
334
|
+
);
|
|
335
|
+
const targetS3 = new S3DataSource(
|
|
336
|
+
{
|
|
337
|
+
type: 'S3_JSON',
|
|
338
|
+
connectionId: 's3-target-json',
|
|
339
|
+
name: 'S3 Target JSON',
|
|
340
|
+
s3Config: targetConfig,
|
|
341
|
+
},
|
|
342
|
+
logger
|
|
343
|
+
);
|
|
344
|
+
const parser = new ParquetParserService(logger);
|
|
345
|
+
|
|
346
|
+
// Load all Parquet files
|
|
347
|
+
const files = await sourceS3.listFiles({ prefix: 'exports/' });
|
|
348
|
+
logger.info(`Found ${files.length} Parquet files`);
|
|
349
|
+
|
|
350
|
+
for (const file of files) {
|
|
351
|
+
if (!file.path.endsWith('.parquet')) continue;
|
|
352
|
+
|
|
353
|
+
logger.info(`Processing ${file.path}...`);
|
|
354
|
+
|
|
355
|
+
// Load and parse
|
|
356
|
+
const buffer = await sourceS3.downloadFile(file.path, { encoding: 'binary' }) as Buffer;
|
|
357
|
+
const arrayBuffer = buffer.buffer.slice(
|
|
358
|
+
buffer.byteOffset,
|
|
359
|
+
buffer.byteOffset + buffer.byteLength
|
|
360
|
+
);
|
|
361
|
+
const { records } = await parser.parse(arrayBuffer, file.path);
|
|
362
|
+
|
|
363
|
+
// Enrich
|
|
364
|
+
const enriched = await enrichWithProductDetails(client, records);
|
|
365
|
+
|
|
366
|
+
// Transform (flatten structure)
|
|
367
|
+
const transformed = enriched.map(record => ({
|
|
368
|
+
sku: record.productRef,
|
|
369
|
+
productName: record.product?.name || 'Unknown',
|
|
370
|
+
warehouse: record.locationRef,
|
|
371
|
+
quantity: parseInt(record.qty) || 0,
|
|
372
|
+
status: record.status?.toLowerCase(),
|
|
373
|
+
lastUpdated: record.updatedOn,
|
|
374
|
+
}));
|
|
375
|
+
|
|
376
|
+
// Export as JSON
|
|
377
|
+
const outputPath = file.path.replace('.parquet', '.json');
|
|
378
|
+
await targetS3.uploadFile(outputPath, JSON.stringify(transformed, null, 2), {
|
|
379
|
+
contentType: 'application/json',
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
logger.info(`Exported ${transformed.length} records to ${outputPath}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Writing Parquet Files
|
|
388
|
+
|
|
389
|
+
While the SDK focuses on reading Parquet, you can write Parquet using the `parquetjs` library:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import { ParquetWriter, ParquetSchema } from 'parquetjs';
|
|
393
|
+
|
|
394
|
+
async function writeParquetFile(records: any[], outputPath: string) {
|
|
395
|
+
// Define schema
|
|
396
|
+
const schema = new ParquetSchema({
|
|
397
|
+
sku: { type: 'UTF8' },
|
|
398
|
+
warehouse: { type: 'UTF8' },
|
|
399
|
+
quantity: { type: 'INT32' },
|
|
400
|
+
status: { type: 'UTF8' },
|
|
401
|
+
lastUpdated: { type: 'UTF8' },
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Create writer
|
|
405
|
+
const writer = await ParquetWriter.openFile(schema, outputPath);
|
|
406
|
+
|
|
407
|
+
// Write records
|
|
408
|
+
for (const record of records) {
|
|
409
|
+
await writer.appendRow(record);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Close file
|
|
413
|
+
await writer.close();
|
|
414
|
+
|
|
415
|
+
console.log(`Wrote ${records.length} records to ${outputPath}`);
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Practice Exercise
|
|
420
|
+
|
|
421
|
+
**Goal**: Load inventory from Parquet, enrich with location details, export to JSON
|
|
422
|
+
|
|
423
|
+
**Requirements:**
|
|
424
|
+
|
|
425
|
+
1. Read Parquet file from S3
|
|
426
|
+
2. Validate required columns: `id`, `productRef`, `locationRef`, `qty`
|
|
427
|
+
3. Enrich with location details via GraphQL
|
|
428
|
+
4. Transform to external format
|
|
429
|
+
5. Write to S3 as JSON
|
|
430
|
+
|
|
431
|
+
**Solution:**
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
async function enrichInventoryFromParquet() {
|
|
435
|
+
const logger = toStructuredLogger(createConsoleLogger(), { logLevel: 'info' });
|
|
436
|
+
const client = await createClient({ config });
|
|
437
|
+
const s3 = new S3DataSource(
|
|
438
|
+
{
|
|
439
|
+
type: 'S3_PARQUET',
|
|
440
|
+
connectionId: 's3-parquet-enrich',
|
|
441
|
+
name: 'S3 Parquet Enrich',
|
|
442
|
+
s3Config: s3Config,
|
|
443
|
+
},
|
|
444
|
+
logger
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
// Load Parquet
|
|
448
|
+
const buffer = await s3.downloadFile('inventory.parquet', { encoding: 'binary' });
|
|
449
|
+
const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
450
|
+
|
|
451
|
+
const { records, stats } = await parser.parse(arrayBuffer, 'inventory.parquet', {
|
|
452
|
+
validation: {
|
|
453
|
+
enabled: true,
|
|
454
|
+
requiredColumns: ['id', 'productRef', 'locationRef', 'qty'],
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
logger.info(`Loaded ${records.length} records`);
|
|
459
|
+
|
|
460
|
+
// Enrich with locations (batch query)
|
|
461
|
+
const locationRefs = [...new Set(records.map(r => r.locationRef))];
|
|
462
|
+
const locationResult = await client.graphql({
|
|
463
|
+
query: `
|
|
464
|
+
query GetLocations($refs: [String!]!) {
|
|
465
|
+
locations(filter: { ref: { in: $refs } }, first: 1000) {
|
|
466
|
+
edges {
|
|
467
|
+
node { ref name type }
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
`,
|
|
472
|
+
variables: { refs: locationRefs },
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
const locationMap = new Map(locationResult.data.locations.edges.map(e => [e.node.ref, e.node]));
|
|
476
|
+
|
|
477
|
+
// Transform
|
|
478
|
+
const transformed = records.map(record => ({
|
|
479
|
+
sku: record.productRef,
|
|
480
|
+
warehouse: record.locationRef,
|
|
481
|
+
warehouseName: locationMap.get(record.locationRef)?.name || 'Unknown',
|
|
482
|
+
warehouseType: locationMap.get(record.locationRef)?.type || 'Unknown',
|
|
483
|
+
quantity: parseInt(record.qty) || 0,
|
|
484
|
+
}));
|
|
485
|
+
|
|
486
|
+
// Export
|
|
487
|
+
await s3.uploadFile('enriched_inventory.json', JSON.stringify(transformed, null, 2), {
|
|
488
|
+
contentType: 'application/json',
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
logger.info('Export complete');
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Key Takeaways
|
|
496
|
+
|
|
497
|
+
- 🎯 Use `ParquetParserService` for reading Parquet files
|
|
498
|
+
- 🎯 Convert S3 Buffer to ArrayBuffer before parsing
|
|
499
|
+
- 🎯 Use streaming for large files to avoid memory issues
|
|
500
|
+
- 🎯 Validate Parquet structure with required columns
|
|
501
|
+
- 🎯 Combine Parquet base data with GraphQL enrichment
|
|
502
|
+
- 🎯 Check statistics for data quality insights
|
|
503
|
+
- 🎯 Use batch queries for efficient enrichment
|
|
504
|
+
|
|
505
|
+
## Next Steps
|
|
506
|
+
|
|
507
|
+
Continue to [Module 4: Data Enrichment](./02-core-guides-extraction-04-data-enrichment.md) to learn advanced GraphQL enrichment patterns.
|