mirror of
https://github.com/gevera/hot-cold-cities.git
synced 2025-12-06 08:18:19 +00:00
Use Postgres instead of SQLite
This commit is contained in:
parent
42999604f6
commit
b095ab6661
7
.env.example
Normal file
7
.env.example
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# DB_DATABASE = "./world.db"
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
|
PGHOST=localhost
|
||||||
|
PGPORT=5432
|
||||||
|
PGUSERNAME=user
|
||||||
|
PGPASSWORD=password
|
||||||
|
PGDATABASE=pg_db
|
||||||
BIN
database/data.db
BIN
database/data.db
Binary file not shown.
@ -1,6 +1,20 @@
|
|||||||
//import Database from 'better-sqlite3';
|
// import { Database } from 'bun:sqlite';
|
||||||
import { Database } from 'bun:sqlite';
|
// const db = new Database('./database/data.db');
|
||||||
|
|
||||||
const db = new Database('./database/data.db');
|
import { SQL } from 'bun';
|
||||||
|
|
||||||
|
const db = new SQL({
|
||||||
|
// Pool configuration
|
||||||
|
max: 20, // Maximum 20 concurrent connections
|
||||||
|
idleTimeout: 30, // Close idle connections after 30s
|
||||||
|
maxLifetime: 3600, // Max connection lifetime 1 hour
|
||||||
|
connectionTimeout: 10, // Connection timeout 10s
|
||||||
|
onconnect: (client) => {
|
||||||
|
console.log('Connected to database');
|
||||||
|
},
|
||||||
|
onclose: (client) => {
|
||||||
|
console.log('Connection closed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default db;
|
export default db;
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import db from ".";
|
// import db from '.';
|
||||||
|
import type { CityBasic, CityTemperature, CityTemperaturSimple, CountryBasic } from '$lib/types';
|
||||||
// export const allCountries = db.query('SELECT id, name, native, emoji FROM countries');
|
import { sql } from 'bun';
|
||||||
export const allCountries = db.query(`
|
// // export const allCountries = await sql('SELECT id, name, native, emoji FROM countries');
|
||||||
|
export const allCountries = (await sql`
|
||||||
SELECT id, name, native, emoji
|
SELECT id, name, native, emoji
|
||||||
FROM countries
|
FROM countries
|
||||||
WHERE id IN(
|
WHERE id IN(
|
||||||
@ -9,119 +10,147 @@ export const allCountries = db.query(`
|
|||||||
FROM cities
|
FROM cities
|
||||||
WHERE capital IN('capital', 'admin') OR(population >= 100000 AND population IS NOT NULL)
|
WHERE capital IN('capital', 'admin') OR(population >= 100000 AND population IS NOT NULL)
|
||||||
)
|
)
|
||||||
`);
|
`) as CountryBasic[];
|
||||||
|
|
||||||
export const allCities = db.query("SELECT id, city as name, country_id, lat as latitude, lng as longitude FROM cities WHERE capital IN ('capital', 'admin') OR (population >= 100000 AND population != '')");
|
export const allCities =
|
||||||
export const allCitiesWithNoTemperatureToday = db.query(`
|
(await sql`SELECT id, city AS name, country_id, lat AS latitude, lng AS longitude
|
||||||
|
FROM cities
|
||||||
|
WHERE capital IN ('capital', 'admin')
|
||||||
|
OR (population >= 100000 AND population::text != '')`) as CityBasic[];
|
||||||
|
|
||||||
|
export const allCitiesWithNoTemperatureToday = async ({
|
||||||
|
date
|
||||||
|
}: {
|
||||||
|
date: string;
|
||||||
|
}): Promise<CityBasic[]> =>
|
||||||
|
await sql`
|
||||||
SELECT c.id, c.city as name, c.country_id, c.lat as latitude, c.lng as longitude
|
SELECT c.id, c.city as name, c.country_id, c.lat as latitude, c.lng as longitude
|
||||||
FROM cities c
|
FROM cities c
|
||||||
LEFT JOIN meteo_data md ON c.id = md.city_id AND md.date = $date
|
LEFT JOIN meteo_data md ON c.id = md.city_id AND md.date = ${date}
|
||||||
WHERE (c.capital IN ('capital', 'admin') OR (c.population >= 100000 AND c.population != ''))
|
WHERE (c.capital IN ('capital', 'admin') OR (c.population >= 100000 AND c.population::text != ''))
|
||||||
AND md.city_id IS NULL;
|
AND md.city_id IS NULL;
|
||||||
`);
|
`;
|
||||||
|
|
||||||
export const cityTemperatureToday = db.query(`
|
export const cityTemperatureToday = async ({
|
||||||
|
id,
|
||||||
|
date
|
||||||
|
}: {
|
||||||
|
id: number;
|
||||||
|
date: string;
|
||||||
|
}): Promise<CityTemperature | null> =>
|
||||||
|
await sql`
|
||||||
SELECT c.id, c.city as name, md.min, md.max, md.date
|
SELECT c.id, c.city as name, md.min, md.max, md.date
|
||||||
FROM cities as c
|
FROM cities as c
|
||||||
JOIN meteo_data as md ON c.id = md.city_id
|
JOIN meteo_data as md ON c.id = md.city_id
|
||||||
WHERE c.id = $id
|
WHERE c.id = ${id}
|
||||||
AND md.date = $date
|
AND md.date = ${date}
|
||||||
`);
|
`;
|
||||||
|
|
||||||
export const insertCityTemperatureData = db.query(`
|
export const insertCityTemperatureData = async ({
|
||||||
|
city_id,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
date
|
||||||
|
}: CityTemperaturSimple): Promise<CityTemperaturSimple> =>
|
||||||
|
await sql`
|
||||||
INSERT INTO meteo_data (city_id, min, max, date)
|
INSERT INTO meteo_data (city_id, min, max, date)
|
||||||
VALUES ($id, $min, $max, $date)
|
VALUES (${city_id}, ${min}, ${max}, ${date})
|
||||||
`);
|
RETURNING *
|
||||||
export const getAllCitiesInCountryByTemp = db.query(`
|
`;
|
||||||
SELECT
|
|
||||||
c.id as city_id,
|
|
||||||
c.city as city_name,
|
|
||||||
md.max as max_temp,
|
|
||||||
md.min as min_temp,
|
|
||||||
md.date
|
|
||||||
FROM cities c
|
|
||||||
JOIN meteo_data md ON c.id = md.city_id
|
|
||||||
WHERE c.country_id = $country_id
|
|
||||||
AND md.date = $date
|
|
||||||
ORDER BY md.max DESC
|
|
||||||
`);
|
|
||||||
|
|
||||||
export const getHottestAndColdestCityInCountry = db.query(`
|
// export const getAllCitiesInCountryByTemp = await sql`
|
||||||
|
// SELECT
|
||||||
|
// c.id as city_id,
|
||||||
|
// c.city as city_name,
|
||||||
|
// md.max as max_temp,
|
||||||
|
// md.min as min_temp,
|
||||||
|
// md.date
|
||||||
|
// FROM cities c
|
||||||
|
// JOIN meteo_data md ON c.id = md.city_id
|
||||||
|
// WHERE c.country_id = $country_id
|
||||||
|
// AND md.date = $date
|
||||||
|
// ORDER BY md.max DESC
|
||||||
|
// `;
|
||||||
|
|
||||||
|
export const getHottestAndColdestCityInCountry = async ({
|
||||||
|
country_id,
|
||||||
|
date
|
||||||
|
}: {
|
||||||
|
country_id: number;
|
||||||
|
date: string;
|
||||||
|
}) =>
|
||||||
|
await sql`
|
||||||
WITH city_temps AS (
|
WITH city_temps AS (
|
||||||
SELECT
|
SELECT
|
||||||
c.id as city_id,
|
c.id as city_id,
|
||||||
c.city as city_name,
|
c.city as city_name,
|
||||||
c.country_id,
|
c.country_id,
|
||||||
md.max as max_temp,
|
ROUND(md.max::numeric, 2) as max_temp,
|
||||||
md.date,
|
md.date,
|
||||||
ROW_NUMBER() OVER (PARTITION BY c.country_id ORDER BY md.max DESC) as hottest_rank,
|
ROW_NUMBER() OVER (PARTITION BY c.country_id ORDER BY md.max DESC)::INTEGER as hottest_rank,
|
||||||
ROW_NUMBER() OVER (PARTITION BY c.country_id ORDER BY md.max ASC) as coldest_rank
|
ROW_NUMBER() OVER (PARTITION BY c.country_id ORDER BY md.max ASC)::INTEGER as coldest_rank
|
||||||
FROM cities c
|
FROM cities c
|
||||||
JOIN meteo_data md ON c.id = md.city_id
|
JOIN meteo_data md ON c.id = md.city_id
|
||||||
WHERE md.date = $date
|
WHERE md.date = ${date}
|
||||||
AND c.country_id = $country_id
|
AND c.country_id = ${country_id}
|
||||||
)
|
)
|
||||||
SELECT * FROM city_temps
|
SELECT * FROM city_temps
|
||||||
WHERE hottest_rank = 1 OR coldest_rank = 1
|
WHERE hottest_rank = 1 OR coldest_rank = 1
|
||||||
`);
|
`;
|
||||||
|
|
||||||
export const getHottestAndColdestCityInWorld = db.query(`
|
|
||||||
WITH city_temps AS (
|
|
||||||
SELECT
|
|
||||||
c.id as city_id,
|
|
||||||
c.city as city_name,
|
|
||||||
c.country_id,
|
|
||||||
co.name as country_name,
|
|
||||||
md.max as max_temp,
|
|
||||||
md.min as min_temp,
|
|
||||||
md.date,
|
|
||||||
ROW_NUMBER() OVER (ORDER BY md.max DESC) as hottest_rank,
|
|
||||||
ROW_NUMBER() OVER (ORDER BY md.min ASC) as coldest_rank
|
|
||||||
FROM cities c
|
|
||||||
JOIN meteo_data md ON c.id = md.city_id
|
|
||||||
JOIN countries co ON c.country_id = co.id
|
|
||||||
WHERE md.date = $date
|
|
||||||
)
|
|
||||||
SELECT * FROM city_temps
|
|
||||||
WHERE hottest_rank = 1 OR coldest_rank = 1
|
|
||||||
LIMIT 2
|
|
||||||
`);
|
|
||||||
|
|
||||||
|
|
||||||
export const getWorldTemperatureStats = db.query(`
|
|
||||||
WITH city_temps AS (
|
|
||||||
SELECT
|
|
||||||
c.id as city_id,
|
|
||||||
c.city as city_name,
|
|
||||||
c.country_id,
|
|
||||||
co.name as country_name,
|
|
||||||
md.max as max_temp,
|
|
||||||
md.min as min_temp,
|
|
||||||
md.date,
|
|
||||||
ROW_NUMBER() OVER (ORDER BY md.max DESC) as hottest_rank,
|
|
||||||
ROW_NUMBER() OVER (ORDER BY md.max ASC) as coldest_rank
|
|
||||||
FROM cities c
|
|
||||||
JOIN meteo_data md ON c.id = md.city_id
|
|
||||||
JOIN countries co ON c.country_id = co.id
|
|
||||||
WHERE md.date = $date
|
|
||||||
),
|
|
||||||
world_stats AS (
|
|
||||||
SELECT
|
|
||||||
ct1.city_id,
|
|
||||||
ct1.city_name,
|
|
||||||
ct1.country_id,
|
|
||||||
ct1.country_name,
|
|
||||||
ct1.max_temp,
|
|
||||||
ct1.date,
|
|
||||||
ct1.hottest_rank,
|
|
||||||
ct1.coldest_rank
|
|
||||||
FROM city_temps ct1
|
|
||||||
WHERE ct1.hottest_rank = 1 OR ct1.coldest_rank = 1
|
|
||||||
)
|
|
||||||
SELECT * FROM world_stats
|
|
||||||
ORDER BY max_temp DESC
|
|
||||||
LIMIT 2
|
|
||||||
`);
|
|
||||||
|
|
||||||
|
|
||||||
|
// export const getHottestAndColdestCityInWorld = await sql`
|
||||||
|
// WITH city_temps AS (
|
||||||
|
// SELECT
|
||||||
|
// c.id as city_id,
|
||||||
|
// c.city as city_name,
|
||||||
|
// c.country_id,
|
||||||
|
// co.name as country_name,
|
||||||
|
// md.max as max_temp,
|
||||||
|
// md.min as min_temp,
|
||||||
|
// md.date,
|
||||||
|
// ROW_NUMBER() OVER (ORDER BY md.max DESC) as hottest_rank,
|
||||||
|
// ROW_NUMBER() OVER (ORDER BY md.min ASC) as coldest_rank
|
||||||
|
// FROM cities c
|
||||||
|
// JOIN meteo_data md ON c.id = md.city_id
|
||||||
|
// JOIN countries co ON c.country_id = co.id
|
||||||
|
// WHERE md.date = $date
|
||||||
|
// )
|
||||||
|
// SELECT * FROM city_temps
|
||||||
|
// WHERE hottest_rank = 1 OR coldest_rank = 1
|
||||||
|
// LIMIT 2
|
||||||
|
// `;
|
||||||
|
|
||||||
|
// export const getWorldTemperatureStats = await sql`
|
||||||
|
// WITH city_temps AS (
|
||||||
|
// SELECT
|
||||||
|
// c.id as city_id,
|
||||||
|
// c.city as city_name,
|
||||||
|
// c.country_id,
|
||||||
|
// co.name as country_name,
|
||||||
|
// md.max as max_temp,
|
||||||
|
// md.min as min_temp,
|
||||||
|
// md.date,
|
||||||
|
// ROW_NUMBER() OVER (ORDER BY md.max DESC) as hottest_rank,
|
||||||
|
// ROW_NUMBER() OVER (ORDER BY md.max ASC) as coldest_rank
|
||||||
|
// FROM cities c
|
||||||
|
// JOIN meteo_data md ON c.id = md.city_id
|
||||||
|
// JOIN countries co ON c.country_id = co.id
|
||||||
|
// WHERE md.date = $date
|
||||||
|
// ),
|
||||||
|
// world_stats AS (
|
||||||
|
// SELECT
|
||||||
|
// ct1.city_id,
|
||||||
|
// ct1.city_name,
|
||||||
|
// ct1.country_id,
|
||||||
|
// ct1.country_name,
|
||||||
|
// ct1.max_temp,
|
||||||
|
// ct1.date,
|
||||||
|
// ct1.hottest_rank,
|
||||||
|
// ct1.coldest_rank
|
||||||
|
// FROM city_temps ct1
|
||||||
|
// WHERE ct1.hottest_rank = 1 OR ct1.coldest_rank = 1
|
||||||
|
// )
|
||||||
|
// SELECT * FROM world_stats
|
||||||
|
// ORDER BY max_temp DESC
|
||||||
|
// LIMIT 2
|
||||||
|
// `;
|
||||||
|
|||||||
@ -1,56 +1,53 @@
|
|||||||
import { allCities, allCitiesWithNoTemperatureToday, cityTemperatureToday, insertCityTemperatureData } from "$lib/db/queries";
|
import { allCitiesWithNoTemperatureToday, insertCityTemperatureData } from '$lib/db/queries';
|
||||||
import type { CityBasic, CityTemperature } from "$lib/types";
|
import { getLocationTemperature } from './meteoService';
|
||||||
import { getLocationTemperature } from "./meteoService";
|
|
||||||
|
|
||||||
const COOLDOWN_TIME = 333;
|
const COOLDOWN_TIME = 333;
|
||||||
|
|
||||||
export const fetchAllCitiesTemperatures = async (date: string) => {
|
export const fetchAllCitiesTemperatures = async (date: string) => {
|
||||||
try {
|
try {
|
||||||
|
const cities = await allCitiesWithNoTemperatureToday({ date });
|
||||||
|
console.log('Today date: ', date);
|
||||||
|
console.log('Total Cities to fetch: ', cities.length);
|
||||||
|
|
||||||
const cities = allCitiesWithNoTemperatureToday.all({ $date: date }) as CityBasic[];
|
for (const [index, city] of cities.entries()) {
|
||||||
|
try {
|
||||||
|
console.log(`Processing city ${index + 1}/${cities.length}`);
|
||||||
|
|
||||||
console.log('Today date: ', date);
|
const { data } = await getLocationTemperature(
|
||||||
console.log('Total Cities to fetch: ', cities.length);
|
city.id,
|
||||||
|
city.latitude.toString(),
|
||||||
|
city.longitude.toString()
|
||||||
|
);
|
||||||
|
|
||||||
for (const [index, city] of cities.entries()) {
|
if (data) {
|
||||||
try {
|
await insertCityTemperatureData({
|
||||||
console.log(`Processing city ${index + 1}/${cities.length}`);
|
city_id: city.id, // Changed from data.id to city.id
|
||||||
const existingRecord = cityTemperatureToday.get({ $id: city.id, $date: date }) as CityTemperature | null;
|
min: data.min,
|
||||||
if (!existingRecord) {
|
max: data.max,
|
||||||
|
date: data.date
|
||||||
|
});
|
||||||
|
console.log(`Temperature data stored for ${city.name}`);
|
||||||
|
} else {
|
||||||
|
console.log(`No temperature data available for ${city.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
const { data } = await getLocationTemperature(
|
// Add cooldown delay to avoid API throttling
|
||||||
city.id,
|
await new Promise((resolve) => setTimeout(resolve, COOLDOWN_TIME));
|
||||||
city.latitude.toString(),
|
} catch (error) {
|
||||||
city.longitude.toString()
|
console.error(`Failed to fetch temperature for city ${city.name}:`, error);
|
||||||
);
|
// Consider adding more specific error handling here
|
||||||
if (data) {
|
}
|
||||||
insertCityTemperatureData.run({
|
}
|
||||||
$id: data.id,
|
|
||||||
$min: data.min,
|
|
||||||
$max: data.max,
|
|
||||||
$date: data.date
|
|
||||||
});
|
|
||||||
console.log(`Temperature data stored for ${city.name}`);
|
|
||||||
}
|
|
||||||
// Add cooldown delay to avoid API throttling
|
|
||||||
await new Promise(resolve => setTimeout(resolve, COOLDOWN_TIME));
|
|
||||||
} else {
|
|
||||||
console.log(`Temperature data already exists for ${city.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
console.log('Finished fetching temperatures for all cities: ', date);
|
||||||
} catch (error) {
|
return {
|
||||||
console.error(`Failed to fetch temperature for city ${city.name}:`, error);
|
ok: true
|
||||||
}
|
};
|
||||||
}
|
} catch (error) {
|
||||||
console.log('Finished fetching temperatures for all cities: ', date);
|
console.error('Failed to fetch cities:', error);
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: false,
|
||||||
}
|
error: error?.message // Added error message for better debugging
|
||||||
} catch (error) {
|
};
|
||||||
console.error('Failed to fetch cities:', error);
|
}
|
||||||
return {
|
};
|
||||||
ok: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,38 +1,37 @@
|
|||||||
import type { MeteoData, MeteoResponseType } from "$lib/types";
|
import type { MeteoData, MeteoResponseType } from '$lib/types';
|
||||||
|
|
||||||
export const getLocationTemperature = async (id: number, latitude: string, longitude: string) => {
|
export const getLocationTemperature = async (id: number, latitude: string, longitude: string) => {
|
||||||
const meteoEndpoint = "https://api.open-meteo.com/v1/forecast";
|
const meteoEndpoint = 'https://api.open-meteo.com/v1/forecast';
|
||||||
// https://api.open-meteo.com/v1/forecast?latitude=48.0356&longitude=27.8129&hourly=temperature_2m&daily=temperature_2m_max,temperature_2m_min&forecast_days=1&format=json&timeformat=unixtime
|
// https://api.open-meteo.com/v1/forecast?latitude=48.0356&longitude=27.8129&hourly=temperature_2m&daily=temperature_2m_max,temperature_2m_min&forecast_days=1&format=json&timeformat=unixtime
|
||||||
|
|
||||||
const url = new URL(meteoEndpoint);
|
const url = new URL(meteoEndpoint);
|
||||||
url.searchParams.set('latitude', latitude);
|
url.searchParams.set('latitude', latitude);
|
||||||
url.searchParams.set('longitude', longitude);
|
url.searchParams.set('longitude', longitude);
|
||||||
url.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min');
|
url.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min');
|
||||||
url.searchParams.set('format', 'json');
|
url.searchParams.set('format', 'json');
|
||||||
url.searchParams.set('forecast_days', '1');
|
url.searchParams.set('forecast_days', '1');
|
||||||
|
|
||||||
|
try {
|
||||||
try {
|
const response = await fetch(url);
|
||||||
const response = await fetch(url);
|
console.log('Fetching data from open meteo...');
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json() as MeteoResponseType;
|
const data = (await response.json()) as MeteoResponseType;
|
||||||
console.log('Fetched DATA from open meteo >>>>');
|
console.log('Fetched DATA from open meteo >>>>');
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
max: data.daily.temperature_2m_max[0],
|
max: data.daily.temperature_2m_max[0],
|
||||||
min: data.daily.temperature_2m_min[0],
|
min: data.daily.temperature_2m_min[0],
|
||||||
date: data.daily.time[0],
|
date: data.daily.time[0]
|
||||||
} as MeteoData
|
} as MeteoData
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
} catch (error) {
|
console.log(error);
|
||||||
console.log(error);
|
return {
|
||||||
return {
|
data: null
|
||||||
data: null
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|||||||
115
src/lib/types.ts
115
src/lib/types.ts
@ -1,72 +1,79 @@
|
|||||||
export type CountryBasic = {
|
export type CountryBasic = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
native: string;
|
native: string;
|
||||||
emoji: string;
|
emoji: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CityBasic = {
|
export type CityBasic = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
country_id: number;
|
country_id: number;
|
||||||
latitude: number;
|
latitude: number;
|
||||||
longitude: number;
|
longitude: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CityTemperature = {
|
export type CityTemperature = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
date: string;
|
date: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type CityTemperaturSimple = {
|
||||||
|
city_id: number;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type HotColdCity = {
|
export type HotColdCity = {
|
||||||
city_id: number;
|
city_id: number;
|
||||||
city_name: string;
|
city_name: string;
|
||||||
country_id: number;
|
country_id: number;
|
||||||
country_name: string;
|
country_name: string;
|
||||||
max_temp: number;
|
max_temp: number;
|
||||||
date: string;
|
date: string;
|
||||||
hottest_rank: number;
|
hottest_rank: number;
|
||||||
coldest_rank: number;
|
coldest_rank: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ComboOption = {
|
export type ComboOption = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
country_id?: number;
|
country_id?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MeteoResponseType = {
|
export type MeteoResponseType = {
|
||||||
latitude: number;
|
latitude: number;
|
||||||
longitude: number;
|
longitude: number;
|
||||||
generationtime_ms: number;
|
generationtime_ms: number;
|
||||||
utc_offset_seconds: number;
|
utc_offset_seconds: number;
|
||||||
timezone: string;
|
timezone: string;
|
||||||
timezone_abbreviation: string;
|
timezone_abbreviation: string;
|
||||||
elevation: number;
|
elevation: number;
|
||||||
daily_units: {
|
daily_units: {
|
||||||
time: string;
|
time: string;
|
||||||
temperature_2m_max: string;
|
temperature_2m_max: string;
|
||||||
temperature_2m_min: string;
|
temperature_2m_min: string;
|
||||||
},
|
};
|
||||||
daily: {
|
daily: {
|
||||||
time: string[];
|
time: string[];
|
||||||
temperature_2m_max: number[];
|
temperature_2m_max: number[];
|
||||||
temperature_2m_min: number[];
|
temperature_2m_min: number[];
|
||||||
},
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export type MeteoData = {
|
export type MeteoData = {
|
||||||
id: number;
|
id: number;
|
||||||
max: number;
|
max: number;
|
||||||
min: number;
|
min: number;
|
||||||
date: string;
|
date: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export enum UnitsEnum {
|
export enum UnitsEnum {
|
||||||
METRIC = 'METRIC',
|
METRIC = 'METRIC',
|
||||||
IMPERIAL = 'IMPERIAL'
|
IMPERIAL = 'IMPERIAL'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
import { allCities, allCountries, getHottestAndColdestCityInCountry } from '$lib/db/queries';
|
import {
|
||||||
|
allCities,
|
||||||
|
allCitiesWithNoTemperatureToday,
|
||||||
|
allCountries,
|
||||||
|
getHottestAndColdestCityInCountry
|
||||||
|
} from '$lib/db/queries';
|
||||||
import type { CityBasic, CityTemperature, CountryBasic, HotColdCity } from '$lib/types';
|
import type { CityBasic, CityTemperature, CountryBasic, HotColdCity } from '$lib/types';
|
||||||
import { type Actions } from '@sveltejs/kit';
|
import { type Actions } from '@sveltejs/kit';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
@ -6,74 +11,67 @@ import type { PageServerLoad } from './$types';
|
|||||||
// import { fetchAllCitiesTemperatures } from '$lib/server/meteoDataHandler';
|
// import { fetchAllCitiesTemperatures } from '$lib/server/meteoDataHandler';
|
||||||
|
|
||||||
const errorObject = {
|
const errorObject = {
|
||||||
ok: false,
|
ok: false,
|
||||||
data: null,
|
data: null,
|
||||||
error: 'Failed to fetch temperature'
|
error: 'Failed to fetch temperature'
|
||||||
}
|
};
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ url }) => {
|
export const load: PageServerLoad = async ({ url }) => {
|
||||||
try {
|
try {
|
||||||
const countries = allCountries.all() as CountryBasic[];
|
const countries = allCountries;
|
||||||
const cities = allCities.all() as CityBasic[];
|
const cities = allCities;
|
||||||
const country_id = url.searchParams.get('country');
|
const country_id = url.searchParams.get('country');
|
||||||
// console.log('country_id >>> ', country_id);
|
|
||||||
|
|
||||||
let temperatureData: HotColdCity[] | null = null;
|
let temperatureData: HotColdCity[] | null = null;
|
||||||
if (country_id) {
|
if (country_id) {
|
||||||
temperatureData = getHottestAndColdestCityInCountry.all({
|
temperatureData = (await getHottestAndColdestCityInCountry({
|
||||||
$country_id: Number(country_id),
|
country_id: Number(country_id),
|
||||||
$date: new Date().toISOString().split('T')[0]
|
date: new Date().toISOString().split('T')[0]
|
||||||
}) as HotColdCity[];
|
})) as HotColdCity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('Loading >>>>', temperatureData);
|
return {
|
||||||
|
countries,
|
||||||
return {
|
cities,
|
||||||
countries,
|
temperatureData,
|
||||||
cities,
|
country_id: country_id ? parseInt(country_id) : null
|
||||||
temperatureData,
|
};
|
||||||
country_id: country_id ? parseInt(country_id) : null
|
} catch (error) {
|
||||||
};
|
console.log(error);
|
||||||
} catch (error) {
|
return {
|
||||||
console.log(error);
|
countries: [],
|
||||||
return {
|
cities: [],
|
||||||
countries: [],
|
temperatureData: null,
|
||||||
cities: [],
|
country_id: null
|
||||||
temperatureData: null,
|
};
|
||||||
country_id: null
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
fetchTemperature: async ({ request }) => {
|
fetchTemperature: async ({ request }) => {
|
||||||
try {
|
try {
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
const country_id = formData.get('country_id') as string;
|
const country_id = formData.get('country_id') as string;
|
||||||
|
|
||||||
// console.log('FORM ACTION >>>', country_id)
|
// console.log('FORM ACTION >>>', country_id)
|
||||||
const response = getHottestAndColdestCityInCountry.all({
|
const response = (await getHottestAndColdestCityInCountry({
|
||||||
$country_id: Number(country_id),
|
country_id: Number(country_id),
|
||||||
$date: new Date().toISOString().split('T')[0]
|
date: new Date().toISOString().split('T')[0]
|
||||||
}) as HotColdCity[];
|
})) as HotColdCity[];
|
||||||
|
|
||||||
if (response.length == 2) {
|
if (response.length == 2) {
|
||||||
// console.log('RESPONSE >>>>', response);
|
return {
|
||||||
|
ok: true,
|
||||||
return {
|
data: response,
|
||||||
ok: true,
|
error: null,
|
||||||
data: response,
|
country_id: country_id ?? null
|
||||||
error: null,
|
};
|
||||||
country_id: country_id ?? null
|
} else {
|
||||||
};
|
return errorObject;
|
||||||
} else {
|
}
|
||||||
return errorObject;
|
} catch (error) {
|
||||||
}
|
console.log(error);
|
||||||
|
return errorObject;
|
||||||
} catch (error) {
|
}
|
||||||
console.log(error);
|
}
|
||||||
return errorObject;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -20,15 +20,15 @@
|
|||||||
let temperatureData: HotColdCity[] | null = $state(data.temperatureData);
|
let temperatureData: HotColdCity[] | null = $state(data.temperatureData);
|
||||||
let tempDiff: number | null = $derived(
|
let tempDiff: number | null = $derived(
|
||||||
temperatureData
|
temperatureData
|
||||||
? Number(Math.abs(temperatureData[0].max_temp - temperatureData[1].max_temp).toFixed(2))
|
? Number(Math.abs(temperatureData[0]?.max_temp - temperatureData[1]?.max_temp).toFixed(2))
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
let tempDiffImperial: number | null = $derived(
|
let tempDiffImperial: number | null = $derived(
|
||||||
temperatureData
|
temperatureData
|
||||||
? Number(
|
? Number(
|
||||||
Math.abs(
|
Math.abs(
|
||||||
celsiusToFahrenheit(temperatureData[0].max_temp) -
|
celsiusToFahrenheit(temperatureData[0]?.max_temp) -
|
||||||
celsiusToFahrenheit(temperatureData[1].max_temp)
|
celsiusToFahrenheit(temperatureData[1]?.max_temp)
|
||||||
).toFixed(2)
|
).toFixed(2)
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
@ -58,8 +58,6 @@
|
|||||||
temperatureData = form.data;
|
temperatureData = form.data;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => console.log(tempDiff));
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -109,7 +107,7 @@
|
|||||||
</form>
|
</form>
|
||||||
{#if selectedCountryId && temperatureData}
|
{#if selectedCountryId && temperatureData}
|
||||||
<div class="my-8 flex flex-col justify-evenly gap-12 md:flex-row">
|
<div class="my-8 flex flex-col justify-evenly gap-12 md:flex-row">
|
||||||
{#each temperatureData as temperature}
|
{#each temperatureData as temperature, index}
|
||||||
<dl class="flex flex-col gap-2">
|
<dl class="flex flex-col gap-2">
|
||||||
{#if temperature.coldest_rank === 1}
|
{#if temperature.coldest_rank === 1}
|
||||||
<dt class="text-center text-lg text-blue-600">❄️ Coldest City</dt>
|
<dt class="text-center text-lg text-blue-600">❄️ Coldest City</dt>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user