usbabynames
Version:
United States baby names database, 1880-2024
282 lines (239 loc) • 6.54 kB
JavaScript
/**
usBabyNames.js
... written by Jon Roig (@runnr_az) over a weekend in early 2016
then kinda evolved from there
**/
import sqlite3 from 'sqlite3';
import path from 'path';
import { fileURLToPath } from 'url';
import { join } from 'path';
const startYear = 1880;
const endYear = 2023;
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
const __dirname = path.dirname(__filename); // get the name of the directory
const nameDataDb = new sqlite3.Database( join(__dirname, '..', 'sqlite', 'us-name-data.sqlite'));
const nameDetailsDb = new sqlite3.Database( join(__dirname, '..', 'sqlite', 'us-name-details.sqlite'));
const stateNameDb = new sqlite3.Database( join(__dirname, '..', 'sqlite', 'state-name-data.sqlite'));
const emptyYearObj = {
births: 0,
rank: 0
};
const getAllByName = async (nameInput) => {
const outputObj = {
byYear: {}
};
// build an array of empty years
for (let x = startYear; x <= endYear; x++) {
outputObj.byYear[x] = {
usa: {
m: emptyYearObj,
f: emptyYearObj
},
};
};
const stateNameObjs = await getStateNameData(nameInput);
const nationalNameObjs = await get({ name: nameInput});
outputObj.detailM = await getDetailed(nameInput, 'm');
outputObj.detailF = await getDetailed(nameInput, 'f');
if (outputObj.detailM?.id) {
delete outputObj.detailM.id;
try {
const decodedNameData = JSON.parse(outputObj.detailM.nameData);
outputObj.detailM.nameData = decodedNameData;
} catch (e) {
const decodedNameData = {};
}
}
if (outputObj.detailF?.id) {
delete outputObj.detailF.id;
try {
const decodedNameData = JSON.parse(outputObj.detailF.nameData);
outputObj.detailF.nameData = decodedNameData;
} catch (e) {
const decodedNameData = {};
}
}
for (let index in nationalNameObjs) {
const nameObj = nationalNameObjs[index];
outputObj.byYear[nameObj.year]['usa'][nameObj.sex] = {
births: nameObj.births,
rank: nameObj.rank
};
}
for (let index in stateNameObjs) {
const nameObj = stateNameObjs[index];
outputObj.byYear[nameObj.year][nameObj.state] = {
m: emptyYearObj,
f: emptyYearObj
};
outputObj.byYear[nameObj.year][nameObj.state][nameObj.sex] = {
births: nameObj.births,
rank: nameObj.rank
};
}
return outputObj;
};
const getStateNameData = async (nameInput, sexInput = null) => {
return new Promise((fulfill, reject) => {
const outputArray = [];
const queryParams = [nameInput];
stateNameDb.serialize(() => {
// the basic sql query
let sql = 'SELECT * FROM stateNameData WHERE name = (?) ';
if (sexInput) {
sql += ' and sex = (?)';
queryParams.push(sexInput);
}
stateNameDb.all(sql, queryParams, (err, rows) => {
if (err) {
console.log('err', err);
reject (err);
}
fulfill(rows);
});
});
});
};
const getDetailed = async (nameInput, sexInput) => {
return new Promise((fulfill, reject) => {
const sql = "SELECT * from usNameDetails where name = ? and sex = ?";
// run the query, return the results...
nameDetailsDb.all(sql, [nameInput, sexInput], (err, rows) => {
if (err) {
console.log('err', err);
reject (err);
}
if (!rows.length) {
return fulfill({});
}
return fulfill(rows[0]);
});
});
};
const getByName = async (nameInput) => {
const output = await get({name: nameInput});
return output;
};
const getByYear = async (yearInput) => {
const output = await get({year: yearInput});
return output;
};
const getById = async (id) => {
const output = await get({id: id});
return output[0] || {};
};
const get = async (params) => {
return new Promise((fulfill, reject) => {
const outputArray = [];
const queryParams = [];
nameDataDb.serialize(() => {
// the basic sql query
let sql = '';
if (params?.unique) {
sql = 'SELECT DISTINCT name FROM usNameData WHERE "b" = "b" ';
} else {
sql = 'SELECT * FROM usNameData WHERE "b" = "b" ';
}
// build the filters
if (params?.id) {
sql += ' AND id = (?) ';
queryParams.push(params.id );
}
if (params?.name) {
sql += ' AND name = (?) ';
queryParams.push(params.name.toLowerCase() );
}
if (params?.year) {
sql += ' AND year = (?) ';
queryParams.push(params.year );
}
if (params?.yearRange) {
sql += ' AND year >= (?) AND year <= (?) ';
queryParams.push(params.yearRange.start );
queryParams.push(params.yearRange.end );
}
if (params?.sex) {
sql += ' AND sex = (?) ';
queryParams.push(params.sex.toLowerCase() );
}
if (params?.rank) {
sql += ' AND rank = (?) ';
queryParams.push(params.rank );
}
if (params?.rankRange) {
sql += ' AND rank >= (?) AND rank <= (?) ';
queryParams.push(params.rankRange.start );
queryParams.push(params.rankRange.end );
}
if (params?.births) {
sql += ' AND births = (?) ';
queryParams.push(params.births );
}
if (params?.birthsRange) {
sql += ' AND births >= (?) AND births <= (?) ';
queryParams.push(params.birthsRange.start );
queryParams.push(params.birthsRange.end );
}
if (params?.unique) {
sql += ' ORDER BY name';
}
// run the query, return the results...
nameDataDb.all(sql, queryParams, (err, rows) => {
if (err) {
console.log('err', err);
reject (err);
}
fulfill(rows);
});
});
});
};
const getNameRankAndBirthsByYear = async (name, params) => {
return new Promise((fulfill, reject) => {
const outputObj = {};
const queryParams = [];
nameDataDb.serialize(() => {
// the basic sql query
let sql = 'SELECT year, births, rank, sex FROM usNameData WHERE name = (?)';
queryParams.push(name?.toLowerCase() );
if (params?.sex) {
sql += ' AND sex = (?) ';
queryParams.push(params?.sex.toLowerCase() );
}
// run the query, return the results...
nameDataDb.all(sql, queryParams, (err, rows) => {
if (err) {
reject(err);
}
if (params?.getEmptyYears) {
for (let x = startYear; x <= endYear; x++) {
outputObj[x] = emptyYearObj;
}
}
// get into the array format we want...
for (let index in rows) {
const nameObj = rows[index];
outputObj[nameObj.year] = {
births: nameObj.births,
rank: nameObj.rank,
sex: nameObj.sex
};
}
fulfill(outputObj);
});
});
});
};
export {
getByName,
getByYear,
getById,
get,
getNameRankAndBirthsByYear,
getDetailed,
getStateNameData,
getAllByName,
nameDataDb,
nameDetailsDb,
stateNameDb
};