@tmlmobilidade/writers 20260121.2332.6 → 20260126.1852.36

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.
@@ -95,6 +95,35 @@ export declare class ClickHouseWriter<T> {
95
95
  * @param orderBy The ORDER BY clause for the table (default: tuple())
96
96
  */
97
97
  ensureTable(schema?: ClickHouseColumn<T>[], engine?: string, orderBy?: string): Promise<void>;
98
+ /**
99
+ * Builds a WHERE clause from a filter object.
100
+ * Supports simple equality, range queries ($gte, $lte, $gt, $lt), and $in queries.
101
+ *
102
+ * @param filter Filter object with column names as keys
103
+ * @returns WHERE clause string (without the WHERE keyword)
104
+ */
105
+ private buildWhereClause;
106
+ /**
107
+ * Formats a value for use in a SQL query.
108
+ */
109
+ private formatValue;
110
+ /**
111
+ * Counts the number of documents in the table that match the given filter.
112
+ * Supports simple equality and range queries ($gte, $lte, $gt, $lt).
113
+ *
114
+ * @param filter Optional WHERE clause conditions (e.g., { operational_date: '2024-01-01' } or { received_at: { $gte: 1234567890 } })
115
+ * @returns The count of matching documents
116
+ */
117
+ countDocuments(filter?: Record<string, unknown>): Promise<number>;
118
+ /**
119
+ * Returns distinct values for a given column, optionally filtered.
120
+ * Supports simple equality and range queries ($gte, $lte, $gt, $lt).
121
+ *
122
+ * @param column The column name to get distinct values for
123
+ * @param filter Optional WHERE clause conditions
124
+ * @returns Array of distinct values
125
+ */
126
+ distinct<K = string>(column: string, filter?: Record<string, unknown>): Promise<K[]>;
98
127
  flush(callback?: (data?: T[]) => Promise<void>): Promise<void>;
99
128
  /**
100
129
  * Write data to the ClickHouse table.
@@ -65,6 +65,120 @@ export class ClickHouseWriter {
65
65
  }
66
66
  }
67
67
  /* * */
68
+ /**
69
+ * Builds a WHERE clause from a filter object.
70
+ * Supports simple equality, range queries ($gte, $lte, $gt, $lt), and $in queries.
71
+ *
72
+ * @param filter Filter object with column names as keys
73
+ * @returns WHERE clause string (without the WHERE keyword)
74
+ */
75
+ buildWhereClause(filter) {
76
+ if (!filter || Object.keys(filter).length === 0) {
77
+ return null;
78
+ }
79
+ const conditions = [];
80
+ for (const [key, value] of Object.entries(filter)) {
81
+ if (value === null || value === undefined) {
82
+ continue;
83
+ }
84
+ // Handle range queries (MongoDB-style operators)
85
+ if (typeof value === 'object' && !Array.isArray(value)) {
86
+ const operators = value;
87
+ for (const [op, opValue] of Object.entries(operators)) {
88
+ switch (op) {
89
+ case '$gt':
90
+ conditions.push(`${key} > ${this.formatValue(opValue)}`);
91
+ break;
92
+ case '$gte':
93
+ conditions.push(`${key} >= ${this.formatValue(opValue)}`);
94
+ break;
95
+ case '$in':
96
+ if (Array.isArray(opValue)) {
97
+ const values = opValue.map(v => this.formatValue(v)).join(', ');
98
+ conditions.push(`${key} IN (${values})`);
99
+ }
100
+ break;
101
+ case '$lt':
102
+ conditions.push(`${key} < ${this.formatValue(opValue)}`);
103
+ break;
104
+ case '$lte':
105
+ conditions.push(`${key} <= ${this.formatValue(opValue)}`);
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ // Simple equality
112
+ conditions.push(`${key} = ${this.formatValue(value)}`);
113
+ }
114
+ }
115
+ return conditions.length > 0 ? conditions.join(' AND ') : null;
116
+ }
117
+ /**
118
+ * Formats a value for use in a SQL query.
119
+ */
120
+ formatValue(value) {
121
+ if (typeof value === 'string') {
122
+ return `'${value}'`;
123
+ }
124
+ return String(value);
125
+ }
126
+ /* * */
127
+ /**
128
+ * Counts the number of documents in the table that match the given filter.
129
+ * Supports simple equality and range queries ($gte, $lte, $gt, $lt).
130
+ *
131
+ * @param filter Optional WHERE clause conditions (e.g., { operational_date: '2024-01-01' } or { received_at: { $gte: 1234567890 } })
132
+ * @returns The count of matching documents
133
+ */
134
+ async countDocuments(filter) {
135
+ try {
136
+ let query = `SELECT count() as count FROM ${this.params.table}`;
137
+ const whereClause = this.buildWhereClause(filter);
138
+ if (whereClause) {
139
+ query += ` WHERE ${whereClause}`;
140
+ }
141
+ const result = await this.client.query({
142
+ format: 'JSONEachRow',
143
+ query,
144
+ });
145
+ const data = await result.json();
146
+ return parseInt(data[0]?.count ?? '0', 10);
147
+ }
148
+ catch (error) {
149
+ Logger.error(`CLICKHOUSEWRITER [${this.params.table}]: Error @ countDocuments(): ${error.message}`);
150
+ throw error;
151
+ }
152
+ }
153
+ /* * */
154
+ /**
155
+ * Returns distinct values for a given column, optionally filtered.
156
+ * Supports simple equality and range queries ($gte, $lte, $gt, $lt).
157
+ *
158
+ * @param column The column name to get distinct values for
159
+ * @param filter Optional WHERE clause conditions
160
+ * @returns Array of distinct values
161
+ */
162
+ async distinct(column, filter) {
163
+ try {
164
+ let query = `SELECT DISTINCT ${column} FROM ${this.params.table}`;
165
+ const whereClause = this.buildWhereClause(filter);
166
+ if (whereClause) {
167
+ query += ` WHERE ${whereClause}`;
168
+ }
169
+ const result = await this.client.query({
170
+ format: 'JSONEachRow',
171
+ query,
172
+ });
173
+ const data = await result.json();
174
+ return data.map(row => row[column]);
175
+ }
176
+ catch (error) {
177
+ Logger.error(`CLICKHOUSEWRITER [${this.params.table}]: Error @ distinct(): ${error.message}`);
178
+ throw error;
179
+ }
180
+ }
181
+ /* * */
68
182
  async flush(callback) {
69
183
  try {
70
184
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/writers",
3
- "version": "20260121.2332.6",
3
+ "version": "20260126.1852.36",
4
4
  "author": {
5
5
  "email": "iso@tmlmobilidade.pt",
6
6
  "name": "TML-ISO"