@stilyng94/athena-query-client 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/demo.js CHANGED
@@ -1,15 +1,32 @@
1
- import { AthenaQueryClient } from "./athena.js";
2
- const client = new AthenaQueryClient({
3
- Catalog: "",
4
- s3OutputLocation: "s3://sjka/s",
5
- s3Region: "us-east-1",
6
- Database: "",
7
- ClientConfig: {
8
- region: "us-east-1",
9
- },
10
- });
11
- client
12
- .query("select * from db")
13
- .then((d) => console.log(d))
14
- .then((e) => console.error({ e }));
1
+ import { DemoS3QueryResultProcessor } from "./demo.processor.js";
2
+ import { JsonFileAppender } from "./json-file-appender.js";
3
+ import { processToJson } from "./utils.js";
4
+ const execute = async () => {
5
+ const fileNamesSet = new Set();
6
+ const s3QueryResultProcessor = new DemoS3QueryResultProcessor({
7
+ s3OutputLocation: "s3://results/queries",
8
+ s3Region: "us-west-2",
9
+ batchSize: 999,
10
+ onData: async (rows) => {
11
+ const fileNames = await processToJson(rows, "conversions");
12
+ // biome-ignore lint/complexity/noForEach: <explanation>
13
+ fileNames.forEach((fileName) => {
14
+ fileNamesSet.add(fileName);
15
+ });
16
+ },
17
+ onComplete: async () => {
18
+ await Promise.all(Array.from(fileNamesSet).map((fileName) => {
19
+ const jsonFileAppender = new JsonFileAppender({
20
+ fileName,
21
+ directory: "conversions",
22
+ });
23
+ return jsonFileAppender.closeFileWithBracket();
24
+ }));
25
+ },
26
+ });
27
+ s3QueryResultProcessor
28
+ .processResults("094cedb4-8739-4957-81c1-ecf3e4d8c783")
29
+ .catch((error) => console.error(error));
30
+ };
31
+ execute().catch(console.error);
15
32
  //# sourceMappingURL=demo.js.map
