import { CityName, getDb, ObjectId, Street } from "../index"; import type { StreetHint } from "./streets.types"; import { AnyBulkWriteOperation, BulkWriteOptions, BulkWriteResult, Collection, Filter, ObjectId as MongoObjectId, } from "mongodb"; export const getStreetsCollection = (): Collection => { return getDb().collection("streets"); }; export const bulkWriteStreets = async ( operations: AnyBulkWriteOperation[], options?: BulkWriteOptions, ): Promise => { return getStreetsCollection().bulkWrite(operations, options); }; export const findStreets = async ( filter: Filter = {}, ): Promise => { return await getStreetsCollection().find(filter).toArray(); }; export const getStreetById = async ( streetId: string, ): Promise => { const street = await getStreetsCollection().findOne({ _id: new ObjectId(streetId), }); return street ? street : null; }; export const getStreetsByCityName = async ( cityName: CityName, ): Promise => { return await getStreetsCollection() .find({ cityName }) .sort({ name: 1 }) .toArray(); }; export const getStreetByStreetId = async ( streetId: string, ): Promise => { const street = await getStreetsCollection().findOne({ id: streetId }); return street ? street : null; }; /** Get street by business id and city. Use this when the client's city is known so the same id in another city is not returned. */ export const getStreetByStreetIdAndCity = async ( streetId: string, cityName: CityName, ): Promise => { const street = await getStreetsCollection().findOne({ id: streetId, cityName, }); return street ? street : null; }; export const createStreet = async ( streetData: Omit, ): Promise => { const street: Omit = { ...streetData, isActive: streetData.isActive ?? true, createdAt: new Date(), updatedAt: new Date(), }; const { insertedId } = await getStreetsCollection().insertOne( street as Street, ); return insertedId; }; export const updateStreet = async ( streetId: string, data: Partial>, ): Promise => { const result = await getStreetsCollection().findOneAndUpdate( { _id: new ObjectId(streetId) }, { $set: { ...data, updatedAt: new Date() } }, { returnDocument: "after" }, ); return result || null; }; /** * Add or update a street hint on an already-fetched street. * Only place that creates a new hint id (Date.getTime().toString()). Returns null if hint.id provided but not found, or text empty. */ export const upsertStreetHintOnStreet = async ( street: Street, hint: Partial & Pick, ): Promise => { const text = hint.text.trim(); if (!text) return null; const hints = street.hints || []; let updatedHints: StreetHint[]; if (hint.id != null && hint.id !== "") { const hintIndex = hints.findIndex((h) => String(h.id) === String(hint.id)); if (hintIndex === -1) return null; updatedHints = [...hints]; updatedHints[hintIndex] = { id: String(hint.id), text }; } else { updatedHints = [...hints, { id: new Date().getTime().toString(), text }]; } return updateStreet(street._id.toString(), { hints: updatedHints }); }; /** Remove a hint from a street. streetId is the street business id (e.g. "703"). Updates document updatedAt. */ export const deleteStreetHint = async ( streetId: string, hintId: string, ): Promise => { const result = await getStreetsCollection().findOneAndUpdate( { id: streetId }, { $pull: { hints: { id: hintId } }, $set: { updatedAt: new Date() } }, { returnDocument: "after" }, ); if (result) { console.info("Street hint deleted", { streetId, hintId }); } return result || null; }; export const deleteStreet = async (streetId: string): Promise => { const result = await getStreetsCollection().deleteOne({ _id: new ObjectId(streetId), }); return result.deletedCount > 0; };