This commit is contained in:
parent
d721f2876e
commit
30db53bd95
38
apps/blakus-api/migrations/20250315152617_categories.js
Normal file
38
apps/blakus-api/migrations/20250315152617_categories.js
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.up = function(knex) {
|
||||
return knex.schema
|
||||
.createTable('categories', function (table) {
|
||||
table.uuid('id').primary().defaultTo(knex.raw(`gen_random_uuid()`));
|
||||
table.string('name').notNullable();
|
||||
table.timestamps(true, true);
|
||||
})
|
||||
.alterTable('places', function(table) {
|
||||
table.uuid('category_id').references('id').inTable('categories')
|
||||
})
|
||||
.createTable('subcategories', function(table) {
|
||||
table.uuid('id').primary().defaultTo(knex.raw(`gen_random_uuid()`));
|
||||
table.string('name').notNullable();
|
||||
table.uuid('category_id').references('id').inTable('categories').onDelete('CASCADE');
|
||||
table.timestamps(true, true);
|
||||
})
|
||||
.createTable('place_subcategories', function(table) {
|
||||
table.uuid('place_id').references('id').inTable('places').onDelete('CASCADE');
|
||||
table.uuid('subcategory_id').references('id').inTable('subcategories').onDelete('CASCADE');
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = function(knex) {
|
||||
knex.schema.alterTable('places', function(table) {
|
||||
table.dropColumn('category_id');
|
||||
});
|
||||
knex.schema.dropTable('categories');
|
||||
knex.schema.dropTable('subcategories');
|
||||
knex.schema.dropTable('place_subcategories');
|
||||
};
|
||||
@ -74,7 +74,7 @@
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"cwd": "apps/blakus-api",
|
||||
"command": "npx knex migrate:make farts"
|
||||
"command": "npx knex migrate:make new"
|
||||
},
|
||||
"schema": {
|
||||
"name": {
|
||||
|
||||
10
apps/blakus-api/seeds/categories.js
Normal file
10
apps/blakus-api/seeds/categories.js
Normal file
@ -0,0 +1,10 @@
|
||||
const CATEGORIES = require('./categories.json');
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.seed = async function(knex) {
|
||||
await knex('categories').del()
|
||||
await knex('categories').insert(CATEGORIES.map(({name}) => ({name})));
|
||||
};
|
||||
10
apps/blakus-api/seeds/categories.json
Normal file
10
apps/blakus-api/seeds/categories.json
Normal file
@ -0,0 +1,10 @@
|
||||
[
|
||||
{ "name": "restaurant", "subcategories": [] },
|
||||
{ "name": "cafe", "subcategories": [] },
|
||||
{ "name": "bar", "subcategories": [] },
|
||||
{ "name": "pub", "subcategories": [] },
|
||||
{ "name": "biergarten", "subcategories": [] },
|
||||
{ "name": "fast_food", "subcategories": [] },
|
||||
{ "name": "food_court", "subcategories": [] },
|
||||
{ "name": "ice_cream", "subcategories": [] }
|
||||
]
|
||||
@ -1,5 +1,5 @@
|
||||
const { fakerLV : faker } = require('@faker-js/faker');
|
||||
|
||||
// const CATEGORIES = require('./categories.json');
|
||||
const PLACE_COUNT = 1000;
|
||||
const BBOX_RIGA = [23.755875,56.815914,24.466553,57.067617];
|
||||
const [ BBOX_MIN_LAT, BBOX_MIN_LON, BBOX_MAX_LAT, BBOX_MAX_LON ] = BBOX_RIGA;
|
||||
@ -10,6 +10,8 @@ const [ BBOX_MIN_LAT, BBOX_MIN_LON, BBOX_MAX_LAT, BBOX_MAX_LON ] = BBOX_RIGA;
|
||||
*/
|
||||
exports.seed = async function(knex) {
|
||||
|
||||
const categories = await knex('categories').select('id');
|
||||
|
||||
const createPlace = () => {
|
||||
const coords = [
|
||||
faker.location.latitude({ min: BBOX_MIN_LAT, max: BBOX_MAX_LAT }),
|
||||
@ -26,12 +28,13 @@ exports.seed = async function(knex) {
|
||||
street: faker.location.street(),
|
||||
house: faker.helpers.maybe(() => faker.person.lastName(), { probability: 0.1 }) || faker.location.buildingNumber(),
|
||||
postalCode: faker.location.zipCode(),
|
||||
category_id: faker.helpers.arrayElement(categories.map(c => c.id)),
|
||||
}
|
||||
};
|
||||
|
||||
const places = new Array(PLACE_COUNT).fill(() => createPlace()).map((fn, i) => fn(i));
|
||||
|
||||
// Deletes ALL existing entries
|
||||
await knex('places').del()
|
||||
await knex('places').insert([
|
||||
...new Array(PLACE_COUNT).fill(() => createPlace()).map((fn, i) => fn(i)),
|
||||
]);
|
||||
await knex('places').insert(places);
|
||||
};
|
||||
|
||||
@ -18,7 +18,7 @@ export default async function (fastify: FastifyInstance) {
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
amenity: { type: 'string' },
|
||||
category: { type: 'string' },
|
||||
address: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@ -51,23 +51,26 @@ export default async function (fastify: FastifyInstance) {
|
||||
}, async function (request, reply) {
|
||||
const {lat, lon} = request.query;
|
||||
|
||||
const knownPlaces = await db.select(
|
||||
'id',
|
||||
'name',
|
||||
'externalId',
|
||||
'country',
|
||||
'county',
|
||||
'district',
|
||||
'city',
|
||||
'street',
|
||||
'house',
|
||||
'postalCode',
|
||||
db.raw('ST_Y(coordinates::geometry) AS lat'),
|
||||
db.raw('ST_X(coordinates::geometry) AS lon')
|
||||
).whereRaw(
|
||||
'ST_DWithin(coordinates, ST_SetSRID(ST_MakePoint(?, ?), 4326), ?)',
|
||||
[lon, lat, 2000]
|
||||
).from('places');
|
||||
const knownPlaces = await db('places')
|
||||
.leftJoin('categories', 'places.category_id', 'categories.id')
|
||||
.select(
|
||||
'places.id',
|
||||
'places.name',
|
||||
'places.externalId',
|
||||
'places.country',
|
||||
'places.county',
|
||||
'places.district',
|
||||
'places.city',
|
||||
'places.street',
|
||||
'places.house',
|
||||
'places.postalCode',
|
||||
db.raw('ST_Y(places.coordinates::geometry) AS lat'),
|
||||
db.raw('ST_X(places.coordinates::geometry) AS lon'),
|
||||
'categories.name AS category'
|
||||
).whereRaw(
|
||||
'ST_DWithin(places.coordinates, ST_SetSRID(ST_MakePoint(?, ?), 4326), ?)',
|
||||
[lon, lat, 2000]
|
||||
);
|
||||
|
||||
// const externalIds = await db.select('externalId').from('places').where('externalId', 'like', 'osm:%');
|
||||
|
||||
@ -97,7 +100,7 @@ export default async function (fastify: FastifyInstance) {
|
||||
const blakus = knownPlaces.map(place => ({
|
||||
id: place.id,
|
||||
title: place.name,
|
||||
amenity: 'pub',
|
||||
category: place.category,
|
||||
address: {
|
||||
country: place.country,
|
||||
county: place.county,
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="_amenity_restaurant_CYImm">"Restaurant"</string>
|
||||
<string name="_amenity_pub_hVjSx">"Pub"</string>
|
||||
<string name="_amenity_ice_cream_12K4Gu">"Ice Cream"</string>
|
||||
<string name="_amenity_food_court_Z2qUk6P">"Food Court"</string>
|
||||
<string name="_amenity_fast_food_Z1zDs8J">"Fast Food"</string>
|
||||
<string name="_amenity_cafe_Z13hX6o">"Cafe"</string>
|
||||
<string name="_amenity_biergarten_zXiC4">"Beer Garden"</string>
|
||||
<string name="_amenity_bar_hVg75">"Bar"</string>
|
||||
<string name="_category_restaurant_ZNNv4O">"Restaurant"</string>
|
||||
<string name="_category_pub_uGSaR">"Pub"</string>
|
||||
<string name="_category_ice_cream_Z1ic9A2">"Ice Cream"</string>
|
||||
<string name="_category_food_court_1bszfU">"Food Court"</string>
|
||||
<string name="_category_fast_food_19ArnF">"Fast Food"</string>
|
||||
<string name="_category_cafe_laiRP">"Cafe"</string>
|
||||
<string name="_category_biergarten_ZQOUO7">"Beer Garden"</string>
|
||||
<string name="_category_bar_uGOop">"Bar"</string>
|
||||
<string name="_app_name_1k3Sbz">"Blakus"</string>
|
||||
<string name="app_name">"Blakus"</string>
|
||||
<string name="title_activity_kimera">"Blakus"</string>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="_amenity_restaurant_CYImm">"Restorāns"</string>
|
||||
<string name="_amenity_pub_hVjSx">"Krogs"</string>
|
||||
<string name="_amenity_ice_cream_12K4Gu">"Saldējums"</string>
|
||||
<string name="_amenity_food_court_Z2qUk6P">"Ēdināšanas laukums"</string>
|
||||
<string name="_amenity_fast_food_Z1zDs8J">"Ātras uzkodas"</string>
|
||||
<string name="_amenity_cafe_Z13hX6o">"Kafejnīca"</string>
|
||||
<string name="_amenity_biergarten_zXiC4">"Biergarten"</string>
|
||||
<string name="_amenity_bar_hVg75">"Bārs"</string>
|
||||
<string name="_category_restaurant_ZNNv4O">"Restorāns"</string>
|
||||
<string name="_category_pub_uGSaR">"Krogs"</string>
|
||||
<string name="_category_ice_cream_Z1ic9A2">"Saldējums"</string>
|
||||
<string name="_category_food_court_1bszfU">"Ēdināšanas laukums"</string>
|
||||
<string name="_category_fast_food_19ArnF">"Ātras uzkodas"</string>
|
||||
<string name="_category_cafe_laiRP">"Kafejnīca"</string>
|
||||
<string name="_category_biergarten_ZQOUO7">"Biergarten"</string>
|
||||
<string name="_category_bar_uGOop">"Bārs"</string>
|
||||
<string name="_app_name_1k3Sbz">"Blakus"</string>
|
||||
<string name="app_name">"Blakus"</string>
|
||||
<string name="title_activity_kimera">"Blakus"</string>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.name": "Blakus",
|
||||
"amenity": {
|
||||
"category": {
|
||||
"bar": "Bar",
|
||||
"biergarten": "Beer Garden",
|
||||
"cafe": "Cafe",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.name": "Blakus",
|
||||
"amenity": {
|
||||
"category": {
|
||||
"bar": "Bārs",
|
||||
"biergarten": "Biergarten",
|
||||
"cafe": "Kafejnīca",
|
||||
|
||||
@ -25,7 +25,7 @@ type ReverseGeocodeResult = {
|
||||
type BlakusItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
amenity: string;
|
||||
category: string;
|
||||
tags: Record<string, string>;
|
||||
affinity: number;
|
||||
coords: {
|
||||
@ -88,7 +88,7 @@ export class HelloWorldModel extends Observable {
|
||||
|
||||
this.items = await this.getBlakus(params);
|
||||
|
||||
this.items.forEach(({ coords, title, amenity, affinity, id }) => {
|
||||
this.items.forEach(({ coords, title, category, affinity, id }) => {
|
||||
this.#map.addMarker({
|
||||
id,
|
||||
position: {
|
||||
@ -97,7 +97,7 @@ export class HelloWorldModel extends Observable {
|
||||
},
|
||||
detail: {
|
||||
title,
|
||||
description: localize(`amenity.${amenity}`),
|
||||
description: localize(`category.${category}`),
|
||||
affinity
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user