├── .gitignore ├── .vscode └── settings.json ├── README.md ├── docker-compose.yml ├── insert-in-batches.ts ├── insert-one-by-one.ts ├── no-streams.ts ├── package-lock.json ├── package.json ├── prisma ├── dev.db ├── migrations │ ├── 20240705200155_db │ │ └── migration.sql │ └── migration_lock.toml └── schema.prisma └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # Keep environment variables out of version control 3 | .env 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotenv.enableAutocloaking": false 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Large JSON file process with Streams 2 | 3 | Downloading a large JSON file and saving its content to Database using: 4 | 5 | - No stream, download full JSON and insert one-by-one on database; 6 | - Stream download and insert one-by-one on database; 7 | - Stream download and insert in batches on database; 8 | 9 | ## No Streams 10 | 11 | Memory usage: 537.05MB 12 | 13 | Executed in 9.23 secs fish external 14 | usr time 11.99 secs 82.00 micros 11.99 secs 15 | sys time 2.21 secs 473.00 micros 2.21 secs 16 | 17 | ## Insert one-by-one 18 | 19 | Memory usage: 19MB 20 | 21 | Executed in 9.80 secs fish external 22 | usr time 12.96 secs 63.00 micros 12.96 secs 23 | sys time 1.86 secs 850.00 micros 1.85 secs 24 | 25 | ## Insert in batches (1000) 26 | 27 | Memory usage: 58MB 28 | 29 | Executed in 3.67 secs fish external 30 | usr time 3.33 secs 16.40 millis 3.31 secs 31 | sys time 0.23 secs 3.46 millis 0.23 secs 32 | 33 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | pg: 5 | image: bitnami/postgresql:latest 6 | ports: 7 | - '5432:5432' 8 | environment: 9 | - POSTGRES_USER=docker 10 | - POSTGRES_PASSWORD=docker 11 | - POSTGRES_DB=pedro 12 | volumes: 13 | - pedro_pg:/bitnami/postgresql 14 | 15 | volumes: 16 | pedro_pg: 17 | -------------------------------------------------------------------------------- /insert-in-batches.ts: -------------------------------------------------------------------------------- 1 | import { createGunzip } from 'node:zlib'; 2 | import axios from 'axios'; 3 | import { parser } from 'stream-json/Parser'; 4 | import { streamArray } from 'stream-json/streamers/StreamArray'; 5 | import { pick } from 'stream-json/filters/Pick'; 6 | import { batch } from 'stream-json/utils/Batch'; 7 | import { chain } from 'stream-chain'; 8 | import { type Readable } from 'node:stream'; 9 | import { PrismaClient } from '@prisma/client'; 10 | 11 | const prisma = new PrismaClient() 12 | 13 | const downloadUrl = 'https://www.infojobs.com.br/OfertasMulheresPositivas.json.gz' 14 | 15 | interface Job { 16 | title: string; 17 | date: string; 18 | referencenumber: string; 19 | url: string; 20 | company: string; 21 | sourcename: string; 22 | city?: string | null; 23 | state: string; 24 | country: string; 25 | postalcode?: null; 26 | description?: string | null; 27 | salary: string; 28 | education?: string | null; 29 | jobtype?: string | null; 30 | category: string; 31 | experience?: string | null; 32 | } 33 | 34 | interface StreamJob { 35 | key: number 36 | value: Job 37 | } 38 | 39 | async function saveJobsToDatabase(jobs: StreamJob[]) { 40 | try { 41 | await prisma.job.createMany({ 42 | data: jobs.map(job => { 43 | return { 44 | company_id: '30', 45 | code: String(job.value.referencenumber), 46 | } 47 | }), 48 | skipDuplicates: true, 49 | }) 50 | 51 | console.log(`Inserted ${jobs.length} jobs.`) 52 | } catch (err) { 53 | console.error(err) 54 | } 55 | } 56 | 57 | function consumeJobsStream(stream: Readable) { 58 | const unzip = createGunzip() 59 | 60 | const pipeline = chain([ 61 | stream, 62 | unzip, 63 | parser(), 64 | pick({ filter: "source.job" }), 65 | streamArray(), 66 | batch({ batchSize: 500 }) 67 | ]) 68 | 69 | pipeline 70 | .on('data', (data: StreamJob[]) => { 71 | saveJobsToDatabase(data) 72 | }) 73 | .on('error', (err: any) => { 74 | console.error('An error occurred:', err); 75 | }) 76 | .on('end', () => { 77 | const memoryUsage = process.memoryUsage(); 78 | const memoryUsageInMB = { 79 | rss: (memoryUsage.rss / 1024 / 1024).toFixed(2), 80 | heapTotal: (memoryUsage.heapTotal / 1024 / 1024).toFixed(2), 81 | heapUsed: (memoryUsage.heapUsed / 1024 / 1024).toFixed(2), 82 | external: (memoryUsage.external / 1024 / 1024).toFixed(2), 83 | }; 84 | 85 | console.log(memoryUsageInMB); 86 | }); 87 | } 88 | 89 | axios.get(downloadUrl, { responseType: 'stream' }) 90 | .then(response => consumeJobsStream(response.data)) 91 | 92 | -------------------------------------------------------------------------------- /insert-one-by-one.ts: -------------------------------------------------------------------------------- 1 | import { createGunzip } from 'node:zlib'; 2 | import axios from 'axios'; 3 | import { parser } from 'stream-json/Parser'; 4 | import { streamArray } from 'stream-json/streamers/StreamArray'; 5 | import { pick } from 'stream-json/filters/Pick'; 6 | import { chain } from 'stream-chain'; 7 | import { type Readable } from 'node:stream'; 8 | import { Prisma, PrismaClient } from '@prisma/client'; 9 | 10 | const prisma = new PrismaClient() 11 | 12 | const downloadUrl = 'https://www.infojobs.com.br/OfertasMulheresPositivas.json.gz' 13 | 14 | interface Job { 15 | title: string; 16 | date: string; 17 | referencenumber: string; 18 | url: string; 19 | company: string; 20 | sourcename: string; 21 | city?: string | null; 22 | state: string; 23 | country: string; 24 | postalcode?: null; 25 | description?: string | null; 26 | salary: string; 27 | education?: string | null; 28 | jobtype?: string | null; 29 | category: string; 30 | experience?: string | null; 31 | } 32 | 33 | interface StreamJob { 34 | key: number 35 | value: Job 36 | } 37 | 38 | async function saveJobsToDatabase(job: StreamJob) { 39 | try { 40 | await prisma.job.create({ 41 | data: { 42 | company_id: '30', 43 | code: String(job.value.referencenumber), 44 | } 45 | }) 46 | 47 | console.log(`Inserted ${job.key}.`) 48 | } catch (err) { 49 | if (err instanceof Prisma.PrismaClientKnownRequestError) { 50 | if (err.code === 'P2002') { 51 | console.log(`Skipped ${job.key}.`) 52 | return 53 | } 54 | } 55 | 56 | console.error(err) 57 | } 58 | } 59 | 60 | function consumeJobsStream(stream: Readable) { 61 | const unzip = createGunzip() 62 | 63 | const pipeline = chain([ 64 | stream, 65 | unzip, 66 | parser(), 67 | pick({ filter: "source.job" }), 68 | streamArray(), 69 | ]) 70 | 71 | pipeline 72 | .on('data', (data: StreamJob) => { 73 | saveJobsToDatabase(data) 74 | }) 75 | .on('error', (err: any) => { 76 | console.error('An error occurred:', err); 77 | }) 78 | .on('end', () => { 79 | const memoryUsage = process.memoryUsage(); 80 | const memoryUsageInMB = { 81 | rss: (memoryUsage.rss / 1024 / 1024).toFixed(2), 82 | heapTotal: (memoryUsage.heapTotal / 1024 / 1024).toFixed(2), 83 | heapUsed: (memoryUsage.heapUsed / 1024 / 1024).toFixed(2), 84 | external: (memoryUsage.external / 1024 / 1024).toFixed(2), 85 | }; 86 | 87 | console.log(memoryUsageInMB); 88 | }); 89 | } 90 | 91 | axios.get(downloadUrl, { responseType: 'stream' }) 92 | .then(response => consumeJobsStream(response.data)) 93 | 94 | -------------------------------------------------------------------------------- /no-streams.ts: -------------------------------------------------------------------------------- 1 | import { gunzip } from 'node:zlib'; 2 | import axios from 'axios'; 3 | import { Prisma, PrismaClient } from '@prisma/client'; 4 | 5 | const prisma = new PrismaClient() 6 | 7 | const downloadUrl = 'https://www.infojobs.com.br/OfertasMulheresPositivas.json.gz' 8 | 9 | interface Job { 10 | title: string; 11 | date: string; 12 | referencenumber: string; 13 | url: string; 14 | company: string; 15 | sourcename: string; 16 | city?: string | null; 17 | state: string; 18 | country: string; 19 | postalcode?: null; 20 | description?: string | null; 21 | salary: string; 22 | education?: string | null; 23 | jobtype?: string | null; 24 | category: string; 25 | experience?: string | null; 26 | } 27 | 28 | async function saveJobToDatabase(job: Job) { 29 | try { 30 | await prisma.job.create({ 31 | data: { 32 | company_id: '30', 33 | code: String(job.referencenumber), 34 | } 35 | }) 36 | } catch (err) { 37 | if (err instanceof Prisma.PrismaClientKnownRequestError) { 38 | if (err.code === 'P2002') { 39 | return 40 | } 41 | } 42 | 43 | console.error(err) 44 | } 45 | } 46 | 47 | function consumeResponse(response: ArrayBuffer) { 48 | gunzip(response, async (err, data) => { 49 | if (err) { 50 | console.error(err) 51 | process.exit() 52 | } 53 | 54 | const jobs = JSON.parse(data.toString()).source.job 55 | 56 | await Promise.all(jobs.map(async (job: Job) => { 57 | await saveJobToDatabase(job) 58 | })) 59 | 60 | const memoryUsage = process.memoryUsage(); 61 | const memoryUsageInMB = { 62 | rss: (memoryUsage.rss / 1024 / 1024).toFixed(2), 63 | heapTotal: (memoryUsage.heapTotal / 1024 / 1024).toFixed(2), 64 | heapUsed: (memoryUsage.heapUsed / 1024 / 1024).toFixed(2), 65 | external: (memoryUsage.external / 1024 / 1024).toFixed(2), 66 | }; 67 | 68 | console.log(memoryUsageInMB); 69 | }) 70 | } 71 | 72 | axios.get(downloadUrl, { responseType: 'arraybuffer' }) 73 | .then(response => consumeResponse(response.data)) 74 | 75 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "read-node-gzip", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "read-node-gzip", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@prisma/client": "5.16.1", 13 | "axios": "1.7.2", 14 | "stream-chain": "2.2.5", 15 | "stream-json": "1.8.0" 16 | }, 17 | "devDependencies": { 18 | "@tsconfig/node20": "20.1.4", 19 | "@types/node": "20.14.9", 20 | "@types/stream-json": "1.7.7", 21 | "prisma": "5.16.1", 22 | "tsx": "4.16.2", 23 | "typescript": "5.5.3" 24 | } 25 | }, 26 | "node_modules/@esbuild/aix-ppc64": { 27 | "version": "0.21.5", 28 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", 29 | "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", 30 | "cpu": [ 31 | "ppc64" 32 | ], 33 | "dev": true, 34 | "optional": true, 35 | "os": [ 36 | "aix" 37 | ], 38 | "engines": { 39 | "node": ">=12" 40 | } 41 | }, 42 | "node_modules/@esbuild/android-arm": { 43 | "version": "0.21.5", 44 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", 45 | "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", 46 | "cpu": [ 47 | "arm" 48 | ], 49 | "dev": true, 50 | "optional": true, 51 | "os": [ 52 | "android" 53 | ], 54 | "engines": { 55 | "node": ">=12" 56 | } 57 | }, 58 | "node_modules/@esbuild/android-arm64": { 59 | "version": "0.21.5", 60 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", 61 | "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", 62 | "cpu": [ 63 | "arm64" 64 | ], 65 | "dev": true, 66 | "optional": true, 67 | "os": [ 68 | "android" 69 | ], 70 | "engines": { 71 | "node": ">=12" 72 | } 73 | }, 74 | "node_modules/@esbuild/android-x64": { 75 | "version": "0.21.5", 76 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", 77 | "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", 78 | "cpu": [ 79 | "x64" 80 | ], 81 | "dev": true, 82 | "optional": true, 83 | "os": [ 84 | "android" 85 | ], 86 | "engines": { 87 | "node": ">=12" 88 | } 89 | }, 90 | "node_modules/@esbuild/darwin-arm64": { 91 | "version": "0.21.5", 92 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", 93 | "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", 94 | "cpu": [ 95 | "arm64" 96 | ], 97 | "dev": true, 98 | "optional": true, 99 | "os": [ 100 | "darwin" 101 | ], 102 | "engines": { 103 | "node": ">=12" 104 | } 105 | }, 106 | "node_modules/@esbuild/darwin-x64": { 107 | "version": "0.21.5", 108 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", 109 | "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", 110 | "cpu": [ 111 | "x64" 112 | ], 113 | "dev": true, 114 | "optional": true, 115 | "os": [ 116 | "darwin" 117 | ], 118 | "engines": { 119 | "node": ">=12" 120 | } 121 | }, 122 | "node_modules/@esbuild/freebsd-arm64": { 123 | "version": "0.21.5", 124 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", 125 | "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", 126 | "cpu": [ 127 | "arm64" 128 | ], 129 | "dev": true, 130 | "optional": true, 131 | "os": [ 132 | "freebsd" 133 | ], 134 | "engines": { 135 | "node": ">=12" 136 | } 137 | }, 138 | "node_modules/@esbuild/freebsd-x64": { 139 | "version": "0.21.5", 140 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", 141 | "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", 142 | "cpu": [ 143 | "x64" 144 | ], 145 | "dev": true, 146 | "optional": true, 147 | "os": [ 148 | "freebsd" 149 | ], 150 | "engines": { 151 | "node": ">=12" 152 | } 153 | }, 154 | "node_modules/@esbuild/linux-arm": { 155 | "version": "0.21.5", 156 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", 157 | "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", 158 | "cpu": [ 159 | "arm" 160 | ], 161 | "dev": true, 162 | "optional": true, 163 | "os": [ 164 | "linux" 165 | ], 166 | "engines": { 167 | "node": ">=12" 168 | } 169 | }, 170 | "node_modules/@esbuild/linux-arm64": { 171 | "version": "0.21.5", 172 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", 173 | "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", 174 | "cpu": [ 175 | "arm64" 176 | ], 177 | "dev": true, 178 | "optional": true, 179 | "os": [ 180 | "linux" 181 | ], 182 | "engines": { 183 | "node": ">=12" 184 | } 185 | }, 186 | "node_modules/@esbuild/linux-ia32": { 187 | "version": "0.21.5", 188 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", 189 | "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", 190 | "cpu": [ 191 | "ia32" 192 | ], 193 | "dev": true, 194 | "optional": true, 195 | "os": [ 196 | "linux" 197 | ], 198 | "engines": { 199 | "node": ">=12" 200 | } 201 | }, 202 | "node_modules/@esbuild/linux-loong64": { 203 | "version": "0.21.5", 204 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", 205 | "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", 206 | "cpu": [ 207 | "loong64" 208 | ], 209 | "dev": true, 210 | "optional": true, 211 | "os": [ 212 | "linux" 213 | ], 214 | "engines": { 215 | "node": ">=12" 216 | } 217 | }, 218 | "node_modules/@esbuild/linux-mips64el": { 219 | "version": "0.21.5", 220 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", 221 | "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", 222 | "cpu": [ 223 | "mips64el" 224 | ], 225 | "dev": true, 226 | "optional": true, 227 | "os": [ 228 | "linux" 229 | ], 230 | "engines": { 231 | "node": ">=12" 232 | } 233 | }, 234 | "node_modules/@esbuild/linux-ppc64": { 235 | "version": "0.21.5", 236 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", 237 | "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", 238 | "cpu": [ 239 | "ppc64" 240 | ], 241 | "dev": true, 242 | "optional": true, 243 | "os": [ 244 | "linux" 245 | ], 246 | "engines": { 247 | "node": ">=12" 248 | } 249 | }, 250 | "node_modules/@esbuild/linux-riscv64": { 251 | "version": "0.21.5", 252 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", 253 | "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", 254 | "cpu": [ 255 | "riscv64" 256 | ], 257 | "dev": true, 258 | "optional": true, 259 | "os": [ 260 | "linux" 261 | ], 262 | "engines": { 263 | "node": ">=12" 264 | } 265 | }, 266 | "node_modules/@esbuild/linux-s390x": { 267 | "version": "0.21.5", 268 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", 269 | "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", 270 | "cpu": [ 271 | "s390x" 272 | ], 273 | "dev": true, 274 | "optional": true, 275 | "os": [ 276 | "linux" 277 | ], 278 | "engines": { 279 | "node": ">=12" 280 | } 281 | }, 282 | "node_modules/@esbuild/linux-x64": { 283 | "version": "0.21.5", 284 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", 285 | "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", 286 | "cpu": [ 287 | "x64" 288 | ], 289 | "dev": true, 290 | "optional": true, 291 | "os": [ 292 | "linux" 293 | ], 294 | "engines": { 295 | "node": ">=12" 296 | } 297 | }, 298 | "node_modules/@esbuild/netbsd-x64": { 299 | "version": "0.21.5", 300 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", 301 | "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", 302 | "cpu": [ 303 | "x64" 304 | ], 305 | "dev": true, 306 | "optional": true, 307 | "os": [ 308 | "netbsd" 309 | ], 310 | "engines": { 311 | "node": ">=12" 312 | } 313 | }, 314 | "node_modules/@esbuild/openbsd-x64": { 315 | "version": "0.21.5", 316 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", 317 | "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", 318 | "cpu": [ 319 | "x64" 320 | ], 321 | "dev": true, 322 | "optional": true, 323 | "os": [ 324 | "openbsd" 325 | ], 326 | "engines": { 327 | "node": ">=12" 328 | } 329 | }, 330 | "node_modules/@esbuild/sunos-x64": { 331 | "version": "0.21.5", 332 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", 333 | "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", 334 | "cpu": [ 335 | "x64" 336 | ], 337 | "dev": true, 338 | "optional": true, 339 | "os": [ 340 | "sunos" 341 | ], 342 | "engines": { 343 | "node": ">=12" 344 | } 345 | }, 346 | "node_modules/@esbuild/win32-arm64": { 347 | "version": "0.21.5", 348 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", 349 | "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", 350 | "cpu": [ 351 | "arm64" 352 | ], 353 | "dev": true, 354 | "optional": true, 355 | "os": [ 356 | "win32" 357 | ], 358 | "engines": { 359 | "node": ">=12" 360 | } 361 | }, 362 | "node_modules/@esbuild/win32-ia32": { 363 | "version": "0.21.5", 364 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", 365 | "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", 366 | "cpu": [ 367 | "ia32" 368 | ], 369 | "dev": true, 370 | "optional": true, 371 | "os": [ 372 | "win32" 373 | ], 374 | "engines": { 375 | "node": ">=12" 376 | } 377 | }, 378 | "node_modules/@esbuild/win32-x64": { 379 | "version": "0.21.5", 380 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", 381 | "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", 382 | "cpu": [ 383 | "x64" 384 | ], 385 | "dev": true, 386 | "optional": true, 387 | "os": [ 388 | "win32" 389 | ], 390 | "engines": { 391 | "node": ">=12" 392 | } 393 | }, 394 | "node_modules/@prisma/client": { 395 | "version": "5.16.1", 396 | "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.16.1.tgz", 397 | "integrity": "sha512-wM9SKQjF0qLxdnOZIVAIMKiz6Hu7vDt4FFAih85K1dk/Rr2mdahy6d3QP41K62N9O0DJJA//gUDA3Mp49xsKIg==", 398 | "hasInstallScript": true, 399 | "engines": { 400 | "node": ">=16.13" 401 | }, 402 | "peerDependencies": { 403 | "prisma": "*" 404 | }, 405 | "peerDependenciesMeta": { 406 | "prisma": { 407 | "optional": true 408 | } 409 | } 410 | }, 411 | "node_modules/@prisma/debug": { 412 | "version": "5.16.1", 413 | "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.16.1.tgz", 414 | "integrity": "sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==", 415 | "devOptional": true 416 | }, 417 | "node_modules/@prisma/engines": { 418 | "version": "5.16.1", 419 | "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.16.1.tgz", 420 | "integrity": "sha512-KkyF3eIUtBIyp5A/rJHCtwQO18OjpGgx18PzjyGcJDY/+vNgaVyuVd+TgwBgeq6NLdd1XMwRCI+58vinHsAdfA==", 421 | "devOptional": true, 422 | "hasInstallScript": true, 423 | "dependencies": { 424 | "@prisma/debug": "5.16.1", 425 | "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", 426 | "@prisma/fetch-engine": "5.16.1", 427 | "@prisma/get-platform": "5.16.1" 428 | } 429 | }, 430 | "node_modules/@prisma/engines-version": { 431 | "version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", 432 | "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303.tgz", 433 | "integrity": "sha512-HkT2WbfmFZ9WUPyuJHhkiADxazHg8Y4gByrTSVeb3OikP6tjQ7txtSUGu9OBOBH0C13dPKN2qqH12xKtHu/Hiw==", 434 | "devOptional": true 435 | }, 436 | "node_modules/@prisma/fetch-engine": { 437 | "version": "5.16.1", 438 | "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.16.1.tgz", 439 | "integrity": "sha512-oOkjaPU1lhcA/Rvr4GVfd1NLJBwExgNBE36Ueq7dr71kTMwy++a3U3oLd2ZwrV9dj9xoP6LjCcky799D9nEt4w==", 440 | "devOptional": true, 441 | "dependencies": { 442 | "@prisma/debug": "5.16.1", 443 | "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", 444 | "@prisma/get-platform": "5.16.1" 445 | } 446 | }, 447 | "node_modules/@prisma/get-platform": { 448 | "version": "5.16.1", 449 | "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.16.1.tgz", 450 | "integrity": "sha512-R4IKnWnMkR2nUAbU5gjrPehdQYUUd7RENFD2/D+xXTNhcqczp0N+WEGQ3ViyI3+6mtVcjjNIMdnUTNyu3GxIgA==", 451 | "devOptional": true, 452 | "dependencies": { 453 | "@prisma/debug": "5.16.1" 454 | } 455 | }, 456 | "node_modules/@tsconfig/node20": { 457 | "version": "20.1.4", 458 | "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", 459 | "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", 460 | "dev": true 461 | }, 462 | "node_modules/@types/node": { 463 | "version": "20.14.9", 464 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", 465 | "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", 466 | "dev": true, 467 | "dependencies": { 468 | "undici-types": "~5.26.4" 469 | } 470 | }, 471 | "node_modules/@types/stream-chain": { 472 | "version": "2.1.0", 473 | "resolved": "https://registry.npmjs.org/@types/stream-chain/-/stream-chain-2.1.0.tgz", 474 | "integrity": "sha512-guDyAl6s/CAzXUOWpGK2bHvdiopLIwpGu8v10+lb9hnQOyo4oj/ZUQFOvqFjKGsE3wJP1fpIesCcMvbXuWsqOg==", 475 | "dev": true, 476 | "dependencies": { 477 | "@types/node": "*" 478 | } 479 | }, 480 | "node_modules/@types/stream-json": { 481 | "version": "1.7.7", 482 | "resolved": "https://registry.npmjs.org/@types/stream-json/-/stream-json-1.7.7.tgz", 483 | "integrity": "sha512-hHG7cLQ09H/m9i0jzL6UJAeLLxIWej90ECn0svO4T8J0nGcl89xZDQ2ujT4WKlvg0GWkcxJbjIDzW/v7BYUM6Q==", 484 | "dev": true, 485 | "dependencies": { 486 | "@types/node": "*", 487 | "@types/stream-chain": "*" 488 | } 489 | }, 490 | "node_modules/asynckit": { 491 | "version": "0.4.0", 492 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 493 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 494 | }, 495 | "node_modules/axios": { 496 | "version": "1.7.2", 497 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", 498 | "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", 499 | "dependencies": { 500 | "follow-redirects": "^1.15.6", 501 | "form-data": "^4.0.0", 502 | "proxy-from-env": "^1.1.0" 503 | } 504 | }, 505 | "node_modules/combined-stream": { 506 | "version": "1.0.8", 507 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 508 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 509 | "dependencies": { 510 | "delayed-stream": "~1.0.0" 511 | }, 512 | "engines": { 513 | "node": ">= 0.8" 514 | } 515 | }, 516 | "node_modules/delayed-stream": { 517 | "version": "1.0.0", 518 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 519 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 520 | "engines": { 521 | "node": ">=0.4.0" 522 | } 523 | }, 524 | "node_modules/esbuild": { 525 | "version": "0.21.5", 526 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", 527 | "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", 528 | "dev": true, 529 | "hasInstallScript": true, 530 | "bin": { 531 | "esbuild": "bin/esbuild" 532 | }, 533 | "engines": { 534 | "node": ">=12" 535 | }, 536 | "optionalDependencies": { 537 | "@esbuild/aix-ppc64": "0.21.5", 538 | "@esbuild/android-arm": "0.21.5", 539 | "@esbuild/android-arm64": "0.21.5", 540 | "@esbuild/android-x64": "0.21.5", 541 | "@esbuild/darwin-arm64": "0.21.5", 542 | "@esbuild/darwin-x64": "0.21.5", 543 | "@esbuild/freebsd-arm64": "0.21.5", 544 | "@esbuild/freebsd-x64": "0.21.5", 545 | "@esbuild/linux-arm": "0.21.5", 546 | "@esbuild/linux-arm64": "0.21.5", 547 | "@esbuild/linux-ia32": "0.21.5", 548 | "@esbuild/linux-loong64": "0.21.5", 549 | "@esbuild/linux-mips64el": "0.21.5", 550 | "@esbuild/linux-ppc64": "0.21.5", 551 | "@esbuild/linux-riscv64": "0.21.5", 552 | "@esbuild/linux-s390x": "0.21.5", 553 | "@esbuild/linux-x64": "0.21.5", 554 | "@esbuild/netbsd-x64": "0.21.5", 555 | "@esbuild/openbsd-x64": "0.21.5", 556 | "@esbuild/sunos-x64": "0.21.5", 557 | "@esbuild/win32-arm64": "0.21.5", 558 | "@esbuild/win32-ia32": "0.21.5", 559 | "@esbuild/win32-x64": "0.21.5" 560 | } 561 | }, 562 | "node_modules/follow-redirects": { 563 | "version": "1.15.6", 564 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 565 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 566 | "funding": [ 567 | { 568 | "type": "individual", 569 | "url": "https://github.com/sponsors/RubenVerborgh" 570 | } 571 | ], 572 | "engines": { 573 | "node": ">=4.0" 574 | }, 575 | "peerDependenciesMeta": { 576 | "debug": { 577 | "optional": true 578 | } 579 | } 580 | }, 581 | "node_modules/form-data": { 582 | "version": "4.0.0", 583 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 584 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 585 | "dependencies": { 586 | "asynckit": "^0.4.0", 587 | "combined-stream": "^1.0.8", 588 | "mime-types": "^2.1.12" 589 | }, 590 | "engines": { 591 | "node": ">= 6" 592 | } 593 | }, 594 | "node_modules/fsevents": { 595 | "version": "2.3.3", 596 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 597 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 598 | "dev": true, 599 | "hasInstallScript": true, 600 | "optional": true, 601 | "os": [ 602 | "darwin" 603 | ], 604 | "engines": { 605 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 606 | } 607 | }, 608 | "node_modules/get-tsconfig": { 609 | "version": "4.7.5", 610 | "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", 611 | "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", 612 | "dev": true, 613 | "dependencies": { 614 | "resolve-pkg-maps": "^1.0.0" 615 | }, 616 | "funding": { 617 | "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 618 | } 619 | }, 620 | "node_modules/mime-db": { 621 | "version": "1.52.0", 622 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 623 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 624 | "engines": { 625 | "node": ">= 0.6" 626 | } 627 | }, 628 | "node_modules/mime-types": { 629 | "version": "2.1.35", 630 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 631 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 632 | "dependencies": { 633 | "mime-db": "1.52.0" 634 | }, 635 | "engines": { 636 | "node": ">= 0.6" 637 | } 638 | }, 639 | "node_modules/prisma": { 640 | "version": "5.16.1", 641 | "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.16.1.tgz", 642 | "integrity": "sha512-Z1Uqodk44diztImxALgJJfNl2Uisl9xDRvqybMKEBYJLNKNhDfAHf+ZIJbZyYiBhLMbKU9cYGdDVG5IIXEnL2Q==", 643 | "devOptional": true, 644 | "hasInstallScript": true, 645 | "dependencies": { 646 | "@prisma/engines": "5.16.1" 647 | }, 648 | "bin": { 649 | "prisma": "build/index.js" 650 | }, 651 | "engines": { 652 | "node": ">=16.13" 653 | } 654 | }, 655 | "node_modules/proxy-from-env": { 656 | "version": "1.1.0", 657 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 658 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 659 | }, 660 | "node_modules/resolve-pkg-maps": { 661 | "version": "1.0.0", 662 | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 663 | "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 664 | "dev": true, 665 | "funding": { 666 | "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 667 | } 668 | }, 669 | "node_modules/stream-chain": { 670 | "version": "2.2.5", 671 | "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", 672 | "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" 673 | }, 674 | "node_modules/stream-json": { 675 | "version": "1.8.0", 676 | "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.8.0.tgz", 677 | "integrity": "sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==", 678 | "dependencies": { 679 | "stream-chain": "^2.2.5" 680 | } 681 | }, 682 | "node_modules/tsx": { 683 | "version": "4.16.2", 684 | "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz", 685 | "integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==", 686 | "dev": true, 687 | "dependencies": { 688 | "esbuild": "~0.21.5", 689 | "get-tsconfig": "^4.7.5" 690 | }, 691 | "bin": { 692 | "tsx": "dist/cli.mjs" 693 | }, 694 | "engines": { 695 | "node": ">=18.0.0" 696 | }, 697 | "optionalDependencies": { 698 | "fsevents": "~2.3.3" 699 | } 700 | }, 701 | "node_modules/typescript": { 702 | "version": "5.5.3", 703 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", 704 | "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", 705 | "dev": true, 706 | "bin": { 707 | "tsc": "bin/tsc", 708 | "tsserver": "bin/tsserver" 709 | }, 710 | "engines": { 711 | "node": ">=14.17" 712 | } 713 | }, 714 | "node_modules/undici-types": { 715 | "version": "5.26.5", 716 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 717 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 718 | "dev": true 719 | } 720 | } 721 | } 722 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "read-node-gzip", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "keywords": [], 6 | "author": "", 7 | "license": "ISC", 8 | "description": "", 9 | "devDependencies": { 10 | "@tsconfig/node20": "20.1.4", 11 | "@types/node": "20.14.9", 12 | "@types/stream-json": "1.7.7", 13 | "prisma": "5.16.1", 14 | "tsx": "4.16.2", 15 | "typescript": "5.5.3" 16 | }, 17 | "dependencies": { 18 | "@prisma/client": "5.16.1", 19 | "axios": "1.7.2", 20 | "stream-chain": "2.2.5", 21 | "stream-json": "1.8.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diego3g/large-json-node-stream-process/d2cc11880e4fb8ba835f7d82f4321c900ac343b1/prisma/dev.db -------------------------------------------------------------------------------- /prisma/migrations/20240705200155_db/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "jobs" ( 3 | "id" SERIAL NOT NULL, 4 | "company_id" TEXT NOT NULL, 5 | "code" TEXT, 6 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 7 | 8 | CONSTRAINT "jobs_pkey" PRIMARY KEY ("id") 9 | ); 10 | 11 | -- CreateIndex 12 | CREATE UNIQUE INDEX "jobs_company_id_code_key" ON "jobs"("company_id", "code"); 13 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model Job { 14 | id Int @id @default(autoincrement()) 15 | 16 | company_id String 17 | code String? 18 | 19 | createdAt DateTime @default(now()) 20 | 21 | @@unique([company_id, code]) 22 | @@map("jobs") 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "_version": "20.1.0", 4 | 5 | "compilerOptions": { 6 | "lib": ["es2023"], 7 | "module": "node16", 8 | "target": "es2022", 9 | 10 | "strict": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "moduleResolution": "node16" 14 | } 15 | } 16 | --------------------------------------------------------------------------------