Fix business filtering logic and add docker sync guide
This commit is contained in:
@@ -5,7 +5,7 @@ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||
import { Logger } from 'winston';
|
||||
import { ZodError } from 'zod';
|
||||
import * as schema from '../drizzle/schema';
|
||||
import { businesses_json, PG_CONNECTION, users_json } from '../drizzle/schema';
|
||||
import { businesses_json, PG_CONNECTION } from '../drizzle/schema';
|
||||
import { GeoService } from '../geo/geo.service';
|
||||
import { BusinessListing, BusinessListingSchema } from '../models/db.model';
|
||||
import { BusinessListingCriteria, JwtUser } from '../models/main.model';
|
||||
@@ -18,27 +18,30 @@ export class BusinessListingService {
|
||||
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
||||
@Inject(PG_CONNECTION) private conn: NodePgDatabase<typeof schema>,
|
||||
private geoService?: GeoService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
private getWhereConditions(criteria: BusinessListingCriteria, user: JwtUser): SQL[] {
|
||||
const whereConditions: SQL[] = [];
|
||||
this.logger.info('getWhereConditions start', { criteria: JSON.stringify(criteria) });
|
||||
|
||||
if (criteria.city && criteria.searchType === 'exact') {
|
||||
whereConditions.push(sql`(${businesses_json.data}->'location'->>'name') ILIKE ${criteria.city.name}`);
|
||||
}
|
||||
|
||||
if (criteria.city && criteria.radius && criteria.searchType === 'radius' && criteria.radius) {
|
||||
this.logger.debug('Adding radius search filter', { city: criteria.city.name, radius: criteria.radius });
|
||||
const cityGeo = this.geoService.getCityWithCoords(criteria.state, criteria.city.name);
|
||||
whereConditions.push(sql`${getDistanceQuery(businesses_json, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius}`);
|
||||
whereConditions.push(sql`(${getDistanceQuery(businesses_json, cityGeo.latitude, cityGeo.longitude)} <= ${criteria.radius})`);
|
||||
}
|
||||
if (criteria.types && Array.isArray(criteria.types) && criteria.types.length > 0) {
|
||||
const validTypes = criteria.types.filter(t => t !== null && t !== undefined && t !== '');
|
||||
if (validTypes.length > 0) {
|
||||
whereConditions.push(inArray(sql`${businesses_json.data}->>'type'`, validTypes));
|
||||
}
|
||||
if (criteria.types && criteria.types.length > 0) {
|
||||
this.logger.warn('Adding business category filter', { types: criteria.types });
|
||||
// Use explicit SQL with IN for robust JSONB comparison
|
||||
const typeValues = criteria.types.map(t => sql`${t}`);
|
||||
whereConditions.push(sql`((${businesses_json.data}->>'type') IN (${sql.join(typeValues, sql`, `)}))`);
|
||||
}
|
||||
|
||||
if (criteria.state) {
|
||||
this.logger.debug('Adding state filter', { state: criteria.state });
|
||||
whereConditions.push(sql`(${businesses_json.data}->'location'->>'state') = ${criteria.state}`);
|
||||
}
|
||||
|
||||
@@ -105,27 +108,30 @@ export class BusinessListingService {
|
||||
if (criteria.title && criteria.title.trim() !== '') {
|
||||
const searchTerm = `%${criteria.title.trim()}%`;
|
||||
whereConditions.push(
|
||||
or(
|
||||
sql`(${businesses_json.data}->>'title') ILIKE ${searchTerm}`,
|
||||
sql`(${businesses_json.data}->>'description') ILIKE ${searchTerm}`
|
||||
)
|
||||
sql`((${businesses_json.data}->>'title') ILIKE ${searchTerm} OR (${businesses_json.data}->>'description') ILIKE ${searchTerm})`
|
||||
);
|
||||
}
|
||||
if (criteria.brokerName) {
|
||||
const { firstname, lastname } = splitName(criteria.brokerName);
|
||||
if (firstname === lastname) {
|
||||
whereConditions.push(sql`(${users_json.data}->>'firstname') ILIKE ${`%${firstname}%`} OR (${users_json.data}->>'lastname') ILIKE ${`%${lastname}%`}`);
|
||||
whereConditions.push(
|
||||
sql`((${schema.users_json.data}->>'firstname') ILIKE ${`%${firstname}%`} OR (${schema.users_json.data}->>'lastname') ILIKE ${`%${lastname}%`})`
|
||||
);
|
||||
} else {
|
||||
whereConditions.push(sql`(${users_json.data}->>'firstname') ILIKE ${`%${firstname}%`} AND (${users_json.data}->>'lastname') ILIKE ${`%${lastname}%`}`);
|
||||
whereConditions.push(
|
||||
sql`((${schema.users_json.data}->>'firstname') ILIKE ${`%${firstname}%`} AND (${schema.users_json.data}->>'lastname') ILIKE ${`%${lastname}%`})`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (criteria.email) {
|
||||
whereConditions.push(eq(users_json.email, criteria.email));
|
||||
whereConditions.push(eq(schema.users_json.email, criteria.email));
|
||||
}
|
||||
if (user?.role !== 'admin') {
|
||||
whereConditions.push(or(eq(businesses_json.email, user?.email), sql`(${businesses_json.data}->>'draft')::boolean IS NOT TRUE`));
|
||||
whereConditions.push(
|
||||
sql`((${businesses_json.email} = ${user?.email || null}) OR (${businesses_json.data}->>'draft')::boolean IS NOT TRUE)`
|
||||
);
|
||||
}
|
||||
whereConditions.push(and(sql`(${users_json.data}->>'customerType') = 'professional'`, sql`(${users_json.data}->>'customerSubType') = 'broker'`));
|
||||
this.logger.warn('whereConditions count', { count: whereConditions.length });
|
||||
return whereConditions;
|
||||
}
|
||||
|
||||
@@ -135,24 +141,21 @@ export class BusinessListingService {
|
||||
const query = this.conn
|
||||
.select({
|
||||
business: businesses_json,
|
||||
brokerFirstName: sql`${users_json.data}->>'firstname'`.as('brokerFirstName'),
|
||||
brokerLastName: sql`${users_json.data}->>'lastname'`.as('brokerLastName'),
|
||||
brokerFirstName: sql`${schema.users_json.data}->>'firstname'`.as('brokerFirstName'),
|
||||
brokerLastName: sql`${schema.users_json.data}->>'lastname'`.as('brokerLastName'),
|
||||
})
|
||||
.from(businesses_json)
|
||||
.leftJoin(users_json, eq(businesses_json.email, users_json.email));
|
||||
.leftJoin(schema.users_json, eq(businesses_json.email, schema.users_json.email));
|
||||
|
||||
const whereConditions = this.getWhereConditions(criteria, user);
|
||||
|
||||
// Uncomment for debugging filter issues:
|
||||
// this.logger.info('Filter Criteria:', { criteria });
|
||||
// this.logger.info('Where Conditions Count:', { count: whereConditions.length });
|
||||
this.logger.warn('Filter Criteria:', { criteria: JSON.stringify(criteria) });
|
||||
|
||||
if (whereConditions.length > 0) {
|
||||
const whereClause = and(...whereConditions);
|
||||
query.where(whereClause);
|
||||
const whereClause = sql.join(whereConditions, sql` AND `);
|
||||
query.where(sql`(${whereClause})`);
|
||||
|
||||
// Uncomment for debugging SQL queries:
|
||||
// this.logger.info('Generated SQL:', { sql: query.toSQL() });
|
||||
this.logger.warn('Generated SQL:', { sql: query.toSQL().sql, params: query.toSQL().params });
|
||||
}
|
||||
|
||||
// Sortierung
|
||||
@@ -228,13 +231,13 @@ export class BusinessListingService {
|
||||
}
|
||||
|
||||
async getBusinessListingsCount(criteria: BusinessListingCriteria, user: JwtUser): Promise<number> {
|
||||
const countQuery = this.conn.select({ value: count() }).from(businesses_json).leftJoin(users_json, eq(businesses_json.email, users_json.email));
|
||||
const countQuery = this.conn.select({ value: count() }).from(businesses_json).leftJoin(schema.users_json, eq(businesses_json.email, schema.users_json.email));
|
||||
|
||||
const whereConditions = this.getWhereConditions(criteria, user);
|
||||
|
||||
if (whereConditions.length > 0) {
|
||||
const whereClause = and(...whereConditions);
|
||||
countQuery.where(whereClause);
|
||||
const whereClause = sql.join(whereConditions, sql` AND `);
|
||||
countQuery.where(sql`(${whereClause})`);
|
||||
}
|
||||
|
||||
const [{ value: totalCount }] = await countQuery;
|
||||
|
||||
Reference in New Issue
Block a user