Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 99 additions & 2 deletions packages/cli-config/src/__tests__/config.diff.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import assert from 'node:assert';
import { before, beforeEach, describe, it, TestContext } from 'node:test';

import { ConfigLayer, ConfigProviderMemory, ConfigTileSetRaster, getAllImagery, sha256base58 } from '@basemaps/config';
import {
ConfigLayer,
ConfigProviderMemory,
ConfigTileSetRaster,
ConfigTileSetVector,
getAllImagery,
sha256base58,
} from '@basemaps/config';
import { ConfigJson } from '@basemaps/config-loader';
import { ConfigImageryTiff } from '@basemaps/config-loader/build/json/tiff.config.js';
import { TileSetConfigSchema, TileSetConfigSchemaLayer } from '@basemaps/config-loader/src/json/parse.tile.set.js';
import { Epsg, EpsgCode, TileMatrixSet, TileMatrixSets } from '@basemaps/geo';
import { fsa, FsMemory, LogConfig } from '@basemaps/shared';
import pLimit from 'p-limit';

import { diffVectorUpdate } from '../cli/config.diff.js';
import {
configTileSetDiff,
DiffNew,
Expand All @@ -17,7 +25,7 @@ import {
DiffTileSetUpdated,
} from '../cli/diff/config.diff.js';
import { diffToMarkdown } from '../cli/diff/config.diff.markdown.js';
import { TsAerial, TsElevation, TsIndividual } from './config.diff.data.js';
import { TsAerial, TsElevation, TsIndividual, TsVector } from './config.diff.data.js';

function splitUrlIntoParts(e: URL): { tileMatrix: TileMatrixSet; name: string; gsd: number } {
const parts = e.pathname.slice(1).split('/');
Expand Down Expand Up @@ -459,6 +467,95 @@ describe('config.diff', () => {
await dumpState(t.fullName, diff);
});
});

describe('vector', () => {
const exampleLink = {
rel: 'lds:layer',
'lds:id': '123113',
'lds:name': '123113-nz-addresses',
'lds:title': 'NZ Addresses',
'lds:version': 436630,
'basemaps:layers': ['addresses'],
href: 'https://data.linz.govt.nz/services/api/v1/layers/123113/versions/436630/',
'lds:feature_count': 2410159,
};

async function basicSetup(t: TestContext): Promise<{ before: ConfigTileSetVector; after: ConfigTileSetVector }> {
const vectorBefore = structuredClone(TsVector);
delete vectorBefore.layers[0]['2193'];
vectorBefore.layers[0]['3857'] = 'before://data/topographic-v2/';

const vectorAfter = structuredClone(vectorBefore);
vectorAfter.layers[0]['3857'] = 'after://data/topographic-v2/';

await fsa.write(fsa.toUrl('before://config/tileset/topographic.json'), JSON.stringify(vectorBefore));
const before = await stubLoadConfig(t, 'before://config/');

await fsa.write(fsa.toUrl('after://config/tileset/topographic.json'), JSON.stringify(vectorAfter));

const after = await stubLoadConfig(t, 'after://config/');

return {
before: after.objects.get('ts_topographic-v2') as ConfigTileSetVector,
after: before.objects.get('ts_topographic-v2') as ConfigTileSetVector,
};
}

async function writeJson(url: string, data: unknown): Promise<void> {
await fsa.write(fsa.toUrl(url), JSON.stringify(data));
}

it('should show diff when a layer is deleted', async (t) => {
const { before, after } = await basicSetup(t);
await writeJson('before://data/topographic-v2/collection.json', { links: [exampleLink] });
await writeJson('after://data/topographic-v2/collection.json', { links: [] });

const diff = await diffVectorUpdate(before, after);

// Layer deleted
assert.deepEqual(diff, ['🟥 123113-nz-addresses features: -2,410,159']);
});

it('should show diff when a layer is added', async (t) => {
const { before, after } = await basicSetup(t);
await writeJson('before://data/topographic-v2/collection.json', { links: [] });
await writeJson('after://data/topographic-v2/collection.json', { links: [exampleLink] });

const diff = await diffVectorUpdate(before, after);

// Layer deleted
assert.deepEqual(diff, ['🟩 123113-nz-addresses - version: 436,630 features: 2,410,159']);
});

it('should show diff when a layer is modified', async (t) => {
const { before, after } = await basicSetup(t);
await writeJson('before://data/topographic-v2/collection.json', { links: [exampleLink] });
const afterLink = structuredClone(exampleLink);
afterLink['lds:feature_count']--;
afterLink['lds:version']++;
await writeJson('after://data/topographic-v2/collection.json', { links: [afterLink] });
const diffDown = await diffVectorUpdate(before, after);

// Layer deleted
assert.deepEqual(diffDown, [
'🟧 123113-nz-addresses - version: 436,631 (from: 436,630) features: 2,410,158 (-1)',
]);

afterLink['lds:feature_count'] += 2;
await writeJson('after://data/topographic-v2/collection.json', { links: [afterLink] });

const diffUp = await diffVectorUpdate(before, after);
assert.deepEqual(diffUp, ['🟦 123113-nz-addresses - version: 436,631 (from: 436,630) features: 2,410,160 (+1)']);

afterLink['lds:version']--;
await writeJson('after://data/topographic-v2/collection.json', { links: [afterLink] });

const diffVersion = await diffVectorUpdate(before, after);
assert.deepEqual(diffVersion, [
'🟥🟥🟥🟥 Feature Change Detected 123113-nz-addresses - version: 436,630 features: 2,410,160 (+1) 🟥🟥🟥🟥',
]);
});
});
});

