Skip to content

Commit

Permalink
Add script to dump contents of rule DB to CSV
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathonherbert committed Jan 27, 2025
1 parent 2a76ed6 commit 9f80f8c
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 2 deletions.
119 changes: 119 additions & 0 deletions script/js/dump-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Pool } from 'pg';
import { createObjectCsvWriter } from 'csv-writer';
import { format } from 'date-fns';

// Database configuration
const dbConfig = {
user: 'tr-rule-manager-local',
host: 'localhost',
database: 'tr-rule-manager-local',
password: 'tr-rule-manager-local',
port: 5678,
};

// Configuration options
interface Config {
tableName: string;
batchSize: number;
orderByColumn: string;
whereClause?: string;
columns: string[];
outputPath: string;
}

async function paginateAndExport(config: Config) {
const pool = new Pool(dbConfig);
let offset = 0;
let hasMoreRecords = true;
let batchNumber = 1;

// Create CSV writer
const timestamp = format(new Date(), 'yyyyMMdd_HHmmss');
const csvWriter = createObjectCsvWriter({
path: `${config.outputPath}/export_${timestamp}_batch_${batchNumber}.csv`,
header: config.columns.map(column => ({
id: column,
title: column
}))
});

try {
console.log('Starting export...');

while (hasMoreRecords) {
// Construct the SQL query
const whereClause = config.whereClause ? `WHERE ${config.whereClause}` : '';
const query = `
SELECT ${config.columns.join(', ')}
FROM ${config.tableName}
${whereClause}
ORDER BY ${config.orderByColumn}
LIMIT ${config.batchSize}
OFFSET ${offset}
`;

// Execute query
const result = await pool.query(query);
const records = result.rows;

if (records.length === 0) {
hasMoreRecords = false;
continue;
}

// Write batch to CSV
await csvWriter.writeRecords(records);

console.log(`Processed batch ${batchNumber}: ${records.length} records`);

// Update for next iteration
offset += config.batchSize;
batchNumber++;
}

console.log('Export completed successfully!');
} catch (error) {
console.error('Error during export:', error);
throw error;
} finally {
await pool.end();
}
}

async function main() {
const config: Config = {
tableName: 'rules_draft',
batchSize: 1000,
orderByColumn: 'id',
columns: [
'id',
'rule_type',
'pattern',
'replacement',
'category',
'description',
'ignore',
'notes',
'external_id',
'force_red_rule',
'advisory_rule',
'created_by',
'created_at',
'updated_by',
'updated_at',
'revision_id',
'is_archived',
'rule_order',
],
outputPath: './',
};

try {
await paginateAndExport(config);
} catch (error) {
console.error('Export failed:', error);
process.exit(1);
}
}

main();
9 changes: 7 additions & 2 deletions script/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
"check-types": "tsc --noEmit"
},
"dependencies": {
"libxml2-wasm": "^0.4.1"
"@types/pg": "^8.11.11",
"csv-writer": "^1.6.0",
"date-fns": "^4.1.0",
"libxml2-wasm": "^0.4.1",
"pg": "^8.13.1"
},
"devDependencies": {
"@types/node": "^22.10.1",
"typescript": "^5.7.2"
}
},
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
164 changes: 164 additions & 0 deletions script/js/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,177 @@
# yarn lockfile v1


"@types/node@*":
version "22.10.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.10.tgz#85fe89f8bf459dc57dfef1689bd5b52ad1af07e6"
integrity sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==
dependencies:
undici-types "~6.20.0"

"@types/node@^22.10.1":
version "22.10.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.1.tgz#41ffeee127b8975a05f8c4f83fb89bcb2987d766"
integrity sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==
dependencies:
undici-types "~6.20.0"

"@types/pg@^8.11.11":
version "8.11.11"
resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.11.tgz#3bdce0580e521a62a62339a53d110458d9eae6df"
integrity sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==
dependencies:
"@types/node" "*"
pg-protocol "*"
pg-types "^4.0.1"

csv-writer@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/csv-writer/-/csv-writer-1.6.0.tgz#d0cea44b6b4d7d3baa2ecc6f3f7209233514bcf9"
integrity sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g==

date-fns@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==

libxml2-wasm@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/libxml2-wasm/-/libxml2-wasm-0.4.1.tgz#6d4149e7c06cf17cc470b6a659c3d00639a3c241"
integrity sha512-pci4oFTbf2ehBh28tKhfFA2Jgh/RqOzfzXgRAP3b0MoLDzKXFtftlEV6YBQjwIGvfEJZDfEglaKFOSmYJ4ZtbA==

obuf@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==

pg-cloudflare@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==

pg-connection-string@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37"
integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==

[email protected]:
version "1.0.1"
resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==

[email protected]:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a"
integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==

pg-pool@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec"
integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==

pg-protocol@*, pg-protocol@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93"
integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==

pg-types@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
dependencies:
pg-int8 "1.0.1"
postgres-array "~2.0.0"
postgres-bytea "~1.0.0"
postgres-date "~1.0.4"
postgres-interval "^1.1.0"

pg-types@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d"
integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==
dependencies:
pg-int8 "1.0.1"
pg-numeric "1.0.2"
postgres-array "~3.0.1"
postgres-bytea "~3.0.0"
postgres-date "~2.1.0"
postgres-interval "^3.0.0"
postgres-range "^1.1.1"

pg@^8.13.1:
version "8.13.1"
resolved "https://registry.yarnpkg.com/pg/-/pg-8.13.1.tgz#6498d8b0a87ff76c2df7a32160309d3168c0c080"
integrity sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==
dependencies:
pg-connection-string "^2.7.0"
pg-pool "^3.7.0"
pg-protocol "^1.7.0"
pg-types "^2.1.0"
pgpass "1.x"
optionalDependencies:
pg-cloudflare "^1.1.1"

[email protected]:
version "1.0.5"
resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
dependencies:
split2 "^4.1.0"

postgres-array@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==

postgres-array@~3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98"
integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==

postgres-bytea@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==

postgres-bytea@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089"
integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==
dependencies:
obuf "~1.1.2"

postgres-date@~1.0.4:
version "1.0.7"
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==

postgres-date@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0"
integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==

postgres-interval@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
dependencies:
xtend "^4.0.0"

postgres-interval@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a"
integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==

postgres-range@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863"
integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==

split2@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==

typescript@^5.7.2:
version "5.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6"
Expand All @@ -23,3 +182,8 @@ undici-types@~6.20.0:
version "6.20.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433"
integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==

xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==

0 comments on commit 9f80f8c

Please sign in to comment.