package/dist/demo.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC;IACnC,OAAO,EAAE,EAAE;IACX,gBAAgB,EAAE,aAAa;IAC/B,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,EAAE;IACZ,YAAY,EAAE;QACZ,MAAM,EAAE,WAAW;KACpB;CACF,CAAC,CAAC;AACH,MAAM;KACH,KAAK,CAAC,kBAAkB,CAAC;KACzB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAC3B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;IACzB,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,MAAM,sBAAsB,GAAG,IAAI,0BAA0B,CAAC;QAC5D,gBAAgB,EAAE,sBAAsB;QACxC,QAAQ,EAAE,WAAW;QACrB,SAAS,EAAE,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACrB,MAAM,SAAS,GAAG,MAAM,aAAa,CACnC,IASE,EACF,aAAa,CACd,CAAC;YACF,wDAAwD;YACxD,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC7B,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,UAAU,EAAE,KAAK,IAAI,EAAE;YACrB,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACxC,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,CAAC;oBAC5C,QAAQ;oBACR,SAAS,EAAE,aAAa;iBACzB,CAAC,CAAC;gBACH,OAAO,gBAAgB,CAAC,oBAAoB,EAAE,CAAC;YACjD,CAAC,CAAC,CACH,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IACH,sBAAsB;SACnB,cAAc,CAAC,sCAAsC,CAAC;SACtD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { Readable } from "node:stream";
2
+ import { type ResultSet, type Row } from "@aws-sdk/client-athena";
3
+ import { type MappedQueryResultProcessorParams, type QueryResultProcessor, type S3QueryResultProcessorParams } from "./types.js";
4
+ /**
5
+ * Processes Athena query results stored in S3
6
+ */
7
+ export declare class DemoS3QueryResultProcessor implements QueryResultProcessor {
8
+ private readonly config;
9
+ readonly batchSize: number;
10
+ readonly s3OutputLocation: string;
11
+ /**
12
+ * Creates a new S3QueryResultProcessor
13
+ * @param {S3QueryResultProcessorParams} config - Configuration parameters
14
+ */
15
+ constructor(config: S3QueryResultProcessorParams);
16
+ /**
17
+ * Processes query results from S3
18
+ * @param {string} queryExecutionId - The ID of the query execution
19
+ * @returns {Promise<void>} Promise that resolves when processing is complete
20
+ */
21
+ processResults(queryExecutionId: string): Promise<void>;
22
+ /**
23
+ * Processes streaming results from S3
24
+ * @param {Readable} stream - The readable stream of results
25
+ * @returns {Promise<void>} Promise that resolves when processing is complete
26
+ */
27
+ processStreamingResults(stream: Readable): Promise<void>;
28
+ /**
29
+ * Processes a batch of records
30
+ * @param {unknown[]} batch - Array of records to process
31
+ * @returns {Promise<void>} Promise that resolves when batch is processed
32
+ */
33
+ processBatch(batch: unknown[]): Promise<void>;
34
+ /**
35
+ * Validates the batch size configuration
36
+ * @param {number} [batchSize] - The batch size to validate
37
+ * @returns {number} The validated batch size
38
+ * @throws {Error} If batch size exceeds maximum allowed
39
+ */
40
+ validateBatchSize(batchSize?: number): number;
41
+ }
42
+ /**
43
+ * Processes Athena query results by mapping them to objects
44
+ */
45
+ export declare class MappedQueryResultProcessor implements QueryResultProcessor {
46
+ private readonly config;
47
+ /**
48
+ * Creates a new MappedQueryResultProcessor
49
+ * @param {MappedQueryResultProcessorParams} config - Configuration parameters
50
+ */
51
+ constructor(config: MappedQueryResultProcessorParams);
52
+ /**
53
+ * Processes query results by mapping them to objects
54
+ * @param {string} queryExecutionId - The ID of the query execution
55
+ * @returns {Promise<Record<string, string>[]>} Promise resolving to array of mapped objects
56
+ */
57
+ processResults(queryExecutionId: string): Promise<Record<string, string>[]>;
58
+ /**
59
+ * Fetches query results from Athena
60
+ * @param {string} queryExecutionId - The ID of the query execution
61
+ * @returns {Promise<ResultSet>} Promise resolving to Athena ResultSet
62
+ * @throws {Error} If results are empty or undefined
63
+ */
64
+ fetchQueryResults(queryExecutionId: string): Promise<ResultSet>;
65
+ /**
66
+ * Extracts column headers from result rows
67
+ * @param {Row[]} rows - Array of result rows
68
+ * @returns {string[]} Array of header names
69
+ * @throws {Error} If no headers are found
70
+ */
71
+ extractHeaders(rows: Row[]): string[];
72
+ /**
73
+ * Maps a row to an object using column headers as keys
74
+ * @param {Row} row - The row to map
75
+ * @param {string[]} headers - Array of column headers
76
+ * @returns {Record<string, string>} Object with header-value pairs
77
+ */
78
+ mapRowToObject(row: Row, headers: string[]): Record<string, string>;
79
+ /**
80
+ * Extracts Athena ResultSet data into an array of key-value objects
81
+ * Extracts Athena ResultSet data into an array of key-value objects
82
+ * @private
83
+ * @param {ResultSet} resultSet - The ResultSet object returned by Athena
84
+ * @returns {Record<string, string>[]} Array of objects representing query rows
85
+ * @throws {Error} If no headers are found
86
+ */
87
+ extractRows(resultSet: ResultSet): Record<string, string>[];
88
+ }
@@ -0,0 +1,192 @@
1
+ import { createReadStream } from "node:fs";
2
+ import path from "node:path";
3
+ import { cwd } from "node:process";
4
+ import { finished } from "node:stream/promises";
5
+ import { GetQueryResultsCommand, } from "@aws-sdk/client-athena";
6
+ import { parse } from "csv-parse";
7
+ import { MAX_BATCH_SIZE, } from "./types.js";
8
+ /**
9
+ * Processes Athena query results stored in S3
10
+ */
11
+ export class DemoS3QueryResultProcessor {
12
+ config;
13
+ batchSize = MAX_BATCH_SIZE;
14
+ s3OutputLocation;
15
+ /**
16
+ * Creates a new S3QueryResultProcessor
17
+ * @param {S3QueryResultProcessorParams} config - Configuration parameters
18
+ */
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.batchSize = this.validateBatchSize(config.batchSize);
22
+ this.s3OutputLocation = config.s3OutputLocation;
23
+ }
24
+ /**
25
+ * Processes query results from S3
26
+ * @param {string} queryExecutionId - The ID of the query execution
27
+ * @returns {Promise<void>} Promise that resolves when processing is complete
28
+ */
29
+ async processResults(queryExecutionId) {
30
+ console.log("Fetching query results from S3:", queryExecutionId);
31
+ const responseStream = createReadStream(path.join(cwd(), "athena.csv"));
32
+ return this.processStreamingResults(responseStream);
33
+ }
34
+ /**
35
+ * Processes streaming results from S3
36
+ * @param {Readable} stream - The readable stream of results
37
+ * @returns {Promise<void>} Promise that resolves when processing is complete
38
+ */
39
+ async processStreamingResults(stream) {
40
+ const batch = [];
41
+ let totalProcessed = 0;
42
+ const parser = stream.pipe(parse({ ...(this.config.csvParseOptions ?? { columns: true }) }));
43
+ try {
44
+ parser.on("readable", async () => {
45
+ let record = parser.read();
46
+ while (record !== null) {
47
+ // Work with each record
48
+ batch.push(record);
49
+ if (batch.length >= this.batchSize) {
50
+ console.log(`Processing batch of ${batch.length} records...`);
51
+ await this.processBatch(batch);
52
+ totalProcessed += batch.length;
53
+ batch.length = 0; // Clear array efficiently
54
+ console.log(`Total records processed: ${totalProcessed}`);
55
+ }
56
+ record = parser.read();
57
+ }
58
+ });
59
+ // Wait for parsing to complete
60
+ await finished(parser);
61
+ // Process remaining records
62
+ if (batch.length > 0) {
63
+ console.log(`Processing final batch of ${batch.length} records...`);
64
+ await this.processBatch(batch);
65
+ totalProcessed += batch.length;
66
+ console.log(`Final total records processed: ${totalProcessed}`);
67
+ }
68
+ await this.config?.onComplete?.();
69
+ }
70
+ catch (error) {
71
+ throw new Error(`Error processing results: ${error instanceof Error ? error.message : "Unknown error"}`);
72
+ }
73
+ }
74
+ /**
75
+ * Processes a batch of records
76
+ * @param {unknown[]} batch - Array of records to process
77
+ * @returns {Promise<void>} Promise that resolves when batch is processed
78
+ */
79
+ async processBatch(batch) {
80
+ try {
81
+ await this.config.onData(batch);
82
+ }
83
+ catch (error) {
84
+ throw new Error(`Error processing batch: ${error instanceof Error ? error.message : "Unknown error"}`);
85
+ }
86
+ }
87
+ /**
88
+ * Validates the batch size configuration
89
+ * @param {number} [batchSize] - The batch size to validate
90
+ * @returns {number} The validated batch size
91
+ * @throws {Error} If batch size exceeds maximum allowed
92
+ */
93
+ validateBatchSize(batchSize) {
94
+ if (!batchSize)
95
+ return MAX_BATCH_SIZE;
96
+ if (batchSize > MAX_BATCH_SIZE) {
97
+ throw new Error(`Batch size cannot be greater than ${MAX_BATCH_SIZE}`);
98
+ }
99
+ return batchSize;
100
+ }
101
+ }
102
+ /**
103
+ * Processes Athena query results by mapping them to objects
104
+ */
105
+ export class MappedQueryResultProcessor {
106
+ config;
107
+ /**
108
+ * Creates a new MappedQueryResultProcessor
109
+ * @param {MappedQueryResultProcessorParams} config - Configuration parameters
110
+ */
111
+ constructor(config) {
112
+ this.config = config;
113
+ }
114
+ /**
115
+ * Processes query results by mapping them to objects
116
+ * @param {string} queryExecutionId - The ID of the query execution
117
+ * @returns {Promise<Record<string, string>[]>} Promise resolving to array of mapped objects
118
+ */
119
+ async processResults(queryExecutionId) {
120
+ console.log("Fetching results for QueryExecutionId:", queryExecutionId);
121
+ try {
122
+ const resultSet = await this.fetchQueryResults(queryExecutionId);
123
+ return this.extractRows(resultSet);
124
+ }
125
+ catch (error) {
126
+ throw new Error(`Error processing results: ${error instanceof Error ? error.message : "Unknown error"}`);
127
+ }
128
+ }
129
+ /**
130
+ * Fetches query results from Athena
131
+ * @param {string} queryExecutionId - The ID of the query execution
132
+ * @returns {Promise<ResultSet>} Promise resolving to Athena ResultSet
133
+ * @throws {Error} If results are empty or undefined
134
+ */
135
+ async fetchQueryResults(queryExecutionId) {
136
+ const response = await this.config.athenaClient.send(new GetQueryResultsCommand({ QueryExecutionId: queryExecutionId }));
137
+ if (!response.ResultSet) {
138
+ throw new Error("Query results are empty or undefined");
139
+ }
140
+ return response.ResultSet;
141
+ }
142
+ /**
143
+ * Extracts column headers from result rows
144
+ * @param {Row[]} rows - Array of result rows
145
+ * @returns {string[]} Array of header names
146
+ * @throws {Error} If no headers are found
147
+ */
148
+ extractHeaders(rows) {
149
+ const headers = rows[0]?.Data?.map((column) => column.VarCharValue || "");
150
+ if (!headers || headers.length === 0) {
151
+ throw new Error("No headers found in the result set");
152
+ }
153
+ return headers;
154
+ }
155
+ /**
156
+ * Maps a row to an object using column headers as keys
157
+ * @param {Row} row - The row to map
158
+ * @param {string[]} headers - Array of column headers
159
+ * @returns {Record<string, string>} Object with header-value pairs
160
+ */
161
+ mapRowToObject(row, headers) {
162
+ const mappedRow = {};
163
+ row.Data?.forEach((value, index) => {
164
+ const header = headers[index];
165
+ if (header) {
166
+ mappedRow[header] = value.VarCharValue || "";
167
+ }
168
+ });
169
+ return mappedRow;
170
+ }
171
+ /**
172
+ * Extracts Athena ResultSet data into an array of key-value objects
173
+ * Extracts Athena ResultSet data into an array of key-value objects
174
+ * @private
175
+ * @param {ResultSet} resultSet - The ResultSet object returned by Athena
176
+ * @returns {Record<string, string>[]} Array of objects representing query rows
177
+ * @throws {Error} If no headers are found
178
+ */
179
+ extractRows(resultSet) {
180
+ const { Rows } = resultSet;
181
+ if (!Rows || Rows.length === 0) {
182
+ console.error("No rows found in result set");
183
+ return [];
184
+ }
185
+ const headers = this.extractHeaders(Rows);
186
+ if (!headers.length) {
187
+ throw new Error("No headers found in the result set");
188
+ }
189
+ return Rows.slice(1).map((row) => this.mapRowToObject(row, headers));
190
+ }
191
+ }
192
+ //# sourceMappingURL=demo.processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo.processor.js","sourceRoot":"","sources":["../src/demo.processor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EACL,sBAAsB,GAGvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,cAAc,GAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC;;GAEG;AACH,MAAM,OAAO,0BAA0B;IAQR;IAPpB,SAAS,GAAG,cAAc,CAAC;IAC3B,gBAAgB,CAAS;IAElC;;;OAGG;IACH,YAA6B,MAAoC;QAApC,WAAM,GAAN,MAAM,CAA8B;QAC/D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,cAAc,CAAC,gBAAwB;QAC3C,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,gBAAgB,CAAC,CAAC;QAEjE,MAAM,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,uBAAuB,CAAC,cAAc,CAAC,CAAC;IACtD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,uBAAuB,CAAC,MAAgB;QAC5C,MAAM,KAAK,GAAc,EAAE,CAAC;QAC5B,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CACxB,KAAK,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CACjE,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;gBAC/B,IAAI,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC3B,OAAO,MAAM,KAAK,IAAI,EAAE,CAAC;oBACvB,wBAAwB;oBACxB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACnB,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;wBACnC,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;wBAC9D,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;wBAC/B,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;wBAC/B,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,0BAA0B;wBAC5C,OAAO,CAAC,GAAG,CAAC,4BAA4B,cAAc,EAAE,CAAC,CAAC;oBAC5D,CAAC;oBACD,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBACzB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,+BAA+B;YAC/B,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;YACvB,4BAA4B;YAC5B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;gBACpE,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC/B,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,kCAAkC,cAAc,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,6BACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,KAAgB;QACjC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,2BACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CAAC,SAAkB;QAClC,IAAI,CAAC,SAAS;YAAE,OAAO,cAAc,CAAC;QACtC,IAAI,SAAS,GAAG,cAAc,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,qCAAqC,cAAc,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,0BAA0B;IAKR;IAJ7B;;;OAGG;IACH,YAA6B,MAAwC;QAAxC,WAAM,GAAN,MAAM,CAAkC;IAAG,CAAC;IAEzE;;;;OAIG;IACH,KAAK,CAAC,cAAc,CAClB,gBAAwB;QAExB,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE,gBAAgB,CAAC,CAAC;QAExE,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,6BACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,iBAAiB,CAAC,gBAAwB;QAC9C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAClD,IAAI,sBAAsB,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC,CACnE,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,QAAQ,CAAC,SAAS,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,IAAW;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAE1E,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,GAAQ,EAAE,OAAiB;QACxC,MAAM,SAAS,GAA2B,EAAE,CAAC;QAE7C,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACjC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,MAAM,EAAE,CAAC;gBACX,SAAS,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;OAOG;IACH,WAAW,CAAC,SAAoB;QAC9B,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,CAAC;CACF"}
@@ -2,7 +2,17 @@ import { finished } from 'node:stream/promises';
2
2
  import { GetQueryResultsCommand, } from '@aws-sdk/client-athena';
