Skip to content

Commit

Permalink
Merge pull request #107 from Dataport/refactor/#33-lib-get-features
Browse files Browse the repository at this point in the history
Refactor/#33 lib get features
  • Loading branch information
dopenguin authored Feb 28, 2024
2 parents 86b1667 + b7a8fde commit c0f41ac
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 51 deletions.
5 changes: 5 additions & 0 deletions packages/clients/dish/src/utils/navigateToDenkmal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export function navigateToDenkmal(instance, objektId: string) {
if (!wfsConfig) {
throw new Error('Client is missing wfsConfig on DISH search method.')
}
if (!wfsConfig.queryParameters) {
throw new Error(
'Client is missing wfsConfig.queryParameters on DISH search method.'
)
}

getWfsFeatures(null, denkmaelerWfsService.url, objektId, {
...wfsConfig.queryParameters.wfsConfiguration,
Expand Down
4 changes: 4 additions & 0 deletions packages/lib/getFeatures/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## unpublished

- Breaking: `getWfsFeatures` now throws errors if required parameters on the wfs configuration are missing instead of only printing error messages on the console.

## 1.0.1

- Fix: Increase type precision of EPSG codes from `string` to `EPSG:${string}`.
Expand Down
1 change: 0 additions & 1 deletion packages/lib/getFeatures/gazetteer/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export function parseGazetteerResponse(
const gmlFeatures = new DOMParser()
.parseFromString(text, 'application/xml')
.getElementsByTagName(`wfs:${memberSuffix}`)
// @ts-expect-error | This is needed as this already is a workaround because the GeoJSON reader can't read the XMLResponse from a WFS-G
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features,
Expand Down
14 changes: 14 additions & 0 deletions packages/lib/getFeatures/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ export interface AdditionalSearchOptions {
typeNames?: string | string[]
}

/*
* Explanation by dimension:
* First: each child resembles a query
* Second: children will be ANDed on multiple children
* Third: [key, value] where key is a property name
* Explanation by example:
* [[['a', 'b'], ['a', 'c']], [['a', 'b']]]
* becomes
* QUERY(a=b && c=d), QUERY(a=b)
* where the second query is only executed if the first doesn't fill
* maxFeatures to its limit.
*/
export type KeyValueSetArray = Array<Array<[string, string]>>

/** Adds the possibility to have a 'title' attribute in a GeoJSON Feature */
export interface PolarGeoJsonFeature extends GeoJsonFeature {
/** The projection of the coordinates of the features */
Expand Down
15 changes: 2 additions & 13 deletions packages/lib/getFeatures/wfs/buildWfsFilter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { WfsParameters } from '../types'
import { KeyValueSetArray, WfsParameters } from '../types'

const removeLinebreaks = (s) => s.replace(/\r?\n|\r/g, '')

Expand Down Expand Up @@ -58,21 +58,10 @@ const buildWfsFilterQuery = (
* Builds filter of multiple queries from possible interpretations of inputs.
* Multiple queries are sent so that service may stop computing after
* maxFeatures has been fulfilled.
* @param inputs - Explanation by dimension.
* First: each child resembles a query
* Second: children will be ANDed on multiple children
* Third: [key, value] where key is a property name
* Explanation by example.
* [[['a', 'b'], ['a', 'c']], [['a', 'b']]]
* becomes
* QUERY(a=b && c=d), QUERY(a=b)
* where the second query is only executed if the first doesn't fill
* maxFeatures to its limit.
* @param parameters - @see WfsParameters
* @returns request xml
*/
export const buildWfsFilter = (
inputs: Array<Array<[string, string]>>,
inputs: KeyValueSetArray,
parameters: WfsParameters
) =>
removeLinebreaks(
Expand Down
4 changes: 2 additions & 2 deletions packages/lib/getFeatures/wfs/getFeatureTitleFromPattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export const getFeatureTitleFromPattern = (
const keys = blocks.reduce(
(keyAccumulator, block) =>
Array.isArray(block) ? [...keyAccumulator, block[1]] : keyAccumulator,
[]
) as string[]
[] as string[]
)
const foundKeys = keys.reduce(
(sum, key) =>
typeof properties[key] !== 'undefined' && properties[key] !== ''
Expand Down
35 changes: 14 additions & 21 deletions packages/lib/getFeatures/wfs/index.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
import { WfsParameters } from '../types'
import { KeyValueSetArray, WfsParameters } from '../types'
import { errorCheck } from '../utils/errorCheck'
import { parseWfsResponse } from './parse'
import { buildWfsFilter } from './buildWfsFilter'
import { match } from './match'

export function getWfsFeatures(
export async function getWfsFeatures(
signal: AbortSignal | null,
url: string,
inputValue: string,
parameters: WfsParameters
) {
const { fieldName, patterns, patternKeys } = parameters
// arrays OF sets OF key-value-pairs
let inputs: string[][][] = [[[]]]

if (fieldName && patterns) {
console.error(
'@polar/lib-get-features: Using both fieldName and patterns for WFS search. These are mutually exclusive. Patterns will be ignored.'
if (!fieldName && (!patterns || !patternKeys)) {
throw new Error(
'Incomplete WFS search configuration. Either "fieldName" or "patterns" and "patternKeys" are required.'
)
}

if (fieldName) {
inputs = [[[fieldName, inputValue]]]
} else if (patterns && patternKeys) {
inputs = match(patterns, patternKeys, inputValue)
} else {
if (fieldName && patterns) {
console.error(
'@polar/lib-get-features: Incomplete WFS search configuration. Either "fieldName" or "patterns" and "patternKeys" are required.'
'@polar/lib-get-features: Using both fieldName and patterns for WFS search. These are mutually exclusive. Patterns will be ignored.'
)
}
// arrays of sets of key-value-pairs
const inputs: KeyValueSetArray = fieldName
? [[[fieldName, inputValue]]]
: match(patterns, patternKeys, inputValue)

const body = buildWfsFilter(inputs, parameters)

return fetch(encodeURI(url), { signal, method: 'POST', body }).then(
(response: Response) => {
errorCheck(response)
return parseWfsResponse(response, fieldName || patterns, !fieldName)
}
)
const response = await fetch(encodeURI(url), { signal, method: 'POST', body })
errorCheck(response)
return parseWfsResponse(response, fieldName || patterns, !fieldName)
}
35 changes: 21 additions & 14 deletions packages/lib/getFeatures/wfs/match.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// code doesn't produce RegExpMatchArray where index is not set ... :|
/* eslint-disable @typescript-eslint/no-non-null-assertion */

import { KeyValueSetArray } from '../types'

export type Separator = string
export type Slot = RegExpMatchArray
export type Block = Slot | Separator
Expand Down Expand Up @@ -55,10 +57,10 @@ const sortComparableMatches = (comparableA, comparableB) => {
* 2. pattern fulfillment
*/
const sortMatches = (
matches: string[][][],
matches: KeyValueSetArray,
patterns: string[],
uninterpretedCharacters: number[]
): string[][][] => {
): KeyValueSetArray => {
const comparableMatches = matches.map((match, index) => ({
match,
uninterpreted: uninterpretedCharacters[index],
Expand All @@ -72,7 +74,7 @@ const sortMatches = (

// remove duplicates and empty matches
const known: string[] = []
const sortedFilteredMatches = sortedMatches.filter((match) => {
return sortedMatches.filter((match) => {
if (match.length === 0) {
return false
}
Expand All @@ -83,23 +85,31 @@ const sortMatches = (
known.push(asString)
return true
})

return sortedFilteredMatches
}

/**
* matches an input string to patterns
*/
export const match = (
patterns: string[],
patternKeys: Record<string, string>,
patterns: string[] | undefined,
patternKeys: Record<string, string> | undefined,
inputValue: string
): string[][][] => {
const matches: string[][][] = []
): KeyValueSetArray => {
if (!patterns) {
throw new Error(
'@polar/lib-get-features: Parameter "patterns" is missing on wfs configuration for pattern-based search.'
)
}
if (!patternKeys) {
throw new Error(
'@polar/lib-get-features: Parameter "patternKeys" is missing on wfs configuration for pattern-based search.'
)
}
const matches: KeyValueSetArray = []
const uninterpretedCharacters: number[] = []
patterns.forEach((pattern) => {
const patternBlocks = getBlocks(pattern)
const patternMapping: string[][] = []
const patternMapping: KeyValueSetArray[number] = []
let traverseInput = inputValue

patternBlocks.forEach((block) => {
Expand All @@ -126,8 +136,5 @@ export const match = (
uninterpretedCharacters.push(traverseInput.length)
matches.push(patternMapping)
})

const sortedMatches = sortMatches(matches, patterns, uninterpretedCharacters)

return sortedMatches
return sortMatches(matches, patterns, uninterpretedCharacters)
}

0 comments on commit c0f41ac

Please sign in to comment.