mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 06:26:26 +00:00
Tours: copy a planned tour's import link in the repository, and teach the tests the new columns
This commit is contained in:
@@ -220,12 +220,23 @@ export class ToursRepository extends TrekRepository<Tours> {
|
||||
|
||||
/**
|
||||
* TO8 — a copied tour keeps every column, `created_at` included, so the
|
||||
* copy lists its tours in the source's order.
|
||||
* copy lists its tours in the source's order. A tour planned from an import
|
||||
* points at the copied import (`copiedPlaceIds` maps source to copy), never
|
||||
* back into the source trip.
|
||||
*/
|
||||
async insertCopy(place_id: number, row: Omit<TourRow, 'place_id'>): Promise<void> {
|
||||
async insertCopy(
|
||||
place_id: number,
|
||||
row: Omit<TourRow, 'place_id'>,
|
||||
copiedPlaceIds: ReadonlyMap<number, number>,
|
||||
): Promise<void> {
|
||||
const derivedFrom = row.derived_from_place_id;
|
||||
await this.db()
|
||||
.insertInto('tours')
|
||||
.values({ ...row, place_id })
|
||||
.values({
|
||||
...row,
|
||||
place_id,
|
||||
derived_from_place_id: derivedFrom === null ? null : (copiedPlaceIds.get(derivedFrom) ?? null),
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -743,10 +743,7 @@ export class TripsService {
|
||||
for (const { place_id, ...tour } of oldTours) {
|
||||
const newPlaceId = placeMap.get(place_id);
|
||||
if (!newPlaceId) continue;
|
||||
// A tour planned from an import points at the copied import, never back into the source trip.
|
||||
const derivedFrom =
|
||||
tour.derived_from_place_id === null ? null : (placeMap.get(tour.derived_from_place_id) ?? null);
|
||||
await this.toursRepo.insertCopy(newPlaceId, { ...tour, derived_from_place_id: derivedFrom });
|
||||
await this.toursRepo.insertCopy(newPlaceId, tour, placeMap);
|
||||
copiedTours.add(place_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ describe('GET /api/addons e2e (real auth guard + temp SQLite)', () => {
|
||||
expect(res.body).toEqual({
|
||||
collabFeatures: { chat: true, notes: true, links: true, polls: true, whatsnext: true },
|
||||
bagTracking: true,
|
||||
// Tours is off in this database, so wanderer is not offered either.
|
||||
toursWanderer: false,
|
||||
addons: [
|
||||
{ id: 'packing', name: 'Packing', type: 'trip', icon: 'Backpack', enabled: true },
|
||||
{ id: 'journey', name: 'Journey', type: 'global', icon: 'Compass', enabled: true },
|
||||
|
||||
@@ -89,6 +89,8 @@ describe('ToursRepository reads', () => {
|
||||
max_hiking_difficulty: 5,
|
||||
planned: 0,
|
||||
has_waypoints: 1,
|
||||
derived_from_place_id: null,
|
||||
has_recorded_track: 0,
|
||||
},
|
||||
{
|
||||
place_id: older.id,
|
||||
@@ -108,6 +110,8 @@ describe('ToursRepository reads', () => {
|
||||
max_hiking_difficulty: 2,
|
||||
planned: 1,
|
||||
has_waypoints: 0,
|
||||
derived_from_place_id: null,
|
||||
has_recorded_track: 0,
|
||||
},
|
||||
]);
|
||||
expect((await repo.listForTrip(trip.id)).map((r) => r.place_id)).not.toContain(plain.id);
|
||||
@@ -183,6 +187,8 @@ describe('ToursRepository writes', () => {
|
||||
wanderer_ref: null,
|
||||
planned: 0,
|
||||
has_waypoints: 0,
|
||||
derived_from_place_id: null,
|
||||
has_recorded_track: 0,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -241,13 +247,34 @@ describe('ToursRepository writes', () => {
|
||||
match_confidence: null,
|
||||
created_at: '2026-03-04 05:06:07',
|
||||
max_hiking_difficulty: 4,
|
||||
derived_from_place_id: null,
|
||||
recorded_route_geometry: null,
|
||||
},
|
||||
]);
|
||||
expect(await repo.listRowsForTrip(other.id)).toEqual([]);
|
||||
|
||||
const copy = createPlace(testDb, other.id);
|
||||
const { place_id: _sourceId, ...columns } = rows[0];
|
||||
await repo.insertCopy(copy.id, columns);
|
||||
await repo.insertCopy(copy.id, columns, new Map());
|
||||
expect(await repo.listRowsForTrip(other.id)).toEqual([{ ...rows[0], place_id: copy.id }]);
|
||||
});
|
||||
|
||||
it('TOURREPO-009: insertCopy points a planned tour at the copied import, and drops a link the copy has no import for', async () => {
|
||||
const { trip, other } = fixture();
|
||||
const sourceImport = createPlace(testDb, trip.id);
|
||||
const planned = createPlace(testDb, trip.id);
|
||||
createTour(testDb, planned.id);
|
||||
const [row] = await repo.listRowsForTrip(trip.id);
|
||||
const { place_id: _sourceId, ...columns } = { ...row, derived_from_place_id: sourceImport.id };
|
||||
const copiedImport = createPlace(testDb, other.id);
|
||||
const copy = createPlace(testDb, other.id);
|
||||
const orphan = createPlace(testDb, other.id);
|
||||
|
||||
await repo.insertCopy(copy.id, columns, new Map([[sourceImport.id, copiedImport.id]]));
|
||||
await repo.insertCopy(orphan.id, columns, new Map());
|
||||
|
||||
const copied = await repo.listRowsForTrip(other.id);
|
||||
expect(copied.find((r) => r.place_id === copy.id)?.derived_from_place_id).toBe(copiedImport.id);
|
||||
expect(copied.find((r) => r.place_id === orphan.id)?.derived_from_place_id).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -261,6 +261,7 @@ function tourRepositoryFixture(ownerTripId: number) {
|
||||
tripId === ownerTripId && placeId === 42 ? row : undefined,
|
||||
),
|
||||
updateInTrip: vi.fn(async () => true),
|
||||
keepRecordedTrack: vi.fn(async () => undefined),
|
||||
};
|
||||
const waypointsRepo = {
|
||||
listForPlace: vi.fn(async () => input.waypoints),
|
||||
|
||||
@@ -89,6 +89,7 @@ function makeService() {
|
||||
findInTrip: vi.fn(async (): Promise<typeof row | undefined> => row),
|
||||
insertTour: inTx(undefined),
|
||||
updateInTrip: inTx(true),
|
||||
keepRecordedTrack: inTx(undefined),
|
||||
};
|
||||
const waypointsRepo = {
|
||||
listForPlace: vi.fn(async () => request.waypoints),
|
||||
@@ -147,6 +148,7 @@ describe('ToursService planner contracts (mock-only; SQLite rollback semantics a
|
||||
expect(setup.toursRepo.insertTour).toHaveBeenCalledExactlyOnceWith({
|
||||
place_id: 42,
|
||||
tour_type: 'hike',
|
||||
derived_from_place_id: null,
|
||||
distance: expect.any(Number),
|
||||
elevation_gain: 50,
|
||||
elevation_loss: 20,
|
||||
|
||||
Reference in New Issue
Block a user