Überarbeitung

This commit is contained in:
2024-08-09 17:59:49 +02:00
parent 6d1c50d5df
commit 1e1d5cea57
27 changed files with 135 additions and 112 deletions

View File

@@ -60,3 +60,8 @@ pictures_base
src/*.js
bun.lockb
#drizzle migrations
src/drizzle/migrations
importlog.txt

View File

@@ -137,7 +137,7 @@ for (let index = 0; index < usersData.length; index++) {
user.companyWebsite = userData.companyWebsite;
const [city, state] = userData.companyLocation.split('-').map(e => e.trim());
user.companyLocation = {};
user.companyLocation.city = city;
user.companyLocation.name = city;
user.companyLocation.state = state;
const cityGeo = geos.states.find(s => s.state_code === state).cities.find(c => c.name === city);
user.companyLocation.latitude = cityGeo.latitude;
@@ -188,7 +188,7 @@ for (let index = 0; index < commercialJsonData.length; index++) {
commercial.location = {};
commercial.location.latitude = cityGeo.latitude;
commercial.location.longitude = cityGeo.longitude;
commercial.location.city = commercialJsonData[index].city;
commercial.location.name = commercialJsonData[index].city;
commercial.location.state = commercialJsonData[index].state;
// console.log(JSON.stringify(commercial.location));
} catch (e) {
@@ -229,7 +229,7 @@ for (let index = 0; index < businessJsonData.length; index++) {
business.location = {};
business.location.latitude = cityGeo.latitude;
business.location.longitude = cityGeo.longitude;
business.location.city = businessJsonData[index].city;
business.location.name = businessJsonData[index].city;
business.location.state = businessJsonData[index].state;
} catch (e) {
console.log(`----------------> ERROR ${businessJsonData[index].state} - ${businessJsonData[index].city}`);

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { readFileSync } from 'fs';
import path, { join } from 'path';
import { CountyResult, GeoResult } from 'src/models/main.model.js';
import { CityAndStateResult, CountyResult, GeoResult } from 'src/models/main.model.js';
import { fileURLToPath } from 'url';
import { City, CountyData, Geo, State } from '../models/server.model.js';
@@ -52,7 +52,7 @@ export class GeoService {
if (city.name.toLowerCase().startsWith(prefix.toLowerCase())) {
result.push({
id: city.id,
city: city.name,
name: city.name,
state: state.state_code,
//state_code: state.state_code,
latitude: city.latitude,
@@ -63,8 +63,8 @@ export class GeoService {
});
return state ? result.filter(e => e.state.toLowerCase() === state.toLowerCase()) : result;
}
findCitiesAndStatesStartingWith(prefix: string, state?: string): Array<{ id: string; name: string; type: 'city' | 'state'; state: string }> {
const results: Array<{ id: string; name: string; type: 'city' | 'state'; state: string }> = [];
findCitiesAndStatesStartingWith(prefix: string, state?: string): Array<CityAndStateResult> {
const results: Array<CityAndStateResult> = [];
const lowercasePrefix = prefix.toLowerCase();
@@ -73,10 +73,9 @@ export class GeoService {
for (const state of this.geo.states) {
if (state.name.toLowerCase().startsWith(lowercasePrefix)) {
results.push({
id: state.id.toString(),
name: state.name,
id: state.id,
type: 'state',
state: state.state_code,
content: state,
});
}
@@ -84,10 +83,9 @@ export class GeoService {
for (const city of state.cities) {
if (city.name.toLowerCase().startsWith(lowercasePrefix)) {
results.push({
id: city.id.toString(),
name: city.name,
id: city.id,
type: 'city',
state: state.state_code,
content: { state: state.state_code, ...city },
});
}
}
@@ -97,7 +95,7 @@ export class GeoService {
return results.sort((a, b) => {
if (a.type === 'state' && b.type === 'city') return -1;
if (a.type === 'city' && b.type === 'state') return 1;
return a.name.localeCompare(b.name);
return a.content.name.localeCompare(b.content.name);
});
}
getCityWithCoords(state: string, city: string): City {

View File

@@ -25,10 +25,10 @@ export class BusinessListingService {
const whereConditions: SQL[] = [];
if (criteria.city && criteria.searchType === 'exact') {
whereConditions.push(ilike(businesses.city, `%${criteria.city}%`));
whereConditions.push(ilike(businesses.city, `%${criteria.city.name}%`));
}
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city.name);
whereConditions.push(sql`${getDistanceQuery(businesses, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
}
if (criteria.types && criteria.types.length > 0) {
@@ -180,11 +180,13 @@ export class BusinessListingService {
return convertDrizzleBusinessToBusiness(createdListing);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
const filteredErrors = error.errors
.map(item => ({
...item,
field: item.path[0],
}))
.filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
throw new BadRequestException(filteredErrors);
}
throw error;
}
@@ -200,11 +202,13 @@ export class BusinessListingService {
return convertDrizzleBusinessToBusiness(updateListing);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
const filteredErrors = error.errors
.map(item => ({
...item,
field: item.path[0],
}))
.filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
throw new BadRequestException(filteredErrors);
}
throw error;
}

View File

@@ -24,10 +24,10 @@ export class CommercialPropertyService {
const whereConditions: SQL[] = [];
if (criteria.city && criteria.searchType === 'exact') {
whereConditions.push(ilike(schema.commercials.city, `%${criteria.city}%`));
whereConditions.push(ilike(schema.commercials.city, `%${criteria.city.name}%`));
}
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city.name);
whereConditions.push(sql`${getDistanceQuery(commercials, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
}
if (criteria.types && criteria.types.length > 0) {
@@ -131,11 +131,13 @@ export class CommercialPropertyService {
return convertDrizzleCommercialToCommercial(createdListing);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
const filteredErrors = error.errors
.map(item => ({
...item,
field: item.path[0],
}))
.filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
throw new BadRequestException(filteredErrors);
}
throw error;
}
@@ -157,11 +159,13 @@ export class CommercialPropertyService {
return convertDrizzleCommercialToCommercial(updateListing);
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
const filteredErrors = error.errors
.map(item => ({
...item,
field: item.path[0],
}))
.filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
throw new BadRequestException(filteredErrors);
}
throw error;
}

View File

@@ -111,7 +111,7 @@ export const LicensedInSchema = z.object({
state: z.string().nonempty('State is required'),
});
export const GeoSchema = z.object({
city: z.string(),
name: z.string(),
state: z.string().refine(val => USStates.safeParse(val).success, {
message: 'Invalid state. Must be a valid 2-letter US state code.',
}),

View File

@@ -1,4 +1,5 @@
import { BusinessListing, CommercialPropertyListing, Sender, User } from './db.model.js';
import { State } from './server.model.js';
export interface StatesResult {
state: string;
@@ -59,7 +60,7 @@ export interface ListCriteria {
page: number;
types: string[];
state: string;
city: string;
city: GeoResult;
prompt: string;
searchType: 'exact' | 'radius';
// radius: '5' | '20' | '50' | '100' | '200' | '300' | '400' | '500';
@@ -224,18 +225,23 @@ export interface UploadParams {
}
export interface GeoResult {
id: number;
city: string;
name: string;
state: string;
// state_code: string;
latitude: number;
longitude: number;
}
export interface CityAndStateResult {
interface CityResult {
id: number;
name: string;
type: string;
state: string;
type: 'city';
content: GeoResult;
}
interface StateResult {
id: number;
type: 'state';
content: State;
}
export type CityAndStateResult = CityResult | StateResult;
export interface CountyResult {
id: number;
name: string;

View File

@@ -26,10 +26,10 @@ export class UserService {
const whereConditions: SQL[] = [];
whereConditions.push(eq(schema.users.customerType, 'professional'));
if (criteria.city && criteria.searchType === 'exact') {
whereConditions.push(ilike(schema.users.city, `%${criteria.city}%`));
whereConditions.push(ilike(schema.users.city, `%${criteria.city.name}%`));
}
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city);
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city.name);
whereConditions.push(sql`${getDistanceQuery(schema.users, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
}
if (criteria.types && criteria.types.length > 0) {
@@ -139,11 +139,13 @@ export class UserService {
}
} catch (error) {
if (error instanceof ZodError) {
const formattedErrors = error.errors.map(err => ({
field: err.path.join('.'),
message: err.message,
}));
throw new BadRequestException(formattedErrors);
const filteredErrors = error.errors
.map(item => ({
...item,
field: item.path[0],
}))
.filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
throw new BadRequestException(filteredErrors);
}
throw error;
}

View File

@@ -33,11 +33,14 @@ type DrizzleUser = typeof users.$inferSelect;
type DrizzleBusinessListing = typeof businesses.$inferSelect;
type DrizzleCommercialPropertyListing = typeof commercials.$inferSelect;
export function convertBusinessToDrizzleBusiness(businessListing: Partial<BusinessListing>): DrizzleBusinessListing {
return flattenObject(businessListing);
const drizzleBusinessListing = flattenObject(businessListing);
drizzleBusinessListing.city = drizzleBusinessListing.name;
delete drizzleBusinessListing.name;
return drizzleBusinessListing;
}
export function convertDrizzleBusinessToBusiness(drizzleBusinessListing: Partial<DrizzleBusinessListing>): BusinessListing {
const o = {
location_city: drizzleBusinessListing.city,
location_name: drizzleBusinessListing.city,
location_state: drizzleBusinessListing.state,
location_latitude: drizzleBusinessListing.latitude,
location_longitude: drizzleBusinessListing.longitude,
@@ -50,11 +53,14 @@ export function convertDrizzleBusinessToBusiness(drizzleBusinessListing: Partial
return unflattenObject(o);
}
export function convertCommercialToDrizzleCommercial(commercialPropertyListing: Partial<CommercialPropertyListing>): DrizzleCommercialPropertyListing {
return flattenObject(commercialPropertyListing);
const drizzleCommercialPropertyListing = flattenObject(commercialPropertyListing);
drizzleCommercialPropertyListing.city = drizzleCommercialPropertyListing.name;
delete drizzleCommercialPropertyListing.name;
return drizzleCommercialPropertyListing;
}
export function convertDrizzleCommercialToCommercial(drizzleCommercialPropertyListing: Partial<DrizzleCommercialPropertyListing>): CommercialPropertyListing {
const o = {
location_city: drizzleCommercialPropertyListing.city,
location_name: drizzleCommercialPropertyListing.city,
location_state: drizzleCommercialPropertyListing.state,
location_latitude: drizzleCommercialPropertyListing.latitude,
location_longitude: drizzleCommercialPropertyListing.longitude,
@@ -67,12 +73,15 @@ export function convertDrizzleCommercialToCommercial(drizzleCommercialPropertyLi
return unflattenObject(o);
}
export function convertUserToDrizzleUser(user: Partial<User>): DrizzleUser {
return flattenObject(user);
const drizzleUser = flattenObject(user);
drizzleUser.city = drizzleUser.name;
delete drizzleUser.name;
return drizzleUser;
}
export function convertDrizzleUserToUser(drizzleUser: Partial<DrizzleUser>): User {
const o = {
companyLocation_city: drizzleUser.city,
companyLocation_name: drizzleUser.city,
companyLocation_state: drizzleUser.state,
companyLocation_latitude: drizzleUser.latitude,
companyLocation_longitude: drizzleUser.longitude,