function fakeLayerConfig(name: string, title: string): ConfigLayer {
Expand Down
18 changes: 12 additions & 6 deletions packages/cli-config/src/cli/config.diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ export class ConfigDiff {
}
}

const formatter = new Intl.NumberFormat('en-NZ', {});

function formatNumber(obj: StacLinkLds, key: keyof StacLinkLds): string {
return `${formatter.format(obj[key] as number)}`;
}

/**
* Given a old and new lds layer stac item and log the changes
*/
Expand All @@ -75,28 +81,28 @@ export function getVectorChanges(
if (newLayer['lds:version'] === existingLayer['lds:version']) {
// Alert if feature changed with no version bump.
if (featureChange !== 0) {
return `🟥🟥🟥🟥 Feature Change Detected ${newLayer['lds:name']} - version: ${newLayer['lds:version']} features: ${newLayer['lds:feature_count']} (+${featureChange}) 🟥🟥🟥🟥`;
return `🟥🟥🟥🟥 Feature Change Detected ${newLayer['lds:name']} - version: ${formatNumber(newLayer, 'lds:version')} features: ${formatNumber(newLayer, 'lds:feature_count')} (+${featureChange}) 🟥🟥🟥🟥`;
}
return null;
}

if (featureChange >= 0) {
// Add Features
return `🟦 ${newLayer['lds:name']} - version: ${newLayer['lds:version']} (from: ${existingLayer['lds:version']}) features: ${newLayer['lds:feature_count']} (+${featureChange})`;
return `🟦 ${newLayer['lds:name']} - version: ${formatNumber(newLayer, 'lds:version')} (from: ${formatNumber(existingLayer, 'lds:version')}) features: ${formatNumber(newLayer, 'lds:feature_count')} (+${featureChange})`;
} else {
// Remove Features
return `🟧 ${newLayer['lds:name']} - version: ${newLayer['lds:version']} (from: ${existingLayer['lds:version']}) features: ${newLayer['lds:feature_count']} (-${featureChange})`;
return `🟧 ${newLayer['lds:name']} - version: ${formatNumber(newLayer, 'lds:version')} (from: ${formatNumber(existingLayer, 'lds:version')}) features: ${formatNumber(newLayer, 'lds:feature_count')} (${featureChange})`;
}
}

// Add new Layer
if (newLayer != null && existingLayer == null) {
return `🟩 ${newLayer['lds:name']} - version: ${newLayer['lds:version']} features: ${newLayer['lds:feature_count']}`;
return `🟩 ${newLayer['lds:name']} - version: ${formatNumber(newLayer, 'lds:version')} features: ${formatNumber(newLayer, 'lds:feature_count')}`;
}

// Remove Layer
if (newLayer == null && existingLayer != null) {
return `🟥 ${existingLayer['lds:name']} features: -${existingLayer['lds:feature_count']}`;
return `🟥 ${existingLayer['lds:name']} features: -${formatNumber(existingLayer, 'lds:feature_count')}`;
}

// No changes detected return null
Expand Down Expand Up @@ -154,7 +160,7 @@ export async function diffVectorUpdate(

// Remove the layers that not deleted from existingLdsLayers
for (const l of existingLdsLayers.values()) {
const change = getVectorChanges(l, undefined);
const change = getVectorChanges(undefined, l);
if (change != null) changes.push(change);
}
}
Expand Down
Loading