reset criteria on home, show filter on home, new BOM generation, Schema overhaul

This commit is contained in:
2024-07-23 20:46:38 +02:00
parent 9db23c2177
commit acec14d372
23 changed files with 577 additions and 131 deletions

View File

@@ -44,10 +44,13 @@ const logger = winston.createLogger({
await db.delete(schema.commercials);
await db.delete(schema.businesses);
await db.delete(schema.users);
let filePath = `./src/assets/geo.json`;
const rawData = readFileSync(filePath, 'utf8');
const geos = JSON.parse(rawData);
const sso = new SelectOptionsService();
//Broker
let filePath = `./data/broker.json`;
filePath = `./data/broker.json`;
let data: string = readFileSync(filePath, 'utf8');
const usersData: UserData[] = JSON.parse(data); // Erwartet ein Array von Objekten
const generatedUserData = [];
@@ -70,7 +73,7 @@ fs.ensureDirSync(`./pictures/property`);
//for (const userData of usersData) {
for (let index = 0; index < usersData.length; index++) {
const userData = usersData[index];
const user: User = { firstname: '', lastname: '', email: '' };
const user: User = { id: undefined, firstname: '', lastname: '', email: '' };
user.licensedIn = [];
userData.licensedIn.forEach(l => {
console.log(l['value'], l['name']);
@@ -91,6 +94,10 @@ for (let index = 0; index < usersData.length; index++) {
user.companyOverview = userData.companyOverview;
user.companyWebsite = userData.companyWebsite;
user.companyLocation = userData.companyLocation;
const [city, state] = user.companyLocation.split('-').map(e => e.trim());
const cityGeo = geos.states.find(s => s.state_code === state).cities.find(c => c.name === city);
const latitude = cityGeo.latitude;
const longitude = cityGeo.longitude;
user.offeredServices = userData.offeredServices;
user.gender = userData.gender;
user.customerType = 'professional';
@@ -142,6 +149,13 @@ for (let index = 0; index < commercialJsonData.length; index++) {
commercial.email = user.email;
commercial.draft = false;
commercial.type = sso.typesOfCommercialProperty.find(e => e.oldValue === String(commercial.type)).value;
const cityGeo = geos.states.find(s => s.state_code === commercial.state).cities.find(c => c.name === commercial.city);
try {
const latitude = cityGeo.latitude;
const longitude = cityGeo.longitude;
} catch (e) {
console.log(`----------------> ERROR ${commercial.state} - ${commercial.city}`);
}
// const reducedCommercial = {
// city: commercial.city,
// description: commercial.description,
@@ -175,6 +189,13 @@ for (let index = 0; index < businessJsonData.length; index++) {
const user = getRandomItem(generatedUserData);
business.email = user.email;
business.imageName = emailToDirName(user.email);
const cityGeo = geos.states.find(s => s.state_code === business.state).cities.find(c => c.name === business.city);
try {
const latitude = cityGeo.latitude;
const longitude = cityGeo.longitude;
} catch (e) {
console.log(`----------------> ERROR ${business.state} - ${business.city}`);
}
// const embeddingText = JSON.stringify({
// type: typesOfBusiness.find(b => b.value === String(business.type))?.name,
// title: business.title,

View File

@@ -16,18 +16,26 @@ EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "public"."listingsCategory" AS ENUM('commercialProperty', 'business');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "businesses" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"email" varchar(255),
"type" integer,
"type" varchar(255),
"title" varchar(255),
"description" text,
"city" varchar(255),
"state" char(2),
"zipCode" integer,
"county" varchar(255),
"price" double precision,
"favoritesForUser" varchar(30)[],
"draft" boolean,
"listingsCategory" varchar(255),
"listingsCategory" "listingsCategory",
"realEstateIncluded" boolean,
"leasedLocation" boolean,
"franchiseResale" boolean,
@@ -40,26 +48,27 @@ CREATE TABLE IF NOT EXISTS "businesses" (
"reasonForSale" varchar(255),
"brokerLicencing" varchar(255),
"internals" text,
"imagePath" varchar(200),
"imageName" varchar(200),
"created" timestamp,
"updated" timestamp,
"visits" integer,
"lastVisit" timestamp,
"embedding" vector(1536)
"latitude" double precision,
"longitude" double precision
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "commercials" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"serial_id" serial NOT NULL,
"email" varchar(255),
"type" integer,
"type" varchar(255),
"title" varchar(255),
"description" text,
"city" varchar(255),
"state" char(2),
"price" double precision,
"favoritesForUser" varchar(30)[],
"listingsCategory" varchar(255),
"listingsCategory" "listingsCategory",
"hideImage" boolean,
"draft" boolean,
"zipCode" integer,
@@ -70,7 +79,8 @@ CREATE TABLE IF NOT EXISTS "commercials" (
"updated" timestamp,
"visits" integer,
"lastVisit" timestamp,
"embedding" vector(1536)
"latitude" double precision,
"longitude" double precision
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users" (
@@ -94,7 +104,8 @@ CREATE TABLE IF NOT EXISTS "users" (
"customerSubType" "customerSubType",
"created" timestamp,
"updated" timestamp,
"embedding" vector(1536),
"latitude" double precision,
"longitude" double precision,
CONSTRAINT "users_email_unique" UNIQUE("email")
);
--> statement-breakpoint

View File

@@ -1,2 +0,0 @@
ALTER TABLE "businesses" ALTER COLUMN "type" SET DATA TYPE varchar(255);--> statement-breakpoint
ALTER TABLE "commercials" ALTER COLUMN "type" SET DATA TYPE varchar(255);

View File

@@ -0,0 +1 @@
ALTER TABLE "commercials" RENAME COLUMN "serial_id" TO "serialId";

View File

@@ -1,5 +1,5 @@
{
"id": "2d8edad3-5544-4cb1-a543-84c07737ea9f",
"id": "aa3e53ed-4f1b-4e00-84ea-58939189a427",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
@@ -23,7 +23,7 @@
},
"type": {
"name": "type",
"type": "integer",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
@@ -51,6 +51,18 @@
"primaryKey": false,
"notNull": false
},
"zipCode": {
"name": "zipCode",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"county": {
"name": "county",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"price": {
"name": "price",
"type": "double precision",
@@ -71,7 +83,8 @@
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"type": "listingsCategory",
"typeSchema": "public",
"primaryKey": false,
"notNull": false
},
@@ -147,8 +160,8 @@
"primaryKey": false,
"notNull": false
},
"imagePath": {
"name": "imagePath",
"imageName": {
"name": "imageName",
"type": "varchar(200)",
"primaryKey": false,
"notNull": false
@@ -177,9 +190,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -228,7 +247,7 @@
},
"type": {
"name": "type",
"type": "integer",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
@@ -270,7 +289,8 @@
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"type": "listingsCategory",
"typeSchema": "public",
"primaryKey": false,
"notNull": false
},
@@ -334,9 +354,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -488,9 +514,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -537,6 +569,14 @@
"male",
"female"
]
},
"public.listingsCategory": {
"name": "listingsCategory",
"schema": "public",
"values": [
"commercialProperty",
"business"
]
}
},
"schemas": {},

View File

@@ -1,6 +1,6 @@
{
"id": "93be31d4-beec-4ba8-8d4a-a52763342335",
"prevId": "2d8edad3-5544-4cb1-a543-84c07737ea9f",
"id": "ff415931-0de6-4c89-900f-c6fd64830b2e",
"prevId": "aa3e53ed-4f1b-4e00-84ea-58939189a427",
"version": "7",
"dialect": "postgresql",
"tables": {
@@ -51,6 +51,18 @@
"primaryKey": false,
"notNull": false
},
"zipCode": {
"name": "zipCode",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"county": {
"name": "county",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"price": {
"name": "price",
"type": "double precision",
@@ -71,7 +83,8 @@
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"type": "listingsCategory",
"typeSchema": "public",
"primaryKey": false,
"notNull": false
},
@@ -147,8 +160,8 @@
"primaryKey": false,
"notNull": false
},
"imagePath": {
"name": "imagePath",
"imageName": {
"name": "imageName",
"type": "varchar(200)",
"primaryKey": false,
"notNull": false
@@ -177,9 +190,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -214,8 +233,8 @@
"notNull": true,
"default": "gen_random_uuid()"
},
"serial_id": {
"name": "serial_id",
"serialId": {
"name": "serialId",
"type": "serial",
"primaryKey": false,
"notNull": true
@@ -270,7 +289,8 @@
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"type": "listingsCategory",
"typeSchema": "public",
"primaryKey": false,
"notNull": false
},
@@ -334,9 +354,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -488,9 +514,15 @@
"primaryKey": false,
"notNull": false
},
"embedding": {
"name": "embedding",
"type": "vector(1536)",
"latitude": {
"name": "latitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"longitude": {
"name": "longitude",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
@@ -537,6 +569,14 @@
"male",
"female"
]
},
"public.listingsCategory": {
"name": "listingsCategory",
"schema": "public",
"values": [
"commercialProperty",
"business"
]
}
},
"schemas": {},

View File

@@ -5,15 +5,15 @@
{
"idx": 0,
"version": "7",
"when": 1720872296432,
"tag": "0000_slim_nova",
"when": 1721737805677,
"tag": "0000_freezing_vengeance",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1721134224160,
"tag": "0001_heavy_bloodscream",
"when": 1721738173220,
"tag": "0001_steady_phantom_reporter",
"breakpoints": true
}
]

View File

@@ -1,9 +1,10 @@
import { boolean, char, doublePrecision, integer, jsonb, pgEnum, pgTable, serial, text, timestamp, uuid, varchar, vector } from 'drizzle-orm/pg-core';
import { boolean, char, doublePrecision, integer, jsonb, pgEnum, pgTable, serial, text, timestamp, uuid, varchar } from 'drizzle-orm/pg-core';
import { AreasServed, LicensedIn } from '../models/db.model';
export const PG_CONNECTION = 'PG_CONNECTION';
export const genderEnum = pgEnum('gender', ['male', 'female']);
export const customerTypeEnum = pgEnum('customerType', ['buyer', 'professional']);
export const customerSubTypeEnum = pgEnum('customerSubType', ['broker', 'cpa', 'attorney', 'titleCompany', 'surveyor', 'appraiser']);
export const listingsCategoryEnum = pgEnum('listingsCategory', ['commercialProperty', 'business']);
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
@@ -26,7 +27,9 @@ export const users = pgTable('users', {
customerSubType: customerSubTypeEnum('customerSubType'),
created: timestamp('created'),
updated: timestamp('updated'),
embedding: vector('embedding', { dimensions: 1536 }),
latitude: doublePrecision('latitude'),
longitude: doublePrecision('longitude'),
// embedding: vector('embedding', { dimensions: 1536 }),
});
export const businesses = pgTable('businesses', {
@@ -37,10 +40,12 @@ export const businesses = pgTable('businesses', {
description: text('description'),
city: varchar('city', { length: 255 }),
state: char('state', { length: 2 }),
zipCode: integer('zipCode'),
county: varchar('county', { length: 255 }),
price: doublePrecision('price'),
favoritesForUser: varchar('favoritesForUser', { length: 30 }).array(),
draft: boolean('draft'),
listingsCategory: varchar('listingsCategory', { length: 255 }),
listingsCategory: listingsCategoryEnum('listingsCategory'), //varchar('listingsCategory', { length: 255 }),
realEstateIncluded: boolean('realEstateIncluded'),
leasedLocation: boolean('leasedLocation'),
franchiseResale: boolean('franchiseResale'),
@@ -53,18 +58,19 @@ export const businesses = pgTable('businesses', {
reasonForSale: varchar('reasonForSale', { length: 255 }),
brokerLicencing: varchar('brokerLicencing', { length: 255 }),
internals: text('internals'),
imageName: varchar('imagePath', { length: 200 }),
imageName: varchar('imageName', { length: 200 }),
created: timestamp('created'),
updated: timestamp('updated'),
visits: integer('visits'),
lastVisit: timestamp('lastVisit'),
// Neue Spalte für das OpenAI Embedding
embedding: vector('embedding', { dimensions: 1536 }),
latitude: doublePrecision('latitude'),
longitude: doublePrecision('longitude'),
// embedding: vector('embedding', { dimensions: 1536 }),
});
export const commercials = pgTable('commercials', {
id: uuid('id').primaryKey().defaultRandom(),
serialId: serial('serial_id'),
serialId: serial('serialId'),
email: varchar('email', { length: 255 }).references(() => users.email),
type: varchar('type', { length: 255 }),
title: varchar('title', { length: 255 }),
@@ -73,7 +79,7 @@ export const commercials = pgTable('commercials', {
state: char('state', { length: 2 }),
price: doublePrecision('price'),
favoritesForUser: varchar('favoritesForUser', { length: 30 }).array(),
listingsCategory: varchar('listingsCategory', { length: 255 }),
listingsCategory: listingsCategoryEnum('listingsCategory'), //listingsCategory: varchar('listingsCategory', { length: 255 }),
hideImage: boolean('hideImage'),
draft: boolean('draft'),
zipCode: integer('zipCode'),
@@ -84,5 +90,7 @@ export const commercials = pgTable('commercials', {
updated: timestamp('updated'),
visits: integer('visits'),
lastVisit: timestamp('lastVisit'),
embedding: vector('embedding', { dimensions: 1536 }),
latitude: doublePrecision('latitude'),
longitude: doublePrecision('longitude'),
// embedding: vector('embedding', { dimensions: 1536 }),
});

View File

@@ -9,6 +9,16 @@ import { FileService } from '../file/file.service.js';
import { BusinessListing, CommercialPropertyListing } from '../models/db.model';
import { BusinessListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
const EARTH_RADIUS_KM = 6371; // Erdradius in Kilometern
const getDistanceQuery = (lat: number, lon: number) => sql`
${EARTH_RADIUS_KM} * 2 * ASIN(SQRT(
POWER(SIN((${lat} - ${businesses.latitude}) * PI() / 180 / 2), 2) +
COS(${lat} * PI() / 180) * COS(${businesses.latitude} * PI() / 180) *
POWER(SIN((${lon} - ${businesses.longitude}) * PI() / 180 / 2), 2)
))
`;
@Injectable()
export class BusinessListingService {
constructor(
@@ -142,7 +152,7 @@ export class BusinessListingService {
const [{ value: totalCount }] = await countQuery;
return totalCount;
}
async findBusinessesById(id: string, user: JwtUser): Promise<CommercialPropertyListing> {
async findBusinessesById(id: string, user: JwtUser): Promise<BusinessListing> {
let result = await this.conn
.select()
.from(businesses)
@@ -159,7 +169,7 @@ export class BusinessListingService {
return (await this.conn
.select()
.from(businesses)
.where(and(...conditions))) as CommercialPropertyListing[];
.where(and(...conditions))) as BusinessListing[];
}
// #### CREATE ########################################
async createListing(data: BusinessListing): Promise<BusinessListing> {

View File

@@ -6,7 +6,7 @@ import { Logger } from 'winston';
import * as schema from '../drizzle/schema.js';
import { commercials, PG_CONNECTION } from '../drizzle/schema.js';
import { FileService } from '../file/file.service.js';
import { BusinessListing, CommercialPropertyListing } from '../models/db.model';
import { CommercialPropertyListing } from '../models/db.model';
import { CommercialPropertyListingCriteria, emailToDirName, JwtUser } from '../models/main.model.js';
@Injectable()
@@ -133,7 +133,7 @@ export class CommercialPropertyService {
data.imageOrder = imageOrder;
}
const [updateListing] = await this.conn.update(commercials).set(data).where(eq(commercials.id, id)).returning();
return updateListing as BusinessListing | CommercialPropertyListing;
return updateListing as CommercialPropertyListing;
}
// ##############################################################
// Images for commercial Properties

View File

@@ -1,25 +1,25 @@
export interface User {
id?: string;
firstname: string;
lastname: string;
email: string;
phoneNumber?: string;
description?: string;
companyName?: string;
companyOverview?: string;
companyWebsite?: string;
companyLocation?: string;
offeredServices?: string;
areasServed?: AreasServed[];
hasProfile?: boolean;
hasCompanyLogo?: boolean;
licensedIn?: LicensedIn[];
gender?: 'male' | 'female';
customerType?: 'buyer' | 'professional';
customerSubType?: 'broker' | 'cpa' | 'attorney' | 'titleCompany' | 'surveyor' | 'appraiser';
created?: Date;
updated?: Date;
}
// export interface User {
// id?: string;
// firstname: string;
// lastname: string;
// email: string;
// phoneNumber?: string;
// description?: string;
// companyName?: string;
// companyOverview?: string;
// companyWebsite?: string;
// companyLocation?: string;
// offeredServices?: string;
// areasServed?: AreasServed[];
// hasProfile?: boolean;
// hasCompanyLogo?: boolean;
// licensedIn?: LicensedIn[];
// gender?: 'male' | 'female';
// customerType?: 'buyer' | 'professional';
// customerSubType?: 'broker' | 'cpa' | 'attorney' | 'titleCompany' | 'surveyor' | 'appraiser';
// created?: Date;
// updated?: Date;
// }
export interface UserData {
id?: string;
firstname: string;
@@ -42,22 +42,53 @@ export interface UserData {
created?: Date;
updated?: Date;
}
export type Gender = 'male' | 'female';
export type CustomerType = 'buyer' | 'professional';
export type CustomerSubType = 'broker' | 'cpa' | 'attorney' | 'titleCompany' | 'surveyor' | 'appraiser';
export type ListingsCategory = 'commercialProperty' | 'business';
export interface User {
id: string; // UUID as a string
firstname: string;
lastname: string;
email: string;
phoneNumber?: string;
description?: string;
companyName?: string;
companyOverview?: string;
companyWebsite?: string;
companyLocation?: string;
offeredServices?: string;
areasServed?: AreasServed[];
hasProfile?: boolean;
hasCompanyLogo?: boolean;
licensedIn?: LicensedIn[];
gender?: Gender;
customerType?: CustomerType;
customerSubType?: CustomerSubType;
created?: Date;
updated?: Date;
latitude?: number;
longitude?: number;
}
export interface BusinessListing {
id: string;
email?: string;
id: string; // UUID as a string
email: string; // References users.email
type?: string;
title?: string;
description?: string;
city?: string;
state?: string;
price?: number;
favoritesForUser?: string[];
state?: string; // 2-character state code
zipCode?: number;
county?: string;
price?: number; // double precision
favoritesForUser?: string[]; // Array of strings
draft?: boolean;
listingsCategory?: ListingsCategory;
realEstateIncluded?: boolean;
leasedLocation?: boolean;
franchiseResale?: boolean;
salesRevenue?: number;
cashFlow?: number;
salesRevenue?: number; // double precision
cashFlow?: number; // double precision
supportAndTraining?: string;
employees?: number;
established?: number;
@@ -70,31 +101,35 @@ export interface BusinessListing {
updated?: Date;
visits?: number;
lastVisit?: Date;
listingsCategory?: 'commercialProperty' | 'business';
latitude?: number; // double precision
longitude?: number; // double precision
}
export interface CommercialPropertyListing {
id: string;
serialId?: number;
email?: string;
id: string; // UUID as a string
serialId: number; // Serial ID
email: string; // References users.email
type?: string;
title?: string;
description?: string;
city?: string;
state?: string;
price?: number;
favoritesForUser?: string[];
state?: string; // 2-character state code
price?: number; // double precision
favoritesForUser?: string[]; // Array of strings
listingsCategory?: ListingsCategory;
hideImage?: boolean;
draft?: boolean;
zipCode?: number;
county?: string;
imageOrder?: string[];
imageOrder?: string[]; // Array of strings
imagePath?: string;
created?: Date;
updated?: Date;
visits?: number;
lastVisit?: Date;
listingsCategory?: 'commercialProperty' | 'business';
latitude?: number; // double precision
longitude?: number; // double precision
// embedding?: number[]; // Uncomment if needed for vector embedding
}
export interface AreasServed {
county: string;

View File

@@ -103,7 +103,7 @@ export class UserService {
.from(schema.users)
.where(sql`email = ${email}`)) as User[];
if (users.length === 0) {
const user: User = { email, firstname: jwtuser.firstname, lastname: jwtuser.lastname, customerType: 'buyer' };
const user: User = { id: undefined, email, firstname: jwtuser.firstname, lastname: jwtuser.lastname, customerType: 'buyer' };
this.saveUser(user);
return user;
} else {