@tricoteuses/senat 0.3.2 → 1.0.1
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/README.md +52 -0
- package/lib/config.d.ts +2 -0
- package/lib/config.js +49 -0
- package/lib/config.mjs +16 -0
- package/lib/config.ts +26 -0
- package/lib/databases.d.ts +11 -0
- package/lib/databases.js +125 -0
- package/lib/databases.mjs +26 -0
- package/lib/databases.ts +32 -0
- package/lib/datasets.d.ts +27 -0
- package/lib/datasets.js +85 -0
- package/lib/datasets.mjs +68 -0
- package/lib/datasets.ts +107 -0
- package/lib/fields.d.ts +10 -0
- package/lib/fields.js +68 -0
- package/lib/fields.mjs +22 -0
- package/lib/fields.ts +29 -0
- package/lib/index.d.ts +6 -5
- package/lib/index.js +236 -7
- package/lib/index.mjs +6 -1
- package/lib/index.ts +59 -0
- package/lib/inserters.d.ts +1 -1
- package/lib/inserters.js +65 -189
- package/lib/inserters.ts +520 -0
- package/lib/raw_types/ameli.d.ts +416 -410
- package/lib/raw_types/ameli.js +26 -144
- package/lib/raw_types/ameli.ts +601 -0
- package/lib/raw_types/debats.d.ts +82 -80
- package/lib/raw_types/debats.js +8 -42
- package/lib/raw_types/debats.ts +145 -0
- package/lib/raw_types/dosleg.d.ts +936 -920
- package/lib/raw_types/dosleg.js +5 -345
- package/lib/raw_types/dosleg.ts +2193 -0
- package/lib/raw_types/questions.d.ts +2 -2
- package/lib/raw_types/questions.js +3 -3
- package/lib/raw_types/questions.mjs +2 -2
- package/lib/raw_types/questions.ts +9 -0
- package/lib/raw_types/sens.d.ts +1180 -1176
- package/lib/raw_types/sens.js +3 -397
- package/lib/raw_types/sens.ts +2907 -0
- package/lib/scripts/images/transparent_150x192.jpg +0 -0
- package/lib/scripts/images/transparent_155x225.jpg +0 -0
- package/lib/scripts/retrieve_open_data.d.ts +1 -0
- package/lib/scripts/retrieve_open_data.js +366 -0
- package/lib/scripts/retrieve_open_data.mjs +215 -0
- package/lib/scripts/retrieve_open_data.ts +254 -0
- package/lib/scripts/retrieve_senateurs_photos.d.ts +1 -0
- package/lib/scripts/retrieve_senateurs_photos.js +268 -0
- package/lib/scripts/retrieve_senateurs_photos.mjs +164 -0
- package/lib/scripts/retrieve_senateurs_photos.ts +200 -0
- package/lib/scripts/retrieve_textes.d.ts +1 -0
- package/lib/scripts/retrieve_textes.js +177 -0
- package/lib/scripts/retrieve_textes.mjs +75 -0
- package/lib/scripts/retrieve_textes.ts +93 -0
- package/lib/strings.d.ts +1 -0
- package/lib/strings.js +49 -0
- package/lib/strings.mjs +18 -0
- package/lib/strings.ts +26 -0
- package/lib/types/ameli.d.ts +5 -0
- package/lib/types/ameli.js +7 -4
- package/lib/types/ameli.mjs +13 -1
- package/lib/types/ameli.ts +21 -0
- package/lib/types/debats.d.ts +2 -0
- package/lib/types/debats.js +4 -3
- package/lib/types/debats.mjs +2 -1
- package/lib/types/debats.ts +6 -0
- package/lib/types/dosleg.d.ts +28 -0
- package/lib/types/dosleg.js +30 -3
- package/lib/types/dosleg.mjs +151 -1
- package/lib/types/dosleg.ts +284 -0
- package/lib/types/questions.js +1 -1
- package/lib/types/questions.ts +0 -0
- package/lib/types/sens.d.ts +2 -0
- package/lib/types/sens.js +4 -3
- package/lib/types/sens.mjs +23 -1
- package/lib/types/sens.ts +36 -0
- package/lib/typings/windows-1252.d.js +2 -0
- package/lib/typings/windows-1252.d.mjs +2 -0
- package/lib/typings/windows-1252.d.ts +11 -0
- package/lib/validators/config.d.ts +1 -0
- package/lib/validators/config.js +121 -0
- package/lib/validators/config.mjs +54 -0
- package/lib/validators/config.ts +79 -0
- package/lib/validators/senat.d.ts +0 -0
- package/lib/validators/senat.js +28 -0
- package/lib/validators/senat.mjs +24 -0
- package/lib/validators/senat.ts +26 -0
- package/package.json +35 -4
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import commandLineArgs from "command-line-args";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
// import fetch from "node-fetch"
|
|
6
|
+
import path from "path";
|
|
7
|
+
// import stream from "stream"
|
|
8
|
+
import StreamZip from "node-stream-zip";
|
|
9
|
+
import readline from "readline";
|
|
10
|
+
// import util from "util"
|
|
11
|
+
import windows1252 from "windows-1252";
|
|
12
|
+
import config from "../config";
|
|
13
|
+
import { datasets, EnabledDatasets } from "../datasets";
|
|
14
|
+
const badWindows1252CharacterRegex = /[\u0080-\u009f]/g;
|
|
15
|
+
const optionsDefinitions = [
|
|
16
|
+
{
|
|
17
|
+
alias: "a",
|
|
18
|
+
help: "all options: fetch, unzip, repair-encoding, import, schema",
|
|
19
|
+
name: "all",
|
|
20
|
+
type: Boolean,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
alias: "c",
|
|
24
|
+
help: "create TypeScript interfaces from databases schemas into src/raw_types directory",
|
|
25
|
+
name: "schema",
|
|
26
|
+
type: Boolean,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
alias: "e",
|
|
30
|
+
help: "repair Windows CP 1252 encoding of SQL dumps",
|
|
31
|
+
name: "repair-encoding",
|
|
32
|
+
type: Boolean,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
alias: "f",
|
|
36
|
+
help: "fetch datasets instead of retrieving them from files",
|
|
37
|
+
name: "fetch",
|
|
38
|
+
type: Boolean,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
alias: "i",
|
|
42
|
+
help: "import SQL dumps into a freshly (re-)created database",
|
|
43
|
+
name: "import",
|
|
44
|
+
type: Boolean,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
alias: "s",
|
|
48
|
+
help: "don't log anything",
|
|
49
|
+
name: "silent",
|
|
50
|
+
type: Boolean,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
alias: "z",
|
|
54
|
+
help: "unzip SQL files",
|
|
55
|
+
name: "unzip",
|
|
56
|
+
type: Boolean,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
defaultOption: true,
|
|
60
|
+
help: "directory containing Sénat open data files",
|
|
61
|
+
name: "dataDir",
|
|
62
|
+
type: String,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
const options = commandLineArgs(optionsDefinitions);
|
|
66
|
+
// const pipeline = util.promisify(stream.pipeline)
|
|
67
|
+
async function retrieveDataset(dataDir, dataset) {
|
|
68
|
+
const zipFilename = dataset.url.substring(dataset.url.lastIndexOf("/") + 1);
|
|
69
|
+
const zipFilePath = path.join(dataDir, zipFilename);
|
|
70
|
+
if (options.all || options.fetch) {
|
|
71
|
+
// Fetch & save ZIP file.
|
|
72
|
+
if (!options.silent) {
|
|
73
|
+
console.log(`Loading ${dataset.title}: ${zipFilename}…`);
|
|
74
|
+
}
|
|
75
|
+
// Fetch fails with OpenSSL error: dh key too small.
|
|
76
|
+
// (so does "curl").
|
|
77
|
+
// const response = await fetch(dataset.url)
|
|
78
|
+
// if (!response.ok) {
|
|
79
|
+
// console.error(response.status, response.statusText)
|
|
80
|
+
// console.error(await response.text())
|
|
81
|
+
// throw new Error(`Fetch failed: ${dataset.url}`)
|
|
82
|
+
// }
|
|
83
|
+
// await pipeline(response.body!, fs.createWriteStream(zipFilePath))
|
|
84
|
+
fs.removeSync(zipFilePath);
|
|
85
|
+
execSync(`wget --quiet ${dataset.url}`, {
|
|
86
|
+
cwd: dataDir,
|
|
87
|
+
env: process.env,
|
|
88
|
+
encoding: "utf-8",
|
|
89
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const sqlFilename = `${dataset.database}.sql`;
|
|
93
|
+
const sqlFilePath = path.join(dataDir, sqlFilename);
|
|
94
|
+
if (options.all || options.unzip) {
|
|
95
|
+
if (!options.silent) {
|
|
96
|
+
console.log(`Unzipping ${dataset.title}: ${zipFilename}…`);
|
|
97
|
+
}
|
|
98
|
+
fs.removeSync(sqlFilePath);
|
|
99
|
+
const zip = new StreamZip({
|
|
100
|
+
file: zipFilePath,
|
|
101
|
+
storeEntries: true,
|
|
102
|
+
});
|
|
103
|
+
await new Promise((resolve, reject) => {
|
|
104
|
+
zip.on("ready", () => {
|
|
105
|
+
zip.extract(null, dataDir, (err, _count) => {
|
|
106
|
+
zip.close();
|
|
107
|
+
if (err) {
|
|
108
|
+
reject(err);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
resolve(null);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
if (dataset.repairZip !== undefined) {
|
|
117
|
+
if (!options.silent) {
|
|
118
|
+
console.log(`Repairing Zip path ${dataset.title}: ${sqlFilename}…`);
|
|
119
|
+
}
|
|
120
|
+
dataset.repairZip(dataset, dataDir);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if ((options.all || options["repair-encoding"]) && dataset.repairEncoding) {
|
|
124
|
+
if (!options.silent) {
|
|
125
|
+
console.log(`Repairing Windows CP1252 encoding of ${dataset.title}: ${sqlFilename}…`);
|
|
126
|
+
}
|
|
127
|
+
const repairedSqlFilePath = sqlFilePath + ".repaired";
|
|
128
|
+
const repairedSqlWriter = fs.createWriteStream(repairedSqlFilePath, {
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
});
|
|
131
|
+
const lineReader = readline.createInterface({
|
|
132
|
+
input: fs.createReadStream(sqlFilePath, { encoding: "utf8" }),
|
|
133
|
+
crlfDelay: Infinity,
|
|
134
|
+
});
|
|
135
|
+
for await (const line of lineReader) {
|
|
136
|
+
repairedSqlWriter.write(line.replace(badWindows1252CharacterRegex, (match) => windows1252.decode(match, { mode: "fatal" })) + "\n");
|
|
137
|
+
}
|
|
138
|
+
repairedSqlWriter.end();
|
|
139
|
+
await fs.move(repairedSqlFilePath, sqlFilePath, { overwrite: true });
|
|
140
|
+
}
|
|
141
|
+
if (options.all || options.import) {
|
|
142
|
+
if (!options.silent) {
|
|
143
|
+
console.log(`Importing ${dataset.title}: ${sqlFilename}…`);
|
|
144
|
+
}
|
|
145
|
+
execSync(`psql -c "DROP DATABASE IF EXISTS ${dataset.database}"`, {
|
|
146
|
+
cwd: dataDir,
|
|
147
|
+
env: process.env,
|
|
148
|
+
encoding: "utf-8",
|
|
149
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
150
|
+
});
|
|
151
|
+
execSync(`psql -c "CREATE DATABASE ${dataset.database} WITH OWNER opendata"`, {
|
|
152
|
+
cwd: dataDir,
|
|
153
|
+
env: process.env,
|
|
154
|
+
encoding: "utf-8",
|
|
155
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
156
|
+
});
|
|
157
|
+
execSync(`psql -f ${sqlFilename} ${dataset.database}`, {
|
|
158
|
+
cwd: dataDir,
|
|
159
|
+
env: process.env,
|
|
160
|
+
encoding: "utf-8",
|
|
161
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (options.schema) {
|
|
165
|
+
const definitionsDir = path.resolve("src", "raw_types");
|
|
166
|
+
assert(fs.statSync(definitionsDir).isDirectory());
|
|
167
|
+
if (!options.silent) {
|
|
168
|
+
console.log(`Creating TypeScript definitions from schema of database ${dataset.database}…`);
|
|
169
|
+
}
|
|
170
|
+
const dbConnectionString = `postgres://${process.env.PGUSER}:${process.env.PGPASSWORD}@${process.env.PGHOST}:${process.env.PGPORT}/${dataset.database}`;
|
|
171
|
+
const definitionFilePath = path.join(definitionsDir, `${dataset.database}.ts`);
|
|
172
|
+
execSync(`npx schemats generate -c ${dbConnectionString} -s public -o ${definitionFilePath}`, {
|
|
173
|
+
// cwd: dataDir,
|
|
174
|
+
env: process.env,
|
|
175
|
+
encoding: "utf-8",
|
|
176
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
177
|
+
});
|
|
178
|
+
const definition = fs.readFileSync(definitionFilePath, { encoding: "utf8" });
|
|
179
|
+
const definitionRepaired = definition
|
|
180
|
+
.replace(/\r\n/g, "\n")
|
|
181
|
+
.replace(/AUTO-GENERATED FILE @ \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/, "AUTO-GENERATED FILE");
|
|
182
|
+
fs.writeFileSync(definitionFilePath, definitionRepaired);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function retrieveOpenData(enabledDatasets) {
|
|
186
|
+
const dataDir = options.dataDir;
|
|
187
|
+
assert(dataDir, "Missing argument: data directory");
|
|
188
|
+
process.env = {
|
|
189
|
+
...process.env,
|
|
190
|
+
PGHOST: process.env.PGHOST || config.db.host,
|
|
191
|
+
PGPORT: process.env.PGPORT || config.db.port,
|
|
192
|
+
PGUSER: process.env.PGUSER || config.db.user,
|
|
193
|
+
PGPASSWORD: process.env.PGPASSWORD || config.db.password
|
|
194
|
+
};
|
|
195
|
+
assert(process.env.PGHOST
|
|
196
|
+
&& process.env.PGPORT
|
|
197
|
+
&& process.env.PGUSER
|
|
198
|
+
&& process.env.PGPASSWORD, 'Missing database configuration: environment variables PGHOST, PGPORT, PGUSER and PGPASSWORD or TRICOTEUSES_SENAT_DB_* in .env file');
|
|
199
|
+
const choosenDatasets = [
|
|
200
|
+
enabledDatasets & EnabledDatasets.Ameli ? datasets.ameli : null,
|
|
201
|
+
enabledDatasets & EnabledDatasets.Debats ? datasets.debats : null,
|
|
202
|
+
enabledDatasets & EnabledDatasets.DosLeg ? datasets.dosleg : null,
|
|
203
|
+
enabledDatasets & EnabledDatasets.Questions ? datasets.questions : null,
|
|
204
|
+
enabledDatasets & EnabledDatasets.Sens ? datasets.sens : null,
|
|
205
|
+
].filter((dataset) => dataset !== null);
|
|
206
|
+
// await Promise.all(choosenDatasets.map(dataset => retrieveDataset(dataDir, dataset)))
|
|
207
|
+
for (const dataset of choosenDatasets) {
|
|
208
|
+
await retrieveDataset(dataDir, dataset);
|
|
209
|
+
}
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
retrieveOpenData(EnabledDatasets.All).catch((error) => {
|
|
213
|
+
console.log(error);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
});
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import assert from "assert"
|
|
2
|
+
import { execSync } from "child_process"
|
|
3
|
+
import commandLineArgs from "command-line-args"
|
|
4
|
+
import fs from "fs-extra"
|
|
5
|
+
// import fetch from "node-fetch"
|
|
6
|
+
import path from "path"
|
|
7
|
+
// import stream from "stream"
|
|
8
|
+
import StreamZip from "node-stream-zip"
|
|
9
|
+
import readline from "readline"
|
|
10
|
+
// import util from "util"
|
|
11
|
+
import windows1252 from "windows-1252"
|
|
12
|
+
|
|
13
|
+
import config from "../config"
|
|
14
|
+
import { datasets, Dataset, EnabledDatasets } from "../datasets"
|
|
15
|
+
|
|
16
|
+
const badWindows1252CharacterRegex = /[\u0080-\u009f]/g
|
|
17
|
+
const optionsDefinitions = [
|
|
18
|
+
{
|
|
19
|
+
alias: "a",
|
|
20
|
+
help: "all options: fetch, unzip, repair-encoding, import, schema",
|
|
21
|
+
name: "all",
|
|
22
|
+
type: Boolean,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
alias: "c",
|
|
26
|
+
help:
|
|
27
|
+
"create TypeScript interfaces from databases schemas into src/raw_types directory",
|
|
28
|
+
name: "schema",
|
|
29
|
+
type: Boolean,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
alias: "e",
|
|
33
|
+
help: "repair Windows CP 1252 encoding of SQL dumps",
|
|
34
|
+
name: "repair-encoding",
|
|
35
|
+
type: Boolean,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
alias: "f",
|
|
39
|
+
help: "fetch datasets instead of retrieving them from files",
|
|
40
|
+
name: "fetch",
|
|
41
|
+
type: Boolean,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
alias: "i",
|
|
45
|
+
help: "import SQL dumps into a freshly (re-)created database",
|
|
46
|
+
name: "import",
|
|
47
|
+
type: Boolean,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
alias: "s",
|
|
51
|
+
help: "don't log anything",
|
|
52
|
+
name: "silent",
|
|
53
|
+
type: Boolean,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
alias: "z",
|
|
57
|
+
help: "unzip SQL files",
|
|
58
|
+
name: "unzip",
|
|
59
|
+
type: Boolean,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
defaultOption: true,
|
|
63
|
+
help: "directory containing Sénat open data files",
|
|
64
|
+
name: "dataDir",
|
|
65
|
+
type: String,
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
const options = commandLineArgs(optionsDefinitions)
|
|
69
|
+
|
|
70
|
+
// const pipeline = util.promisify(stream.pipeline)
|
|
71
|
+
|
|
72
|
+
async function retrieveDataset(
|
|
73
|
+
dataDir: string,
|
|
74
|
+
dataset: Dataset,
|
|
75
|
+
): Promise<void> {
|
|
76
|
+
const zipFilename = dataset.url.substring(dataset.url.lastIndexOf("/") + 1)
|
|
77
|
+
const zipFilePath = path.join(dataDir, zipFilename)
|
|
78
|
+
if (options.all || options.fetch) {
|
|
79
|
+
// Fetch & save ZIP file.
|
|
80
|
+
if (!options.silent) {
|
|
81
|
+
console.log(`Loading ${dataset.title}: ${zipFilename}…`)
|
|
82
|
+
}
|
|
83
|
+
// Fetch fails with OpenSSL error: dh key too small.
|
|
84
|
+
// (so does "curl").
|
|
85
|
+
// const response = await fetch(dataset.url)
|
|
86
|
+
// if (!response.ok) {
|
|
87
|
+
// console.error(response.status, response.statusText)
|
|
88
|
+
// console.error(await response.text())
|
|
89
|
+
// throw new Error(`Fetch failed: ${dataset.url}`)
|
|
90
|
+
// }
|
|
91
|
+
// await pipeline(response.body!, fs.createWriteStream(zipFilePath))
|
|
92
|
+
fs.removeSync(zipFilePath)
|
|
93
|
+
execSync(`wget --quiet ${dataset.url}`, {
|
|
94
|
+
cwd: dataDir,
|
|
95
|
+
env: process.env,
|
|
96
|
+
encoding: "utf-8",
|
|
97
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const sqlFilename = `${dataset.database}.sql`
|
|
102
|
+
const sqlFilePath = path.join(dataDir, sqlFilename)
|
|
103
|
+
if (options.all || options.unzip) {
|
|
104
|
+
if (!options.silent) {
|
|
105
|
+
console.log(`Unzipping ${dataset.title}: ${zipFilename}…`)
|
|
106
|
+
}
|
|
107
|
+
fs.removeSync(sqlFilePath)
|
|
108
|
+
const zip = new StreamZip({
|
|
109
|
+
file: zipFilePath,
|
|
110
|
+
storeEntries: true,
|
|
111
|
+
})
|
|
112
|
+
await new Promise((resolve, reject) => {
|
|
113
|
+
zip.on("ready", () => {
|
|
114
|
+
zip.extract(null, dataDir, (err?: any, _count?: number) => {
|
|
115
|
+
zip.close()
|
|
116
|
+
if (err) {
|
|
117
|
+
reject(err)
|
|
118
|
+
} else {
|
|
119
|
+
resolve(null)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
if (dataset.repairZip !== undefined) {
|
|
125
|
+
if (!options.silent) {
|
|
126
|
+
console.log(`Repairing Zip path ${dataset.title}: ${sqlFilename}…`)
|
|
127
|
+
}
|
|
128
|
+
dataset.repairZip(dataset, dataDir)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ((options.all || options["repair-encoding"]) && dataset.repairEncoding) {
|
|
133
|
+
if (!options.silent) {
|
|
134
|
+
console.log(
|
|
135
|
+
`Repairing Windows CP1252 encoding of ${dataset.title}: ${sqlFilename}…`,
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
const repairedSqlFilePath = sqlFilePath + ".repaired"
|
|
139
|
+
const repairedSqlWriter = fs.createWriteStream(repairedSqlFilePath, {
|
|
140
|
+
encoding: "utf8",
|
|
141
|
+
})
|
|
142
|
+
const lineReader = readline.createInterface({
|
|
143
|
+
input: fs.createReadStream(sqlFilePath, { encoding: "utf8" }),
|
|
144
|
+
crlfDelay: Infinity,
|
|
145
|
+
})
|
|
146
|
+
for await (const line of lineReader) {
|
|
147
|
+
repairedSqlWriter.write(
|
|
148
|
+
line.replace(badWindows1252CharacterRegex, (match) =>
|
|
149
|
+
windows1252.decode(match, { mode: "fatal" }),
|
|
150
|
+
) + "\n",
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
repairedSqlWriter.end()
|
|
154
|
+
await fs.move(repairedSqlFilePath, sqlFilePath, { overwrite: true })
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (options.all || options.import) {
|
|
158
|
+
if (!options.silent) {
|
|
159
|
+
console.log(`Importing ${dataset.title}: ${sqlFilename}…`)
|
|
160
|
+
}
|
|
161
|
+
execSync(`psql -c "DROP DATABASE IF EXISTS ${dataset.database}"`, {
|
|
162
|
+
cwd: dataDir,
|
|
163
|
+
env: process.env,
|
|
164
|
+
encoding: "utf-8",
|
|
165
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
166
|
+
})
|
|
167
|
+
execSync(
|
|
168
|
+
`psql -c "CREATE DATABASE ${dataset.database} WITH OWNER opendata"`,
|
|
169
|
+
{
|
|
170
|
+
cwd: dataDir,
|
|
171
|
+
env: process.env,
|
|
172
|
+
encoding: "utf-8",
|
|
173
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
execSync(`psql -f ${sqlFilename} ${dataset.database}`, {
|
|
177
|
+
cwd: dataDir,
|
|
178
|
+
env: process.env,
|
|
179
|
+
encoding: "utf-8",
|
|
180
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (options.schema) {
|
|
185
|
+
const definitionsDir = path.resolve("src", "raw_types")
|
|
186
|
+
assert(fs.statSync(definitionsDir).isDirectory())
|
|
187
|
+
if (!options.silent) {
|
|
188
|
+
console.log(
|
|
189
|
+
`Creating TypeScript definitions from schema of database ${dataset.database}…`,
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
const dbConnectionString = `postgres://${process.env.PGUSER}:${process.env.PGPASSWORD}@${process.env.PGHOST}:${process.env.PGPORT}/${dataset.database}`
|
|
193
|
+
const definitionFilePath = path.join(
|
|
194
|
+
definitionsDir,
|
|
195
|
+
`${dataset.database}.ts`,
|
|
196
|
+
)
|
|
197
|
+
execSync(
|
|
198
|
+
`npx schemats generate -c ${dbConnectionString} -s public -o ${definitionFilePath}`,
|
|
199
|
+
{
|
|
200
|
+
// cwd: dataDir,
|
|
201
|
+
env: process.env,
|
|
202
|
+
encoding: "utf-8",
|
|
203
|
+
// stdio: ["ignore", "ignore", "pipe"],
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
const definition = fs.readFileSync(definitionFilePath, { encoding: "utf8" })
|
|
207
|
+
const definitionRepaired = definition
|
|
208
|
+
.replace(/\r\n/g, "\n")
|
|
209
|
+
.replace(
|
|
210
|
+
/AUTO-GENERATED FILE @ \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/,
|
|
211
|
+
"AUTO-GENERATED FILE",
|
|
212
|
+
)
|
|
213
|
+
fs.writeFileSync(definitionFilePath, definitionRepaired)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function retrieveOpenData(
|
|
218
|
+
enabledDatasets: EnabledDatasets,
|
|
219
|
+
): Promise<void> {
|
|
220
|
+
const dataDir = options.dataDir
|
|
221
|
+
assert(dataDir, "Missing argument: data directory")
|
|
222
|
+
|
|
223
|
+
process.env = {
|
|
224
|
+
...process.env,
|
|
225
|
+
PGHOST: process.env.PGHOST || config.db.host,
|
|
226
|
+
PGPORT: process.env.PGPORT || config.db.port,
|
|
227
|
+
PGUSER: process.env.PGUSER || config.db.user,
|
|
228
|
+
PGPASSWORD: process.env.PGPASSWORD || config.db.password
|
|
229
|
+
}
|
|
230
|
+
assert(process.env.PGHOST
|
|
231
|
+
&& process.env.PGPORT
|
|
232
|
+
&& process.env.PGUSER
|
|
233
|
+
&& process.env.PGPASSWORD,
|
|
234
|
+
'Missing database configuration: environment variables PGHOST, PGPORT, PGUSER and PGPASSWORD or TRICOTEUSES_SENAT_DB_* in .env file'
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
const choosenDatasets: Dataset[] = [
|
|
238
|
+
enabledDatasets & EnabledDatasets.Ameli ? datasets.ameli : null,
|
|
239
|
+
enabledDatasets & EnabledDatasets.Debats ? datasets.debats : null,
|
|
240
|
+
enabledDatasets & EnabledDatasets.DosLeg ? datasets.dosleg : null,
|
|
241
|
+
enabledDatasets & EnabledDatasets.Questions ? datasets.questions : null,
|
|
242
|
+
enabledDatasets & EnabledDatasets.Sens ? datasets.sens : null,
|
|
243
|
+
].filter((dataset: Dataset | null) => dataset !== null) as Dataset[]
|
|
244
|
+
// await Promise.all(choosenDatasets.map(dataset => retrieveDataset(dataDir, dataset)))
|
|
245
|
+
for (const dataset of choosenDatasets) {
|
|
246
|
+
await retrieveDataset(dataDir, dataset)
|
|
247
|
+
}
|
|
248
|
+
process.exit(0)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
retrieveOpenData(EnabledDatasets.All).catch((error) => {
|
|
252
|
+
console.log(error)
|
|
253
|
+
process.exit(1)
|
|
254
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|