Skip to content

Commit

Permalink
feat: add prisma schema with seed file
Browse files Browse the repository at this point in the history
  • Loading branch information
dr5hn committed Oct 19, 2024
1 parent 47d13a3 commit d8e389a
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 0 deletions.
54 changes: 54 additions & 0 deletions prisma/README.md
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/)
32 changes: 32 additions & 0 deletions prisma/package.json
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"
}
}
120 changes: 120 additions & 0 deletions prisma/schema.prisma
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")
}
130 changes: 130 additions & 0 deletions prisma/seed.ts
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()
})

0 comments on commit d8e389a

Please sign in to comment.