triangle-utils 1.4.170 → 1.4.172
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/src/UtilsMisc.d.ts +5 -0
- package/dist/src/UtilsMisc.js +20 -0
- package/dist/src/UtilsRDS.d.ts +1 -15
- package/dist/src/UtilsRDS.js +46 -67
- package/dist/src/f.js +2 -18
- package/package.json +3 -5
- package/src/UtilsMisc.ts +21 -0
- package/src/UtilsRDS.ts +56 -84
- package/src/f.ts +2 -21
- package/dist/src/UtilsNitter.d.ts +0 -24
- package/dist/src/UtilsNitter.js +0 -172
- package/dist/src/types/TriangleUtilsConfig.d.ts +0 -6
- package/dist/src/types/TriangleUtilsConfig.js +0 -1
package/dist/src/UtilsMisc.d.ts
CHANGED
|
@@ -31,5 +31,10 @@ export declare class UtilsMisc {
|
|
|
31
31
|
batch_num_items: number;
|
|
32
32
|
max_num_items?: number;
|
|
33
33
|
}): Promise<void>;
|
|
34
|
+
static get_line_fragments(fragment_max_size: number, text: string): {
|
|
35
|
+
min_index: number;
|
|
36
|
+
max_index: number;
|
|
37
|
+
fragment_text: string;
|
|
38
|
+
}[];
|
|
34
39
|
}
|
|
35
40
|
export {};
|
package/dist/src/UtilsMisc.js
CHANGED
|
@@ -146,4 +146,24 @@ export class UtilsMisc {
|
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
|
+
static get_line_fragments(fragment_max_size, text) {
|
|
150
|
+
const text_lines = text.split("\n");
|
|
151
|
+
const fragments = [];
|
|
152
|
+
for (let index = 0; index < text_lines.length; index += 1) {
|
|
153
|
+
const line = text_lines[index];
|
|
154
|
+
const last_fragment = fragments.at(-1);
|
|
155
|
+
if (last_fragment === undefined || last_fragment.fragment_text.length + 1 + line.length > fragment_max_size) {
|
|
156
|
+
fragments.push({
|
|
157
|
+
min_index: index,
|
|
158
|
+
max_index: index + 1,
|
|
159
|
+
fragment_text: line
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
fragments[fragments.length - 1].fragment_text = fragments[fragments.length - 1].fragment_text + "\n" + line;
|
|
164
|
+
fragments[fragments.length - 1].max_index += 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return fragments;
|
|
168
|
+
}
|
|
149
169
|
}
|
package/dist/src/UtilsRDS.d.ts
CHANGED
|
@@ -2,17 +2,13 @@ export declare class UtilsRDS {
|
|
|
2
2
|
private readonly rds_host;
|
|
3
3
|
private readonly rds_username;
|
|
4
4
|
private readonly rds_password;
|
|
5
|
-
private readonly
|
|
6
|
-
private readonly rds_data;
|
|
7
|
-
private readonly rds_cluster_arn;
|
|
8
|
-
private readonly rds_secret_arn;
|
|
5
|
+
private readonly pool;
|
|
9
6
|
constructor(region: string, rds_cluster_arn: string, rds_secret_arn: string, rds_host: string, rds_username: string, rds_password: string);
|
|
10
7
|
query(sql: string, options?: {
|
|
11
8
|
is_verbose?: boolean;
|
|
12
9
|
}): Promise<any[]>;
|
|
13
10
|
exec(sql: string, options?: {
|
|
14
11
|
is_verbose?: boolean;
|
|
15
|
-
is_forced?: boolean;
|
|
16
12
|
}): Promise<any[]>;
|
|
17
13
|
scan(table_id: string, options?: {
|
|
18
14
|
filters?: Record<string, any>;
|
|
@@ -21,48 +17,38 @@ export declare class UtilsRDS {
|
|
|
21
17
|
attribute_names?: string[];
|
|
22
18
|
max_num_items?: number;
|
|
23
19
|
is_verbose?: boolean;
|
|
24
|
-
is_forced?: boolean;
|
|
25
20
|
}): Promise<any[]>;
|
|
26
21
|
get(table_id: string, primary_key: Record<string, any>, options?: {
|
|
27
22
|
attribute_names?: string[];
|
|
28
23
|
is_verbose?: boolean;
|
|
29
|
-
is_forced?: boolean;
|
|
30
24
|
}): Promise<Record<string, any> | undefined>;
|
|
31
25
|
batch_get(table_id: string, primary_keys: Record<string, any>[], options?: {
|
|
32
26
|
batch_num_items?: number;
|
|
33
27
|
attribute_names?: string[];
|
|
34
28
|
is_verbose?: boolean;
|
|
35
|
-
is_forced?: boolean;
|
|
36
29
|
}): Promise<any[]>;
|
|
37
30
|
create(table_id: string, item: Record<string, any>, options?: {
|
|
38
31
|
is_verbose?: boolean;
|
|
39
|
-
is_forced?: boolean;
|
|
40
32
|
}): Promise<any[] | undefined>;
|
|
41
33
|
batch_create(table_id: string, items: Record<string, any>[], options?: {
|
|
42
34
|
is_verbose?: boolean;
|
|
43
|
-
is_forced?: boolean;
|
|
44
35
|
batch_num_items?: number;
|
|
45
36
|
}): Promise<void>;
|
|
46
37
|
put(table_id: string, item: Record<string, any>, options?: {
|
|
47
38
|
is_verbose?: boolean;
|
|
48
|
-
is_forced?: boolean;
|
|
49
39
|
}): Promise<any[] | undefined>;
|
|
50
40
|
batch_put(table_id: string, items: Record<string, any>[], options?: {
|
|
51
41
|
is_verbose?: boolean;
|
|
52
|
-
is_forced?: boolean;
|
|
53
42
|
batch_num_items?: number;
|
|
54
43
|
}): Promise<void>;
|
|
55
44
|
delete(table_id: string, primary_key: Record<string, any>, options?: {
|
|
56
45
|
is_verbose?: boolean;
|
|
57
|
-
is_forced?: boolean;
|
|
58
46
|
}): Promise<any[]>;
|
|
59
47
|
batch_delete(table_id: string, primary_keys: Record<string, any>[], options?: {
|
|
60
48
|
is_verbose?: boolean;
|
|
61
|
-
is_forced?: boolean;
|
|
62
49
|
batch_num_items?: number;
|
|
63
50
|
}): Promise<void>;
|
|
64
51
|
set(table_id: string, primary_key: Record<string, any>, attributes: Record<string, any>, options?: {
|
|
65
52
|
is_verbose?: boolean;
|
|
66
|
-
is_forced?: boolean;
|
|
67
53
|
}): Promise<any[]>;
|
|
68
54
|
}
|
package/dist/src/UtilsRDS.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { RDSData } from "@aws-sdk/client-rds-data";
|
|
2
1
|
import { Pool } from "pg";
|
|
3
|
-
function
|
|
2
|
+
function convert_postgres_input(input) {
|
|
4
3
|
if (input === undefined) {
|
|
5
4
|
return "NULL";
|
|
6
5
|
}
|
|
@@ -14,7 +13,7 @@ function convert_rds_input(input) {
|
|
|
14
13
|
return input.toString().toUpperCase();
|
|
15
14
|
}
|
|
16
15
|
else if (Array.isArray(input)) {
|
|
17
|
-
return "ARRAY[" + input.map(a =>
|
|
16
|
+
return "ARRAY[" + input.map(a => convert_postgres_input(a)).join(", ") + "]";
|
|
18
17
|
}
|
|
19
18
|
else if (typeof input === "object") {
|
|
20
19
|
if (input.expression !== undefined) {
|
|
@@ -23,45 +22,46 @@ function convert_rds_input(input) {
|
|
|
23
22
|
}
|
|
24
23
|
return "NULL";
|
|
25
24
|
}
|
|
26
|
-
function convert_rds_output(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
25
|
+
// function convert_rds_output(output : Field) {
|
|
26
|
+
// if (output.isNull) {
|
|
27
|
+
// return undefined
|
|
28
|
+
// } else if (output.stringValue !== undefined) {
|
|
29
|
+
// return output.stringValue
|
|
30
|
+
// } else if (output.doubleValue !== undefined) {
|
|
31
|
+
// return output.doubleValue
|
|
32
|
+
// } else if (output.longValue !== undefined) {
|
|
33
|
+
// return output.longValue
|
|
34
|
+
// } else if (output.booleanValue !== undefined) {
|
|
35
|
+
// return output.booleanValue
|
|
36
|
+
// } else if (output.arrayValue !== undefined) {
|
|
37
|
+
// return [
|
|
38
|
+
// ...(output.arrayValue.stringValues || []),
|
|
39
|
+
// ...(output.arrayValue.longValues || []),
|
|
40
|
+
// ...(output.arrayValue.booleanValues || [])
|
|
41
|
+
// ]
|
|
42
|
+
// .filter(value => value !== null)
|
|
43
|
+
// }
|
|
44
|
+
// return undefined
|
|
45
|
+
// }
|
|
46
|
+
function convert_postgres_output(output, field) {
|
|
47
|
+
if (field.dataTypeID === 1700) {
|
|
48
|
+
return Number(output[field.name]);
|
|
49
|
+
}
|
|
50
|
+
if (field.dataTypeID === 712048) {
|
|
51
|
+
return JSON.parse(output[field.name]);
|
|
52
|
+
}
|
|
53
|
+
return output[field.name];
|
|
51
54
|
}
|
|
52
55
|
export class UtilsRDS {
|
|
53
56
|
rds_host;
|
|
54
57
|
rds_username;
|
|
55
58
|
rds_password;
|
|
56
|
-
|
|
57
|
-
rds_data;
|
|
58
|
-
rds_cluster_arn;
|
|
59
|
-
rds_secret_arn;
|
|
59
|
+
pool;
|
|
60
60
|
constructor(region, rds_cluster_arn, rds_secret_arn, rds_host, rds_username, rds_password) {
|
|
61
61
|
this.rds_host = rds_host;
|
|
62
62
|
this.rds_username = rds_username;
|
|
63
63
|
this.rds_password = rds_password;
|
|
64
|
-
this.
|
|
64
|
+
this.pool = new Pool({
|
|
65
65
|
host: this.rds_host,
|
|
66
66
|
user: this.rds_username,
|
|
67
67
|
password: this.rds_password,
|
|
@@ -71,43 +71,22 @@ export class UtilsRDS {
|
|
|
71
71
|
rejectUnauthorized: false
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
this.rds_data = new RDSData({ region: region });
|
|
75
|
-
this.rds_cluster_arn = rds_cluster_arn,
|
|
76
|
-
this.rds_secret_arn = rds_secret_arn;
|
|
77
74
|
}
|
|
78
75
|
async query(sql, options = {}) {
|
|
79
76
|
const is_verbose = Boolean(options.is_verbose);
|
|
80
77
|
if (is_verbose) {
|
|
81
78
|
console.log(sql);
|
|
82
79
|
}
|
|
83
|
-
const response = await this.
|
|
84
|
-
return response.rows.map(item => Object.fromEntries(response.fields.map(field => [field.name,
|
|
80
|
+
const response = await this.pool.query(sql);
|
|
81
|
+
return response.rows.map(item => Object.fromEntries(response.fields.map(field => [field.name, convert_postgres_output(item, field)])
|
|
85
82
|
.filter(([attribute_name, attribute_value]) => attribute_value !== null && attribute_value !== undefined)));
|
|
86
83
|
}
|
|
87
84
|
async exec(sql, options = {}) {
|
|
88
85
|
const is_verbose = Boolean(options.is_verbose);
|
|
89
|
-
const is_forced = Boolean(options.is_forced);
|
|
90
86
|
if (is_verbose) {
|
|
91
87
|
console.log(sql);
|
|
92
88
|
}
|
|
93
|
-
const items = (sql
|
|
94
|
-
await this.rds_data.executeStatement({
|
|
95
|
-
resourceArn: this.rds_cluster_arn,
|
|
96
|
-
secretArn: this.rds_secret_arn,
|
|
97
|
-
database: "triangle",
|
|
98
|
-
sql: sql,
|
|
99
|
-
includeResultMetadata: true
|
|
100
|
-
})
|
|
101
|
-
// .then(response => {
|
|
102
|
-
// console.log(JSON.stringify(response, undefined, 4))
|
|
103
|
-
// return response
|
|
104
|
-
// })
|
|
105
|
-
.then(response => (response.records || [])
|
|
106
|
-
.map((item) => Object.fromEntries((response.columnMetadata || [])
|
|
107
|
-
.map((column, i) => [column.name || "", column.typeName === "numeric" ? Number(convert_rds_output(item[i])) : convert_rds_output(item[i])])
|
|
108
|
-
.filter(([key, value]) => value !== null))))
|
|
109
|
-
:
|
|
110
|
-
await this.query(sql, options);
|
|
89
|
+
const items = await this.query(sql, options);
|
|
111
90
|
if (!Array.isArray(items)) {
|
|
112
91
|
if (is_verbose) {
|
|
113
92
|
console.log("Bad items:", items);
|
|
@@ -121,7 +100,7 @@ export class UtilsRDS {
|
|
|
121
100
|
const defined_attribute_names = options.defined_attribute_names || [];
|
|
122
101
|
const filters = options.filters || {};
|
|
123
102
|
const clauses_where = [
|
|
124
|
-
...Object.entries(filters).map(([key_name, value]) => key_name + " = " +
|
|
103
|
+
...Object.entries(filters).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)),
|
|
125
104
|
...undefined_attribute_names.map(undefined_attribute_name => undefined_attribute_name + " IS NULL"),
|
|
126
105
|
...defined_attribute_names.map(undefined_attribute_name => undefined_attribute_name + " IS NOT NULL")
|
|
127
106
|
];
|
|
@@ -135,7 +114,7 @@ export class UtilsRDS {
|
|
|
135
114
|
return items;
|
|
136
115
|
}
|
|
137
116
|
async get(table_id, primary_key, options = {}) {
|
|
138
|
-
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " +
|
|
117
|
+
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ");
|
|
139
118
|
const items = await this.exec(sql, options);
|
|
140
119
|
const item = items[0];
|
|
141
120
|
return item;
|
|
@@ -145,7 +124,7 @@ export class UtilsRDS {
|
|
|
145
124
|
const attribute_names = Array.from(new Set(primary_keys.map(primary_key => Object.keys(primary_key)).flat())).sort();
|
|
146
125
|
const items = [];
|
|
147
126
|
for (let i = 0; i < primary_keys.length; i += batch_num_items) {
|
|
148
|
-
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name =>
|
|
127
|
+
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name => convert_postgres_input(primary_key[attribute_name])).join(", ") + ")").join(", ") + ")";
|
|
149
128
|
const new_items = await this.exec(sql, options);
|
|
150
129
|
items.push(...new_items);
|
|
151
130
|
}
|
|
@@ -153,7 +132,7 @@ export class UtilsRDS {
|
|
|
153
132
|
}
|
|
154
133
|
async create(table_id, item, options = {}) {
|
|
155
134
|
const attribute_names = Object.keys(item).sort();
|
|
156
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name =>
|
|
135
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")" + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO NOTHING;";
|
|
157
136
|
try {
|
|
158
137
|
const items = await this.exec(sql, options);
|
|
159
138
|
return items;
|
|
@@ -173,7 +152,7 @@ export class UtilsRDS {
|
|
|
173
152
|
const attribute_names = Array.from(new Set(items.map(item => Object.keys(item)).flat())).sort();
|
|
174
153
|
const batch_num_items = options.batch_num_items || 100;
|
|
175
154
|
for (let i = 0; i < items.length; i += batch_num_items) {
|
|
176
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name =>
|
|
155
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")").join(", ") + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO NOTHING;";
|
|
177
156
|
try {
|
|
178
157
|
await this.exec(sql, options);
|
|
179
158
|
}
|
|
@@ -188,7 +167,7 @@ export class UtilsRDS {
|
|
|
188
167
|
}
|
|
189
168
|
async put(table_id, item, options = {}) {
|
|
190
169
|
const attribute_names = Object.keys(item).sort();
|
|
191
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name =>
|
|
170
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")" + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO UPDATE SET " + attribute_names.map(attribute_name => attribute_name + " = " + "EXCLUDED." + attribute_name).join(", ") + ";";
|
|
192
171
|
try {
|
|
193
172
|
const items = await this.exec(sql, options);
|
|
194
173
|
return items;
|
|
@@ -208,7 +187,7 @@ export class UtilsRDS {
|
|
|
208
187
|
const attribute_names = Array.from(new Set(items.map(item => Object.keys(item)).flat())).sort();
|
|
209
188
|
const batch_num_items = options.batch_num_items || 100;
|
|
210
189
|
for (let i = 0; i < items.length; i += batch_num_items) {
|
|
211
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name =>
|
|
190
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")").join(", ") + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO UPDATE SET " + attribute_names.map(attribute_name => attribute_name + " = " + "EXCLUDED." + attribute_name).join(", ") + ";";
|
|
212
191
|
try {
|
|
213
192
|
await this.exec(sql, options);
|
|
214
193
|
}
|
|
@@ -222,20 +201,20 @@ export class UtilsRDS {
|
|
|
222
201
|
}
|
|
223
202
|
}
|
|
224
203
|
async delete(table_id, primary_key, options = {}) {
|
|
225
|
-
const sql = "DELETE FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " +
|
|
204
|
+
const sql = "DELETE FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ");
|
|
226
205
|
return await this.exec(sql, options);
|
|
227
206
|
}
|
|
228
207
|
async batch_delete(table_id, primary_keys, options = {}) {
|
|
229
208
|
const batch_num_items = options.batch_num_items || 100;
|
|
230
209
|
const attribute_names = Array.from(new Set(primary_keys.map(primary_key => Object.keys(primary_key)).flat())).sort();
|
|
231
210
|
for (let i = 0; i < primary_keys.length; i += batch_num_items) {
|
|
232
|
-
const sql = "DELETE FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name =>
|
|
211
|
+
const sql = "DELETE FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name => convert_postgres_input(primary_key[attribute_name])).join(", ") + ")").join(", ") + ")";
|
|
233
212
|
await this.exec(sql, options);
|
|
234
213
|
}
|
|
235
214
|
}
|
|
236
215
|
async set(table_id, primary_key, attributes, options = {}) {
|
|
237
216
|
const attribute_names = Object.keys(attributes).sort();
|
|
238
|
-
const sql = "UPDATE " + table_id + " SET " + attribute_names.map(attribute_name => attribute_name + " = " +
|
|
217
|
+
const sql = "UPDATE " + table_id + " SET " + attribute_names.map(attribute_name => attribute_name + " = " + convert_postgres_input(attributes[attribute_name])).join(", ") + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ");
|
|
239
218
|
return await this.exec(sql, options);
|
|
240
219
|
}
|
|
241
220
|
}
|
package/dist/src/f.js
CHANGED
|
@@ -83,21 +83,5 @@ const utils = new TriangleUtils(config);
|
|
|
83
83
|
// .then(response => console.log(response))
|
|
84
84
|
// await utils.s3.get_download_url("s3://triangle-675045717295-us-east-1-an/tenant_documents/a3a9627f-a94d-4d47-a110-307a6f5563af/a146d789-da40-4e3c-a132-8b7110f3f7df.pdf", { name : "hye.pdf" })
|
|
85
85
|
// .then(response => console.log(response))
|
|
86
|
-
await utils.
|
|
87
|
-
|
|
88
|
-
role: "user",
|
|
89
|
-
text: "ayo"
|
|
90
|
-
}
|
|
91
|
-
], {
|
|
92
|
-
json_format: {
|
|
93
|
-
type: "object",
|
|
94
|
-
properties: {
|
|
95
|
-
relevance: {
|
|
96
|
-
type: "string"
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
required: ["relevance"],
|
|
100
|
-
additionalProperties: false
|
|
101
|
-
},
|
|
102
|
-
verbosity: 5
|
|
103
|
-
});
|
|
86
|
+
await utils.rds.query("SELECT * FROM twitter_tweets LIMIT 10")
|
|
87
|
+
.then(console.log);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "triangle-utils",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.172",
|
|
4
4
|
"main": "dist/src/index.js",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"directories": {
|
|
@@ -15,13 +15,11 @@
|
|
|
15
15
|
"description": "",
|
|
16
16
|
"type": "module",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@anthropic-ai/bedrock-sdk": "^0.
|
|
19
|
-
"@anthropic-ai/sdk": "^0.
|
|
18
|
+
"@anthropic-ai/bedrock-sdk": "^0.33.4",
|
|
19
|
+
"@anthropic-ai/sdk": "^0.124.0",
|
|
20
20
|
"@aws-sdk/client-bedrock-runtime": "^3.953.0",
|
|
21
21
|
"@aws-sdk/client-cognito-identity-provider": "^3.1004.0",
|
|
22
22
|
"@aws-sdk/client-dynamodb": "^3.953.0",
|
|
23
|
-
"@aws-sdk/client-rds": "^3.1111.0",
|
|
24
|
-
"@aws-sdk/client-rds-data": "^3.1111.0",
|
|
25
23
|
"@aws-sdk/client-s3": "^3.1106.0",
|
|
26
24
|
"@aws-sdk/client-s3vectors": "^3.953.0",
|
|
27
25
|
"@aws-sdk/client-secrets-manager": "^3.965.0",
|
package/src/UtilsMisc.ts
CHANGED
|
@@ -174,4 +174,25 @@ export class UtilsMisc {
|
|
|
174
174
|
})
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
static get_line_fragments(fragment_max_size : number, text : string) {
|
|
178
|
+
const text_lines = text.split("\n")
|
|
179
|
+
const fragments : { min_index : number, max_index : number, fragment_text : string }[] = []
|
|
180
|
+
for (let index = 0; index < text_lines.length; index += 1) {
|
|
181
|
+
|
|
182
|
+
const line = text_lines[index]
|
|
183
|
+
const last_fragment = fragments.at(-1)
|
|
184
|
+
if (last_fragment === undefined || last_fragment.fragment_text.length + 1 + line.length > fragment_max_size) {
|
|
185
|
+
fragments.push({
|
|
186
|
+
min_index : index,
|
|
187
|
+
max_index : index + 1,
|
|
188
|
+
fragment_text : line
|
|
189
|
+
})
|
|
190
|
+
} else {
|
|
191
|
+
fragments[fragments.length - 1].fragment_text = fragments[fragments.length - 1].fragment_text + "\n" + line
|
|
192
|
+
fragments[fragments.length - 1].max_index += 1
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return fragments
|
|
196
|
+
}
|
|
197
|
+
|
|
177
198
|
}
|
package/src/UtilsRDS.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Client, Pool } from "pg"
|
|
1
|
+
import { FieldDef, Pool } from "pg"
|
|
3
2
|
|
|
4
|
-
function
|
|
3
|
+
function convert_postgres_input(input : string | boolean | number | any[] | Record<string, any> | undefined) : string {
|
|
5
4
|
if (input === undefined) {
|
|
6
5
|
return "NULL"
|
|
7
6
|
} else if (typeof input === "string") {
|
|
@@ -11,7 +10,7 @@ function convert_rds_input(input : string | boolean | number | any[] | Record<st
|
|
|
11
10
|
} else if (typeof input === "boolean") {
|
|
12
11
|
return input.toString().toUpperCase()
|
|
13
12
|
} else if (Array.isArray(input)) {
|
|
14
|
-
return "ARRAY[" + input.map(a =>
|
|
13
|
+
return "ARRAY[" + input.map(a => convert_postgres_input(a)).join(", ") + "]"
|
|
15
14
|
} else if (typeof input === "object") {
|
|
16
15
|
if (input.expression !== undefined) {
|
|
17
16
|
return input.expression
|
|
@@ -20,26 +19,36 @@ function convert_rds_input(input : string | boolean | number | any[] | Record<st
|
|
|
20
19
|
return "NULL"
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
function convert_rds_output(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
// function convert_rds_output(output : Field) {
|
|
23
|
+
// if (output.isNull) {
|
|
24
|
+
// return undefined
|
|
25
|
+
// } else if (output.stringValue !== undefined) {
|
|
26
|
+
// return output.stringValue
|
|
27
|
+
// } else if (output.doubleValue !== undefined) {
|
|
28
|
+
// return output.doubleValue
|
|
29
|
+
// } else if (output.longValue !== undefined) {
|
|
30
|
+
// return output.longValue
|
|
31
|
+
// } else if (output.booleanValue !== undefined) {
|
|
32
|
+
// return output.booleanValue
|
|
33
|
+
// } else if (output.arrayValue !== undefined) {
|
|
34
|
+
// return [
|
|
35
|
+
// ...(output.arrayValue.stringValues || []),
|
|
36
|
+
// ...(output.arrayValue.longValues || []),
|
|
37
|
+
// ...(output.arrayValue.booleanValues || [])
|
|
38
|
+
// ]
|
|
39
|
+
// .filter(value => value !== null)
|
|
40
|
+
// }
|
|
41
|
+
// return undefined
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
function convert_postgres_output(output : any, field : FieldDef) {
|
|
45
|
+
if (field.dataTypeID === 1700) {
|
|
46
|
+
return Number(output[field.name])
|
|
47
|
+
}
|
|
48
|
+
if (field.dataTypeID === 712048) {
|
|
49
|
+
return JSON.parse(output[field.name])
|
|
41
50
|
}
|
|
42
|
-
return
|
|
51
|
+
return output[field.name]
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
export class UtilsRDS {
|
|
@@ -47,10 +56,7 @@ export class UtilsRDS {
|
|
|
47
56
|
private readonly rds_host : string
|
|
48
57
|
private readonly rds_username : string
|
|
49
58
|
private readonly rds_password : string
|
|
50
|
-
private readonly
|
|
51
|
-
private readonly rds_data : RDSData
|
|
52
|
-
private readonly rds_cluster_arn : string
|
|
53
|
-
private readonly rds_secret_arn : string
|
|
59
|
+
private readonly pool : Pool
|
|
54
60
|
|
|
55
61
|
constructor(
|
|
56
62
|
region : string,
|
|
@@ -63,7 +69,7 @@ export class UtilsRDS {
|
|
|
63
69
|
this.rds_host = rds_host
|
|
64
70
|
this.rds_username = rds_username
|
|
65
71
|
this.rds_password = rds_password
|
|
66
|
-
this.
|
|
72
|
+
this.pool = new Pool({
|
|
67
73
|
host : this.rds_host,
|
|
68
74
|
user : this.rds_username,
|
|
69
75
|
password : this.rds_password,
|
|
@@ -73,9 +79,6 @@ export class UtilsRDS {
|
|
|
73
79
|
rejectUnauthorized: false
|
|
74
80
|
}
|
|
75
81
|
})
|
|
76
|
-
this.rds_data = new RDSData({ region : region })
|
|
77
|
-
this.rds_cluster_arn = rds_cluster_arn,
|
|
78
|
-
this.rds_secret_arn = rds_secret_arn
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
async query(
|
|
@@ -88,9 +91,9 @@ export class UtilsRDS {
|
|
|
88
91
|
if (is_verbose) {
|
|
89
92
|
console.log(sql)
|
|
90
93
|
}
|
|
91
|
-
const response = await this.
|
|
94
|
+
const response = await this.pool.query(sql)
|
|
92
95
|
return response.rows.map(item => Object.fromEntries(
|
|
93
|
-
response.fields.map(field => [field.name,
|
|
96
|
+
response.fields.map(field => [field.name, convert_postgres_output(item, field)])
|
|
94
97
|
.filter(([attribute_name, attribute_value]) => attribute_value !== null && attribute_value !== undefined)
|
|
95
98
|
))
|
|
96
99
|
}
|
|
@@ -98,35 +101,14 @@ export class UtilsRDS {
|
|
|
98
101
|
async exec(
|
|
99
102
|
sql : string,
|
|
100
103
|
options : {
|
|
101
|
-
is_verbose? : boolean
|
|
102
|
-
is_forced? : boolean
|
|
104
|
+
is_verbose? : boolean
|
|
103
105
|
} = {}
|
|
104
106
|
) {
|
|
105
107
|
const is_verbose = Boolean(options.is_verbose)
|
|
106
|
-
const is_forced = Boolean(options.is_forced)
|
|
107
108
|
if (is_verbose) {
|
|
108
109
|
console.log(sql)
|
|
109
110
|
}
|
|
110
|
-
const items = (sql
|
|
111
|
-
await this.rds_data.executeStatement({
|
|
112
|
-
resourceArn : this.rds_cluster_arn,
|
|
113
|
-
secretArn : this.rds_secret_arn,
|
|
114
|
-
database : "triangle",
|
|
115
|
-
sql : sql,
|
|
116
|
-
includeResultMetadata : true
|
|
117
|
-
})
|
|
118
|
-
// .then(response => {
|
|
119
|
-
// console.log(JSON.stringify(response, undefined, 4))
|
|
120
|
-
// return response
|
|
121
|
-
// })
|
|
122
|
-
.then(response => (response.records || [])
|
|
123
|
-
.map((item : any) => Object.fromEntries((response.columnMetadata || [])
|
|
124
|
-
.map((column, i) => [column.name || "", column.typeName === "numeric" ? Number(convert_rds_output(item[i])) : convert_rds_output(item[i])])
|
|
125
|
-
.filter(([key, value]) => value !== null)
|
|
126
|
-
))
|
|
127
|
-
)
|
|
128
|
-
:
|
|
129
|
-
await this.query(sql, options)
|
|
111
|
+
const items = await this.query(sql, options)
|
|
130
112
|
if (!Array.isArray(items)) {
|
|
131
113
|
if (is_verbose) {
|
|
132
114
|
console.log("Bad items:", items)
|
|
@@ -144,15 +126,14 @@ export class UtilsRDS {
|
|
|
144
126
|
defined_attribute_names? : string[],
|
|
145
127
|
attribute_names? : string[],
|
|
146
128
|
max_num_items? : number,
|
|
147
|
-
is_verbose? : boolean
|
|
148
|
-
is_forced? : boolean
|
|
129
|
+
is_verbose? : boolean
|
|
149
130
|
} = {}
|
|
150
131
|
) {
|
|
151
132
|
const undefined_attribute_names = options.undefined_attribute_names || []
|
|
152
133
|
const defined_attribute_names = options.defined_attribute_names || []
|
|
153
134
|
const filters = options.filters || {}
|
|
154
135
|
const clauses_where = [
|
|
155
|
-
...Object.entries(filters).map(([key_name, value]) => key_name + " = " +
|
|
136
|
+
...Object.entries(filters).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)),
|
|
156
137
|
...undefined_attribute_names.map(undefined_attribute_name => undefined_attribute_name + " IS NULL"),
|
|
157
138
|
...defined_attribute_names.map(undefined_attribute_name => undefined_attribute_name + " IS NOT NULL")
|
|
158
139
|
]
|
|
@@ -171,11 +152,10 @@ export class UtilsRDS {
|
|
|
171
152
|
primary_key : Record<string, any>,
|
|
172
153
|
options : {
|
|
173
154
|
attribute_names? : string[],
|
|
174
|
-
is_verbose? : boolean
|
|
175
|
-
is_forced? : boolean
|
|
155
|
+
is_verbose? : boolean
|
|
176
156
|
} = {}
|
|
177
157
|
) {
|
|
178
|
-
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " +
|
|
158
|
+
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ")
|
|
179
159
|
const items = await this.exec(sql, options)
|
|
180
160
|
const item : Record<string, any> | undefined = items[0]
|
|
181
161
|
return item
|
|
@@ -187,15 +167,14 @@ export class UtilsRDS {
|
|
|
187
167
|
options : {
|
|
188
168
|
batch_num_items? : number,
|
|
189
169
|
attribute_names? : string[],
|
|
190
|
-
is_verbose? : boolean
|
|
191
|
-
is_forced? : boolean
|
|
170
|
+
is_verbose? : boolean
|
|
192
171
|
} = {}
|
|
193
172
|
) {
|
|
194
173
|
const batch_num_items = options.batch_num_items || 100
|
|
195
174
|
const attribute_names = Array.from(new Set(primary_keys.map(primary_key => Object.keys(primary_key)).flat())).sort()
|
|
196
175
|
const items = []
|
|
197
176
|
for (let i = 0; i < primary_keys.length; i += batch_num_items) {
|
|
198
|
-
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name =>
|
|
177
|
+
const sql = "SELECT " + (options.attribute_names === undefined ? "*" : options.attribute_names.join(", ")) + " FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name => convert_postgres_input(primary_key[attribute_name])).join(", ") + ")" ).join(", ") + ")"
|
|
199
178
|
const new_items = await this.exec(sql, options)
|
|
200
179
|
items.push(...new_items)
|
|
201
180
|
}
|
|
@@ -206,12 +185,11 @@ export class UtilsRDS {
|
|
|
206
185
|
table_id : string,
|
|
207
186
|
item : Record<string, any>,
|
|
208
187
|
options : {
|
|
209
|
-
is_verbose? : boolean
|
|
210
|
-
is_forced? : boolean
|
|
188
|
+
is_verbose? : boolean
|
|
211
189
|
} = {}
|
|
212
190
|
) {
|
|
213
191
|
const attribute_names = Object.keys(item).sort()
|
|
214
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name =>
|
|
192
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")" + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO NOTHING;"
|
|
215
193
|
try {
|
|
216
194
|
const items = await this.exec(sql, options)
|
|
217
195
|
return items
|
|
@@ -228,8 +206,7 @@ export class UtilsRDS {
|
|
|
228
206
|
table_id : string,
|
|
229
207
|
items : Record<string, any>[],
|
|
230
208
|
options : {
|
|
231
|
-
is_verbose? : boolean
|
|
232
|
-
is_forced? : boolean,
|
|
209
|
+
is_verbose? : boolean
|
|
233
210
|
batch_num_items? : number
|
|
234
211
|
} = {}
|
|
235
212
|
) {
|
|
@@ -239,7 +216,7 @@ export class UtilsRDS {
|
|
|
239
216
|
const attribute_names = Array.from(new Set(items.map(item => Object.keys(item)).flat())).sort()
|
|
240
217
|
const batch_num_items = options.batch_num_items || 100
|
|
241
218
|
for (let i = 0; i < items.length; i += batch_num_items) {
|
|
242
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name =>
|
|
219
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")").join(", ") + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO NOTHING;"
|
|
243
220
|
try {
|
|
244
221
|
await this.exec(sql, options)
|
|
245
222
|
} catch (error : any) {
|
|
@@ -256,12 +233,11 @@ export class UtilsRDS {
|
|
|
256
233
|
table_id : string,
|
|
257
234
|
item : Record<string, any>,
|
|
258
235
|
options : {
|
|
259
|
-
is_verbose? : boolean
|
|
260
|
-
is_forced? : boolean
|
|
236
|
+
is_verbose? : boolean
|
|
261
237
|
} = {}
|
|
262
238
|
) {
|
|
263
239
|
const attribute_names = Object.keys(item).sort()
|
|
264
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name =>
|
|
240
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")" + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO UPDATE SET " + attribute_names.map(attribute_name => attribute_name + " = " + "EXCLUDED." + attribute_name).join(", ") + ";"
|
|
265
241
|
try {
|
|
266
242
|
const items = await this.exec(sql, options)
|
|
267
243
|
return items
|
|
@@ -279,7 +255,6 @@ export class UtilsRDS {
|
|
|
279
255
|
items : Record<string, any>[],
|
|
280
256
|
options : {
|
|
281
257
|
is_verbose? : boolean,
|
|
282
|
-
is_forced? : boolean,
|
|
283
258
|
batch_num_items? : number
|
|
284
259
|
} = {}
|
|
285
260
|
) {
|
|
@@ -289,7 +264,7 @@ export class UtilsRDS {
|
|
|
289
264
|
const attribute_names = Array.from(new Set(items.map(item => Object.keys(item)).flat())).sort()
|
|
290
265
|
const batch_num_items = options.batch_num_items || 100
|
|
291
266
|
for (let i = 0; i < items.length; i += batch_num_items) {
|
|
292
|
-
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name =>
|
|
267
|
+
const sql = "INSERT INTO " + table_id + " (" + attribute_names.join(", ") + ")" + " VALUES " + items.slice(i, i + batch_num_items).map(item => "(" + attribute_names.map(attribute_name => convert_postgres_input(item[attribute_name])).join(", ") + ")").join(", ") + " ON CONFLICT ON CONSTRAINT " + table_id + "_pkey DO UPDATE SET " + attribute_names.map(attribute_name => attribute_name + " = " + "EXCLUDED." + attribute_name).join(", ") + ";"
|
|
293
268
|
try {
|
|
294
269
|
await this.exec(sql, options)
|
|
295
270
|
} catch (error : any) {
|
|
@@ -306,11 +281,10 @@ export class UtilsRDS {
|
|
|
306
281
|
table_id : string,
|
|
307
282
|
primary_key : Record<string, any>,
|
|
308
283
|
options : {
|
|
309
|
-
is_verbose? : boolean
|
|
310
|
-
is_forced? : boolean
|
|
284
|
+
is_verbose? : boolean
|
|
311
285
|
} = {}
|
|
312
286
|
) {
|
|
313
|
-
const sql = "DELETE FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " +
|
|
287
|
+
const sql = "DELETE FROM " + table_id + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ")
|
|
314
288
|
return await this.exec(sql, options)
|
|
315
289
|
}
|
|
316
290
|
|
|
@@ -319,14 +293,13 @@ export class UtilsRDS {
|
|
|
319
293
|
primary_keys : Record<string, any>[],
|
|
320
294
|
options : {
|
|
321
295
|
is_verbose? : boolean,
|
|
322
|
-
is_forced? : boolean,
|
|
323
296
|
batch_num_items? : number
|
|
324
297
|
} = {}
|
|
325
298
|
) {
|
|
326
299
|
const batch_num_items = options.batch_num_items || 100
|
|
327
300
|
const attribute_names = Array.from(new Set(primary_keys.map(primary_key => Object.keys(primary_key)).flat())).sort()
|
|
328
301
|
for (let i = 0; i < primary_keys.length; i += batch_num_items) {
|
|
329
|
-
const sql = "DELETE FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name =>
|
|
302
|
+
const sql = "DELETE FROM " + table_id + " WHERE " + "(" + attribute_names.join(", ") + ")" + " IN " + "(" + primary_keys.map(primary_key => "(" + attribute_names.map(attribute_name => convert_postgres_input(primary_key[attribute_name])).join(", ") + ")" ).join(", ") + ")"
|
|
330
303
|
await this.exec(sql, options)
|
|
331
304
|
}
|
|
332
305
|
}
|
|
@@ -336,12 +309,11 @@ export class UtilsRDS {
|
|
|
336
309
|
primary_key : Record<string, any>,
|
|
337
310
|
attributes : Record<string, any>,
|
|
338
311
|
options : {
|
|
339
|
-
is_verbose? : boolean
|
|
340
|
-
is_forced? : boolean
|
|
312
|
+
is_verbose? : boolean
|
|
341
313
|
} = {}
|
|
342
314
|
) {
|
|
343
315
|
const attribute_names = Object.keys(attributes).sort()
|
|
344
|
-
const sql = "UPDATE " + table_id + " SET " + attribute_names.map(attribute_name => attribute_name + " = " +
|
|
316
|
+
const sql = "UPDATE " + table_id + " SET " + attribute_names.map(attribute_name => attribute_name + " = " + convert_postgres_input(attributes[attribute_name])).join(", ") + " WHERE " + Object.entries(primary_key).map(([key_name, value]) => key_name + " = " + convert_postgres_input(value)).join(" AND ")
|
|
345
317
|
return await this.exec(sql, options)
|
|
346
318
|
}
|
|
347
319
|
|
package/src/f.ts
CHANGED
|
@@ -107,24 +107,5 @@ const utils = new TriangleUtils(config)
|
|
|
107
107
|
// .then(response => console.log(response))
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
await utils.
|
|
111
|
-
|
|
112
|
-
{
|
|
113
|
-
role : "user",
|
|
114
|
-
text : "ayo"
|
|
115
|
-
}
|
|
116
|
-
],
|
|
117
|
-
{
|
|
118
|
-
json_format : {
|
|
119
|
-
type : "object",
|
|
120
|
-
properties : {
|
|
121
|
-
relevance : {
|
|
122
|
-
type : "string"
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
required : ["relevance"],
|
|
126
|
-
additionalProperties : false
|
|
127
|
-
},
|
|
128
|
-
verbosity : 5
|
|
129
|
-
}
|
|
130
|
-
)
|
|
110
|
+
await utils.rds.query("SELECT * FROM twitter_tweets LIMIT 10")
|
|
111
|
+
.then(console.log)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { UtilsBee } from "./UtilsBee.js";
|
|
2
|
-
export declare class Tweet {
|
|
3
|
-
readonly tweet_id: string;
|
|
4
|
-
readonly username: string;
|
|
5
|
-
readonly url: string;
|
|
6
|
-
readonly tweet_time: string;
|
|
7
|
-
readonly tweet_content: string;
|
|
8
|
-
readonly quote?: string;
|
|
9
|
-
readonly html: string;
|
|
10
|
-
readonly text: string;
|
|
11
|
-
constructor(tweet: any);
|
|
12
|
-
static is(tweet: any): tweet is Tweet;
|
|
13
|
-
}
|
|
14
|
-
export declare class UtilsNitter extends UtilsBee {
|
|
15
|
-
constructor(scraping_bee_api_key: string | undefined);
|
|
16
|
-
get_tweets(username: string, options?: {
|
|
17
|
-
min_tweet_id?: string;
|
|
18
|
-
min_tweet_time?: string;
|
|
19
|
-
}): Promise<Tweet[]>;
|
|
20
|
-
search(query: string, options?: {
|
|
21
|
-
min_tweet_id?: string;
|
|
22
|
-
min_tweet_time?: string;
|
|
23
|
-
}): Promise<Tweet[]>;
|
|
24
|
-
}
|
package/dist/src/UtilsNitter.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { JSDOM } from "jsdom";
|
|
2
|
-
import { UtilsBee } from "./UtilsBee.js";
|
|
3
|
-
import { UtilsMisc } from "./UtilsMisc.js";
|
|
4
|
-
export class Tweet {
|
|
5
|
-
tweet_id;
|
|
6
|
-
username;
|
|
7
|
-
url;
|
|
8
|
-
tweet_time;
|
|
9
|
-
tweet_content;
|
|
10
|
-
quote;
|
|
11
|
-
html;
|
|
12
|
-
text;
|
|
13
|
-
constructor(tweet) {
|
|
14
|
-
if (!Tweet.is(tweet)) {
|
|
15
|
-
throw Error("Invalid input.");
|
|
16
|
-
}
|
|
17
|
-
this.tweet_id = tweet.tweet_id;
|
|
18
|
-
this.username = tweet.username;
|
|
19
|
-
this.url = tweet.url;
|
|
20
|
-
this.tweet_time = tweet.tweet_time;
|
|
21
|
-
this.tweet_content = tweet.tweet_content;
|
|
22
|
-
this.quote = tweet.quote;
|
|
23
|
-
this.html = tweet.html;
|
|
24
|
-
this.text = tweet.text;
|
|
25
|
-
}
|
|
26
|
-
static is(tweet) {
|
|
27
|
-
return (tweet !== undefined &&
|
|
28
|
-
typeof tweet.tweet_id === "string" &&
|
|
29
|
-
typeof tweet.username === "string" &&
|
|
30
|
-
typeof tweet.url === "string" &&
|
|
31
|
-
typeof tweet.tweet_time === "string" &&
|
|
32
|
-
typeof tweet.tweet_content === "string" &&
|
|
33
|
-
(tweet.quote === undefined || typeof tweet.quote === "string") &&
|
|
34
|
-
(typeof tweet.html === "string") &&
|
|
35
|
-
(typeof tweet.text === "string"));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function parse_tweet_element(tweet_element) {
|
|
39
|
-
if (tweet_element.className.includes("show-more")) {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
const tweet_link = tweet_element.querySelector(".tweet-link");
|
|
43
|
-
if (tweet_link === null) {
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
const url_element = tweet_link.getAttribute("href");
|
|
47
|
-
const url = url_element !== null ? url_element.replace("#m", "") : undefined;
|
|
48
|
-
if (url === undefined) {
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
const username = url.split("/")[1];
|
|
52
|
-
const tweet_number = url.split("/")[3].padStart(20, "0");
|
|
53
|
-
const tweet_date = tweet_element.querySelector(".tweet-date")?.querySelector("a")?.getAttribute("title")?.replace(" · ", " ");
|
|
54
|
-
if (tweet_date === undefined) {
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
const tweet_time = (new Date(tweet_date)).toISOString();
|
|
58
|
-
const tweet_id = tweet_time.substring(0, 16) + "|" + tweet_number;
|
|
59
|
-
const tweet_content = tweet_element.querySelector(".tweet-content")?.innerHTML?.replaceAll(/\<[^\>]+\>/g, "");
|
|
60
|
-
if (tweet_content === undefined) {
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
const tweet_quote = tweet_element.querySelector(".quote-big");
|
|
64
|
-
const quote = tweet_quote !== null ?
|
|
65
|
-
tweet_quote.innerHTML
|
|
66
|
-
.replaceAll(/\<[^\>]+\>/g, "")
|
|
67
|
-
.replaceAll(/[^\n\S\r]+/g, " ").split("\n").map(line => line.trim()).filter(line => line !== "").join("\n")
|
|
68
|
-
:
|
|
69
|
-
undefined;
|
|
70
|
-
const text = "Tweet from @" + username + " on " + tweet_time + ":\n\n" +
|
|
71
|
-
tweet_content +
|
|
72
|
-
(quote !== undefined ? ("\n\nQuote:\n\n" + quote) : "");
|
|
73
|
-
const html = tweet_element.innerHTML;
|
|
74
|
-
const tweet = {
|
|
75
|
-
tweet_id: tweet_id,
|
|
76
|
-
username: username,
|
|
77
|
-
url: url,
|
|
78
|
-
tweet_time: tweet_time,
|
|
79
|
-
tweet_content: tweet_content,
|
|
80
|
-
quote: quote,
|
|
81
|
-
html: html,
|
|
82
|
-
text: text
|
|
83
|
-
};
|
|
84
|
-
return tweet;
|
|
85
|
-
}
|
|
86
|
-
function parse_nitter_html(nitter_html) {
|
|
87
|
-
const dom = new JSDOM(nitter_html);
|
|
88
|
-
const root = dom.window.document.body;
|
|
89
|
-
const tweet_elements = root.querySelectorAll(".timeline-item");
|
|
90
|
-
const tweets = Array.from(tweet_elements).map(parse_tweet_element).filter(tweet => tweet !== undefined);
|
|
91
|
-
const next_button = root.querySelector(".show-more:not(.timeline-item)");
|
|
92
|
-
const next_button_link = next_button !== null ? next_button.querySelector("a") : null;
|
|
93
|
-
const next_nitter_query = (next_button_link !== null ? next_button_link.getAttribute("href") : null) || undefined;
|
|
94
|
-
return { tweets: tweets, next_nitter_query: next_nitter_query };
|
|
95
|
-
}
|
|
96
|
-
export class UtilsNitter extends UtilsBee {
|
|
97
|
-
constructor(scraping_bee_api_key) {
|
|
98
|
-
super(scraping_bee_api_key);
|
|
99
|
-
}
|
|
100
|
-
async get_tweets(username, options) {
|
|
101
|
-
const min_tweet_id = options !== undefined ? options.min_tweet_id : undefined;
|
|
102
|
-
const min_tweet_time = options !== undefined ? options.min_tweet_time : undefined;
|
|
103
|
-
console.log("Querying Twitter: @" + username, "min_tweet_id:", min_tweet_id, "min_tweet_time:", min_tweet_time);
|
|
104
|
-
let nitter_query = "";
|
|
105
|
-
const tweets = [];
|
|
106
|
-
while (nitter_query !== undefined) {
|
|
107
|
-
const nitter_url = "https://nitter.net/" + username + nitter_query;
|
|
108
|
-
console.log(nitter_url);
|
|
109
|
-
let nitter_html = undefined;
|
|
110
|
-
for (let i = 0; i < 10; i++) {
|
|
111
|
-
nitter_html = await this.get(nitter_url, { render_js: false });
|
|
112
|
-
if (nitter_html !== undefined && nitter_html !== "" && !(nitter_html instanceof Error)) {
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
console.log("Failed to query Nitter, trying again.");
|
|
116
|
-
await UtilsMisc.wait((2 + 2 * i) * 1000);
|
|
117
|
-
}
|
|
118
|
-
if (nitter_html === undefined || nitter_html === "" || nitter_html instanceof Error) {
|
|
119
|
-
console.log("Nitter failed for url", nitter_url);
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
const nitter_data = parse_nitter_html(nitter_html);
|
|
123
|
-
nitter_query = nitter_data.next_nitter_query;
|
|
124
|
-
for (const tweet of nitter_data.tweets) {
|
|
125
|
-
if (min_tweet_id !== undefined && tweet.tweet_id.localeCompare(min_tweet_id) < 0) {
|
|
126
|
-
nitter_query = undefined;
|
|
127
|
-
}
|
|
128
|
-
if (min_tweet_time !== undefined && tweet.tweet_time.localeCompare(min_tweet_time) < 0) {
|
|
129
|
-
nitter_query = undefined;
|
|
130
|
-
}
|
|
131
|
-
tweets.push(tweet);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return tweets;
|
|
135
|
-
}
|
|
136
|
-
async search(query, options) {
|
|
137
|
-
const min_tweet_id = options !== undefined ? options.min_tweet_id : undefined;
|
|
138
|
-
const min_tweet_time = options !== undefined ? options.min_tweet_time : undefined;
|
|
139
|
-
console.log("Querying Twitter:", query, "min_tweet_id:", min_tweet_id, "min_tweet_time:", min_tweet_time);
|
|
140
|
-
let nitter_query = "?f=tweets&q=" + query + "&e-nativeretweets=on";
|
|
141
|
-
const tweets = [];
|
|
142
|
-
while (nitter_query !== undefined) {
|
|
143
|
-
const nitter_url = "https://nitter.net/search" + nitter_query;
|
|
144
|
-
console.log(nitter_url);
|
|
145
|
-
let nitter_html = undefined;
|
|
146
|
-
for (let i = 0; i < 10; i++) {
|
|
147
|
-
nitter_html = await this.get(nitter_url, { render_js: false });
|
|
148
|
-
if (nitter_html !== undefined && nitter_html !== "" && !(nitter_html instanceof Error)) {
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
console.log("Failed to query Nitter, trying again.");
|
|
152
|
-
await UtilsMisc.wait((2 + 2 * i) * 1000);
|
|
153
|
-
}
|
|
154
|
-
if (nitter_html === undefined || nitter_html === "" || nitter_html instanceof Error) {
|
|
155
|
-
console.log("Nitter failed for url", nitter_url);
|
|
156
|
-
return [];
|
|
157
|
-
}
|
|
158
|
-
const nitter_data = parse_nitter_html(nitter_html);
|
|
159
|
-
nitter_query = nitter_data.next_nitter_query;
|
|
160
|
-
for (const tweet of nitter_data.tweets) {
|
|
161
|
-
if (min_tweet_id !== undefined && tweet.tweet_id.localeCompare(min_tweet_id) < 0) {
|
|
162
|
-
nitter_query = undefined;
|
|
163
|
-
}
|
|
164
|
-
if (min_tweet_time !== undefined && tweet.tweet_time.localeCompare(min_tweet_time) < 0) {
|
|
165
|
-
nitter_query = undefined;
|
|
166
|
-
}
|
|
167
|
-
tweets.push(tweet);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return tweets;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|