3
3
  import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
4
4
  import { parse } from 'csv-parse';
5
+ import { EMPTY, defer, firstValueFrom, from, of, throwError, timer, } from 'rxjs';
5
6
  import { MAX_BATCH_SIZE, } from './types.js';
7
+ import { catchError, concatWith, expand, filter, switchMap, } from 'rxjs/operators';
8
+ function validateBatchSize(maxBatchSize, batchSize) {
9
+ if (!batchSize)
10
+ return maxBatchSize;
11
+ if (batchSize > maxBatchSize) {
12
+ throw new Error(`Batch size cannot be greater than ${maxBatchSize}`);
13
+ }
14
+ return batchSize;
15
+ }
6
16
  /**
7
17
  * Processes Athena query results stored in S3
8
18
  */
@@ -42,10 +52,10 @@ export class S3QueryResultProcessor {
42
52
  async #processStreamingResults(stream) {
43
53
  const batch = [];
44
54
  let totalProcessed = 0;
45
- const parser = stream.pipe(parse({ ...(this.config.csvParseOptions ?? {}) }));
55
+ const parser = stream.pipe(parse({ columns: true, ...(this.config.csvParseOptions ?? {}) }));
46
56
  try {
47
57
  parser.on('readable', async () => {
48
- const record = parser.read();
58
+ let record = parser.read();
49
59
  while (record !== null) {
50
60
  // Work with each record
51
61
  batch.push(record);
@@ -56,6 +66,7 @@ export class S3QueryResultProcessor {
56
66
  batch.length = 0; // Clear array efficiently
57
67
  console.log(`Total records processed: ${totalProcessed}`);
58
68
  }
69
+ record = parser.read();
59
70
  }
60
71
  });
61
72
  // Wait for parsing to complete
@@ -93,12 +104,7 @@ export class S3QueryResultProcessor {
93
104
  * @throws {Error} If batch size exceeds maximum allowed
94
105
  */
95
106
  #validateBatchSize(batchSize) {
96
- if (!batchSize)
97
- return MAX_BATCH_SIZE;
98
- if (batchSize > MAX_BATCH_SIZE) {
99
- throw new Error(`Batch size cannot be greater than ${MAX_BATCH_SIZE}`);
100
- }
101
- return batchSize;
107
+ return validateBatchSize(this.#batchSize, batchSize);
102
108
  }
103
109
  /**
104
110
  * Fetches an object from S3
@@ -143,12 +149,16 @@ export class S3QueryResultProcessor {
143
149
  */
144
150
  export class MappedQueryResultProcessor {
145
151
  config;
152
+ #batchSize = MAX_BATCH_SIZE;
153
+ #shouldPaginate = true;
146
154
  /**
147
155
  * Creates a new MappedQueryResultProcessor
148
156
  * @param {MappedQueryResultProcessorParams} config - Configuration parameters
149
157
  */
150
158
  constructor(config) {
151
159
  this.config = config;
160
+ this.#batchSize = this.#validateBatchSize(config.MaxResults);
161
+ this.#shouldPaginate = config.paginateResults ?? true;
152
162
  }
153
163
  /**
154
164
  * Processes query results by mapping them to objects
@@ -158,8 +168,8 @@ export class MappedQueryResultProcessor {
158
168
  async processResults(queryExecutionId) {
159
169
  console.log('Fetching results for QueryExecutionId:', queryExecutionId);
160
170
  try {
161
- const resultSet = await this.#fetchQueryResults(queryExecutionId);
162
- return this.#extractRows(resultSet);
171
+ const resultSets = await firstValueFrom(this.#fetchQueryResults(queryExecutionId, undefined));
172
+ return resultSets.flatMap((resultSet) => this.#extractRows(resultSet));
163
173
  }
164
174
  catch (error) {
165
175
  throw new Error(`Error processing results: ${error instanceof Error ? error.message : 'Unknown error'}`);
@@ -168,15 +178,32 @@ export class MappedQueryResultProcessor {
168
178
  /**
169
179
  * Fetches query results from Athena
170
180
  * @param {string} queryExecutionId - The ID of the query execution
171
- * @returns {Promise<ResultSet>} Promise resolving to Athena ResultSet
172
- * @throws {Error} If results are empty or undefined
181
+ * @param {string | undefined} nextToken - The pagination token
182
+ * @returns {Promise<ResultSet[]>} Promise resolving to Athena ResultSet
183
+ * @throws {Error} If results are undefined
173
184
  */
174
- async #fetchQueryResults(queryExecutionId) {
175
- const response = await this.config.athenaClient.send(new GetQueryResultsCommand({ QueryExecutionId: queryExecutionId }));
176
- if (!response.ResultSet) {
177
- throw new Error('Query results are empty or undefined');
178
- }
179
- return response.ResultSet;
185
+ #fetchQueryResults(queryExecutionId, nextToken) {
186
+ return defer(() => from(this.config.athenaClient.send(new GetQueryResultsCommand({
187
+ QueryExecutionId: queryExecutionId,
188
+ MaxResults: this.#batchSize,
189
+ NextToken: nextToken,
190
+ })))).pipe(switchMap((response) => {
191
+ if (!response.ResultSet) {
192
+ return throwError(() => new Error(`Query results are undefined for QueryExecutionId: ${queryExecutionId}`));
193
+ }
194
+ const resultObservable = of(response.ResultSet);
195
+ if (this.#shouldPaginate && response.NextToken) {
196
+ console.log('Fetching next page of results...');
197
+ return resultObservable.pipe(concatWith(of(response.NextToken)));
198
+ }
199
+ console.log('Query results fetching complete');
200
+ return resultObservable; // Only emit the current ResultSet
201
+ }), expand((resultOrNextToken) => typeof resultOrNextToken === 'string' // If it's a NextToken, fetch the next page
202
+ ? timer(500).pipe(switchMap(() => this.#fetchQueryResults(queryExecutionId, resultOrNextToken)))
203
+ : EMPTY), filter((resultOrNextToken) => typeof resultOrNextToken !== 'string'), catchError((error) => {
204
+ console.error(`Error fetching query results for QueryExecutionId: ${queryExecutionId}`, error);
205
+ return throwError(() => new Error(`Failed to fetch query results for QueryExecutionId: ${queryExecutionId}. ${error.message}`));
206
+ }));
180
207
  }
181
208
  /**
182
209
  * Extracts column headers from result rows
@@ -227,5 +254,14 @@ export class MappedQueryResultProcessor {
227
254
  }
228
255
  return Rows.slice(1).map((row) => this.#mapRowToObject(row, headers));
229
256
  }
257
+ /**
258
+ * Validates the batch size configuration
259
+ * @param {number} [batchSize] - The batch size to validate
260
+ * @returns {number} The validated batch size
261
+ * @throws {Error} If batch size exceeds maximum allowed
262
+ */
263
+ #validateBatchSize(batchSize) {
264
+ return validateBatchSize(this.#batchSize, batchSize);
265
+ }
230
266
  }
231
267
  //# sourceMappingURL=query-results-processor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-results-processor.js","sourceRoot":"","sources":["../src/query-results-processor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query-results-processor.js","sourceRoot":"","sources":["../src/query-results-processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ export declare const safeUrlDecode: (value: string) => string;
3
+ export declare const urlEncodedString: (schema: z.ZodString) => z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>;
4
+ export declare const datePreprocessor: z.ZodEffects<z.ZodString, string, unknown>;
5
+ export declare const CsiUriQuerySchema: z.ZodObject<{
6
+ type: z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>;
7
+ siteId: z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>;
8
+ currency: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
9
+ idorder: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
10
+ revenue: z.ZodDefault<z.ZodOptional<z.ZodString>>;
11
+ created_at: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodString, string, unknown>>>;
12
+ shipping: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
13
+ discount: z.ZodDefault<z.ZodOptional<z.ZodString>>;
14
+ referrer: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
15
+ _idv: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
16
+ _id: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
17
+ idsite: z.ZodDefault<z.ZodOptional<z.ZodString>>;
18
+ quicktransaction: z.ZodOptional<z.ZodEnum<["0", "1"]>>;
19
+ agent: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
20
+ audit_key: z.ZodNullable<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>;
21
+ device_type: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
22
+ parent_idv: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>>;
23
+ country: z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>;
24
+ items_count: z.ZodDefault<z.ZodOptional<z.ZodString>>;
25
+ url: z.ZodOptional<z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, unknown>>;
26
+ date: z.ZodOptional<z.ZodEffects<z.ZodString, string, unknown>>;
27
+ }, "strip", z.ZodTypeAny, {
28
+ currency: string;
29
+ idorder: string;
30
+ revenue: string;
31
+ created_at: string;
32
+ shipping: string;
33
+ discount: string;
34
+ referrer: string;
35
+ _idv: string;
36
+ _id: string;
37
+ idsite: string;
38
+ agent: string;
39
+ audit_key: string | null;
40
+ device_type: string;
41
+ parent_idv: string;
42
+ items_count: string;
43
+ type?: string | undefined;
44
+ siteId?: string | undefined;
45
+ quicktransaction?: "0" | "1" | undefined;
46
+ country?: string | undefined;
47
+ url?: string | undefined;
48
+ date?: string | undefined;
49
+ }, {
50
+ type?: unknown;
51
+ siteId?: unknown;
52
+ currency?: unknown;
53
+ idorder?: unknown;
54
+ revenue?: string | undefined;
55
+ created_at?: unknown;
56
+ shipping?: unknown;
57
+ discount?: string | undefined;
58
+ referrer?: unknown;
59
+ _idv?: unknown;
60
+ _id?: unknown;
61
+ idsite?: string | undefined;
62
+ quicktransaction?: "0" | "1" | undefined;
63
+ agent?: unknown;
64
+ audit_key?: unknown;
65
+ device_type?: unknown;
66
+ parent_idv?: unknown;
67
+ country?: unknown;
68
+ items_count?: string | undefined;
69
+ url?: unknown;
70
+ date?: unknown;
71
+ }>;
72
+ export type CsiUriQuery = z.infer<typeof CsiUriQuerySchema>;
package/dist/schema.js ADDED
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ // Helper function to decode URL components safely
3
+ export const safeUrlDecode = (value) => {
4
+ try {
5
+ // Handle different levels of URL encoding
6
+ return decodeURIComponent(decodeURIComponent(value.replace(/\+/g, " ")));
7
+ // biome-ignore lint/correctness/noUnusedVariables: <explanation>
8
+ }
9
+ catch (e) {
10
+ try {
11
+ // Try single decoding if double fails
12
+ return decodeURIComponent(value.replace(/\+/g, " "));
13
+ }
14
+ catch {
15
+ // Return original if both fail
16
+ return value;
17
+ }
18
+ }
19
+ };
20
+ // Create a preprocessor for URL-encoded strings
21
+ export const urlEncodedString = (schema) => z.preprocess((val) => {
22
+ if (typeof val !== "string")
23
+ return val;
24
+ return safeUrlDecode(val);
25
+ }, schema.optional().default(""));
26
+ // Create a preprocessor for dates
27
+ export const datePreprocessor = z.preprocess((val) => {
28
+ if (typeof val !== "string")
29
+ return val;
30
+ const decoded = safeUrlDecode(val);
31
+ try {
32
+ return new Date(decoded).toISOString();
33
+ }
34
+ catch {
35
+ return val;
36
+ }
37
+ }, z.string());
38
+ // Zod schema with all fields optional
39
+ export const CsiUriQuerySchema = z.object({
40
+ type: urlEncodedString(z.string()).optional(),
41
+ siteId: urlEncodedString(z.string().regex(/^\d+$/, "Site ID must be numeric")).optional(),
42
+ currency: urlEncodedString(z.string()).optional().default(""),
43
+ idorder: urlEncodedString(z.string()).optional().default(""),
44
+ revenue: z.string().optional().default(""),
45
+ created_at: datePreprocessor.optional().default(""),
46
+ shipping: urlEncodedString(z.string()).optional().default(""),
47
+ discount: z.string().optional().default(""),
48
+ referrer: urlEncodedString(z.string()).optional().default(""),
49
+ _idv: urlEncodedString(z.string()).optional().default(""),
50
+ _id: urlEncodedString(z.string()).optional().default(""),
51
+ idsite: z.string().optional().default(""),
52
+ quicktransaction: z.enum(["0", "1"]).optional(),
53
+ agent: urlEncodedString(z.string()).optional().default(""),
54
+ audit_key: urlEncodedString(z.string()).nullable(),
55
+ device_type: urlEncodedString(z.string()).optional().default(""),
56
+ parent_idv: urlEncodedString(z.string()).optional().default(""),
57
+ country: urlEncodedString(z.string().length(2, "Country must be a 2-letter code")).optional(),
58
+ items_count: z.string().optional().default(""),
59
+ url: urlEncodedString(z.string().url()).optional(),
60
+ date: datePreprocessor.optional(),
61
+ });
62
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -46,6 +46,7 @@ export interface S3QueryResultProcessorParams {
46
46
  onComplete?: (data?: unknown) => Promise<void>;
47
47
  /**
48
48
  * Optional: The maximum number of records to process in a single batch
49
+ * should be less than or equal to 999
49
50
  * @default 999
50
51
  */
51
52
  batchSize?: number;
@@ -61,9 +62,20 @@ export interface S3QueryResultProcessorParams {
61
62
  }
62
63
  export interface MappedQueryResultProcessorParams {
63
64
  /**
64
- *
65
+ * Athena client for executing queries
65
66
  */
66
67
  athenaClient: AthenaClient;
68
+ /**
69
+ * Optional: Maximum number of records per query
70
+ * should be less than or equal to 999
71
+ * @default 999
72
+ */
73
+ MaxResults?: number;
74
+ /**
75
+ * Should results be paginated. Athena has a limit of 1000 records per query, so this is useful for large datasets
76
+ * @default true
77
+ */
78
+ paginateResults?: boolean;
67
79
  }
68
80
  /**
69
81
  *@description Options for configuring the JsonFileAppender
@@ -0,0 +1,21 @@
1
+ /**
2
+ *@description Interface for mapped data row structure
3
+ */
4
+ interface MappedDataRow {
5
+ partition_date: string;
6
+ hour: string;
7
+ idorder: string;
8
+ idsite: string;
9
+ siteid: string;
10
+ sid: string;
11
+ cs_uri_query: string;
12
+ cs_referer: string;
13
+ }
14
+ /**
15
+ * @description Processes mapped data and writes to JSON files grouped by date
16
+ * @param {MappedDataRow[]} mappedData - Data to be processed
17
+ * @param {string} directory - Output directory for files
18
+ * @returns {Promise<string[]>} Array of created filenames
19
+ */
20
+ export declare function processToJson(mappedData: MappedDataRow[], directory: string): Promise<string[]>;
21
+ export {};
package/dist/utils.js ADDED
@@ -0,0 +1,98 @@
1
+ import { JsonFileAppender } from "./json-file-appender.js";
2
+ import { CsiUriQuerySchema } from "./schema.js";
3
+ /**
4
+ *@description Parses a CSI_URI query string into a structured object
5
+ * @param {string} queryString - The query string to parse
6
+ * @returns {CsiUriQuery} Parsed and validated query object
7
+ */
8
+ const parseCsiUriQuery = (queryString) => {
9
+ const cleanQueryString = queryString
10
+ .replace(/^cs_uri_query:\s*['"]?/, "")
11
+ .replace(/['"]$/, "");
12
+ // Create params object
13
+ const params = {};
14
+ // Split and parse, handling both & and ; separators
15
+ // biome-ignore lint/complexity/noForEach: <explanation>
16
+ cleanQueryString.split(/[&;]/).forEach((param) => {
17
+ const [key, ...values] = param.split("=");
18
+ if (key) {
19
+ // Join values back together in case the value contained = signs
20
+ params[key.trim()] = values.join("=");
21
+ }
22
+ });
23
+ // Validate and return
24
+ const parsed = CsiUriQuerySchema.parse(params);
25
+ return parsed;
26
+ };
27
+ /**
28
+ *@description Converts pixel log data to conversion format
29
+ * @param {MappedDataRow} mappedRow - Raw mapped data
30
+ * @param {CsiUriQuery} csiUriQuery - Parsed URI query parameters
31
+ */
32
+ const pixelLog = (mappedRow, csiUriQuery) => {
33
+ const conversion = {
34
+ created_at: `${new Date(mappedRow.partition_date).toISOString().split("T")[0]} ${mappedRow.hour}:00`,
35
+ date: new Date(mappedRow.partition_date).toISOString().split("T")[0] ?? "",
36
+ idorder: mappedRow.idorder,
37
+ revenue: csiUriQuery.revenue,
38
+ currency: csiUriQuery.currency,
39
+ parent_idv: csiUriQuery._idv,
40
+ _idv: csiUriQuery._idv,
41
+ nginxLogs: true,
42
+ };
43
+ return conversion;
44
+ };
45
+ /**
46
+ * @description Processes mapped data and writes to JSON files grouped by date
47
+ * @param {MappedDataRow[]} mappedData - Data to be processed
48
+ * @param {string} directory - Output directory for files
49
+ * @returns {Promise<string[]>} Array of created filenames
50
+ */
51
+ export async function processToJson(mappedData, directory) {
52
+ console.log(`Processing ${mappedData.length} rows to directory: ${directory}`);
53
+ const fileNames = [];
54
+ try {
55
+ // Group data by date
56
+ const dateGroup = mappedData.reduce((acc, row) => {
57
+ const csiUriQuery = parseCsiUriQuery(row.cs_uri_query);
58
+ const log = pixelLog(row, csiUriQuery);
59
+ // biome-ignore lint/style/noNonNullAssertion: <explanation>
60
+ const date = log.created_at.split(" ")[0];
61
+ // ignore log if idorder is empty or _idv is empty or idv value is undefined or revenue cannot be parsed as number
62
+ if (!log.idorder ||
63
+ log.idorder === "undefined" ||
64
+ !log._idv ||
65
+ log._idv === "undefined" ||
66
+ !log.revenue ||
67
+ Number.isNaN(Number(log.revenue))) {
68
+ return acc;
69
+ }
70
+ if (!acc[date]) {
71
+ acc[date] = [];
72
+ }
73
+ // biome-ignore lint/style/noNonNullAssertion: <explanation>
74
+ acc[date].push(log);
75
+ return acc;
76
+ }, {});
77
+ console.log(`Grouped data into ${Object.keys(dateGroup).length} dates`);
78
+ const jsonFileAppenderPromises = Object.entries(dateGroup).map(async ([date, data]) => {
79
+ const filename = `conversion_${date}.json`;
80
+ console.log(`Processing ${date}: ${data.length} records`);
81
+ fileNames.push(filename);
82
+ const jsonFileAppender = new JsonFileAppender({
83
+ fileName: filename,
84
+ directory: directory,
85
+ });
86
+ await jsonFileAppender.flush(data);
87
+ console.log(`Completed writing ${filename}`);
88
+ });
89
+ await Promise.all(jsonFileAppenderPromises);
90
+ console.log("All files processed successfully");
91
+ return fileNames;
92
+ }
93
+ catch (error) {
94
+ console.error("Error in processToJson:", error);
95
+ process.exit(1);
96
+ }
97
+ }
98
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stilyng94/athena-query-client",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "An Athena client to query data from Athena utilizing Aws-S3 or direct results from Athena query",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,6 +29,7 @@
29
29
  "@aws-sdk/client-athena": "^3.696.0",
30
30
  "@aws-sdk/client-s3": "^3.717.0",
31
31
  "csv-parse": "^5.6.0",
32
+ "pino": "^9.6.0",
32
33
  "rxjs": "^7.8.1"
33
34
  },
34
35
  "devDependencies": {