-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add prisma schema with seed file
- Loading branch information
Showing
4 changed files
with
336 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Countries States Cities Database with Prisma | ||
|
||
This project provides a Prisma schema and seeding script for a comprehensive database including regions, subregions, countries, states, and cities. | ||
|
||
## Setup | ||
|
||
1. Install dependencies: | ||
``` | ||
npm install | ||
``` | ||
|
||
2. Set up your database and update the `DATABASE_URL` in your `.env` file. | ||
|
||
3. Generate Prisma client: | ||
``` | ||
npm run generate | ||
``` | ||
|
||
4. Apply the database schema: | ||
``` | ||
npm run db:push | ||
``` | ||
|
||
## Seeding the Database | ||
|
||
To populate the database with geographical data: | ||
|
||
``` | ||
npm run seed | ||
``` | ||
|
||
## Notes | ||
|
||
- The seeding process can take a while due to the large amount of data being processed. | ||
- Ensure you have a stable internet connection as the script fetches data from GitHub. | ||
- The database structure is designed to balance normalization and query performance. | ||
|
||
## Customization | ||
|
||
You can modify the `schema.prisma` file and the seeding script to fit your specific requirements. Remember to run `npm run generate` after any changes to the schema. | ||
|
||
## Scripts | ||
|
||
- `npm run generate`: Generate Prisma client | ||
- `npm run db:push`: Push the schema to the database | ||
- `npm run seed`: Run the seeding script | ||
|
||
## Data Source | ||
|
||
The data is sourced from the [countries-states-cities-database](https://github.com/dr5hn/countries-states-cities-database) repository. | ||
|
||
## License | ||
|
||
[MIT](https://choosealicense.com/licenses/mit/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "countries-states-cities-database", | ||
"version": "1.0.0", | ||
"description": "A comprehensive database of countries, states, and cities using Prisma ORM", | ||
"main": "index.js", | ||
"scripts": { | ||
"generate": "prisma generate", | ||
"db:push": "prisma db push", | ||
"seed": "ts-node prisma/seed.ts" | ||
}, | ||
"keywords": [ | ||
"prisma", | ||
"database", | ||
"countries", | ||
"states", | ||
"cities", | ||
"regions", | ||
"subregions" | ||
], | ||
"author": "Darshan Gada", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@prisma/client": "^4.15.0", | ||
"node-fetch": "^3.3.1" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.16.16", | ||
"prisma": "^4.15.0", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.1.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// schema.prisma | ||
|
||
datasource db { | ||
provider = "mysql" | ||
url = env("DATABASE_URL") | ||
} | ||
|
||
generator client { | ||
provider = "prisma-client-js" | ||
} | ||
|
||
model Region { | ||
id Int @id @default(autoincrement()) | ||
name String @unique | ||
translations Json? | ||
wikiDataId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
countries Country[] | ||
subregions Subregion[] | ||
@@map("regions") | ||
} | ||
|
||
model Subregion { | ||
id Int @id @default(autoincrement()) | ||
name String @unique | ||
translations Json? | ||
wikiDataId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
region Region @relation(fields: [regionId], references: [id]) | ||
regionId Int | ||
countries Country[] | ||
@@index([regionId]) | ||
@@map("subregions") | ||
} | ||
|
||
model Country { | ||
id Int @id @default(autoincrement()) | ||
name String | ||
iso3 String @unique @db.Char(3) | ||
iso2 String @unique @db.Char(2) | ||
numericCode String? @db.Char(3) | ||
phoneCode String? | ||
capital String? | ||
currency String? | ||
currencyName String? | ||
currencySymbol String? | ||
tld String? | ||
native String? | ||
region String? | ||
subregion String? | ||
latitude Decimal? @db.Decimal(10, 8) | ||
longitude Decimal? @db.Decimal(11, 8) | ||
emoji String? | ||
emojiU String? | ||
timezones Json? | ||
translations Json? | ||
wikiDataId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
regionRelation Region? @relation(fields: [regionId], references: [id]) | ||
regionId Int? | ||
subregionRelation Subregion? @relation(fields: [subregionId], references: [id]) | ||
subregionId Int? | ||
states State[] | ||
cities City[] | ||
@@index([regionId]) | ||
@@index([subregionId]) | ||
@@map("countries") | ||
} | ||
|
||
model State { | ||
id Int @id @default(autoincrement()) | ||
name String | ||
countryCode String @db.Char(2) | ||
fipsCode String? | ||
iso2 String? | ||
type String? | ||
latitude Decimal? @db.Decimal(10, 8) | ||
longitude Decimal? @db.Decimal(11, 8) | ||
wikiDataId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
country Country @relation(fields: [countryId], references: [id]) | ||
countryId Int | ||
cities City[] | ||
@@index([countryId]) | ||
@@map("states") | ||
} | ||
|
||
model City { | ||
id Int @id @default(autoincrement()) | ||
name String | ||
stateCode String | ||
countryCode String @db.Char(2) | ||
latitude Decimal @db.Decimal(10, 8) | ||
longitude Decimal @db.Decimal(11, 8) | ||
wikiDataId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
state State @relation(fields: [stateId], references: [id]) | ||
stateId Int | ||
country Country @relation(fields: [countryId], references: [id]) | ||
countryId Int | ||
@@index([stateId]) | ||
@@index([countryId]) | ||
@@map("cities") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { PrismaClient } from '@prisma/client' | ||
import fetch from 'node-fetch' | ||
|
||
const prisma = new PrismaClient() | ||
|
||
const API_BASE = 'https://raw.githubusercontent.com/dr5hn/countries-states-cities-database/master/json/' | ||
|
||
async function fetchData(endpoint: string) { | ||
const response = await fetch(`${API_BASE}${endpoint}.json`) | ||
return response.json() | ||
} | ||
|
||
async function main() { | ||
// Seed Regions | ||
const regions = await fetchData('regions') | ||
for (const region of regions) { | ||
await prisma.region.create({ | ||
data: { | ||
name: region.name, | ||
translations: region.translations, | ||
wikiDataId: region.wikiDataId, | ||
} | ||
}) | ||
} | ||
|
||
// Seed Subregions | ||
const subregions = await fetchData('subregions') | ||
for (const subregion of subregions) { | ||
const region = await prisma.region.findUnique({ where: { name: subregion.region } }) | ||
if (region) { | ||
await prisma.subregion.create({ | ||
data: { | ||
name: subregion.name, | ||
translations: subregion.translations, | ||
wikiDataId: subregion.wikiDataId, | ||
regionId: region.id, | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// Seed Countries | ||
const countries = await fetchData('countries') | ||
for (const country of countries) { | ||
const region = await prisma.region.findUnique({ where: { name: country.region } }) | ||
const subregion = await prisma.subregion.findUnique({ where: { name: country.subregion } }) | ||
await prisma.country.create({ | ||
data: { | ||
name: country.name, | ||
iso3: country.iso3, | ||
iso2: country.iso2, | ||
numericCode: country.numeric_code, | ||
phoneCode: country.phone_code, | ||
capital: country.capital, | ||
currency: country.currency, | ||
currencyName: country.currency_name, | ||
currencySymbol: country.currency_symbol, | ||
tld: country.tld, | ||
native: country.native, | ||
region: country.region, | ||
subregion: country.subregion, | ||
latitude: country.latitude, | ||
longitude: country.longitude, | ||
emoji: country.emoji, | ||
emojiU: country.emojiU, | ||
timezones: country.timezones, | ||
translations: country.translations, | ||
wikiDataId: country.wikiDataId, | ||
regionId: region?.id, | ||
subregionId: subregion?.id, | ||
} | ||
}) | ||
} | ||
|
||
// Seed States | ||
const states = await fetchData('states') | ||
for (const state of states) { | ||
const country = await prisma.country.findUnique({ where: { iso2: state.country_code } }) | ||
if (country) { | ||
await prisma.state.create({ | ||
data: { | ||
name: state.name, | ||
countryCode: state.country_code, | ||
fipsCode: state.fips_code, | ||
iso2: state.iso2, | ||
type: state.type, | ||
latitude: state.latitude, | ||
longitude: state.longitude, | ||
wikiDataId: state.wikiDataId, | ||
countryId: country.id, | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// Seed Cities | ||
const cities = await fetchData('cities') | ||
for (const city of cities) { | ||
const state = await prisma.state.findFirst({ | ||
where: { | ||
name: city.state_name, | ||
country: { iso2: city.country_code } | ||
} | ||
}) | ||
const country = await prisma.country.findUnique({ where: { iso2: city.country_code } }) | ||
if (state && country) { | ||
await prisma.city.create({ | ||
data: { | ||
name: city.name, | ||
stateCode: city.state_code, | ||
countryCode: city.country_code, | ||
latitude: city.latitude, | ||
longitude: city.longitude, | ||
wikiDataId: city.wikiDataId, | ||
stateId: state.id, | ||
countryId: country.id, | ||
} | ||
}) | ||
} | ||
} | ||
} | ||
|
||
main() | ||
.catch((e) => { | ||
console.error(e) | ||
process.exit(1) | ||
}) | ||
.finally(async () => { | ||
await prisma.$disconnect() | ||
}) |