diff --git a/src/models/common/decorators/wfs/wfs.decorator.ts b/src/models/common/decorators/wfs/wfs.decorator.ts new file mode 100644 index 0000000..a1e299b --- /dev/null +++ b/src/models/common/decorators/wfs/wfs.decorator.ts @@ -0,0 +1,36 @@ +import 'reflect-metadata'; + +const wfsMetadataKey = Symbol('wfsmapping'); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export enum JAVA_BINDINGS { + UUID = 'java.util.UUID', + STRING = 'java.lang.String', + TIMESTAMP = 'java.sql.Timestamp', + FLOAT = 'java.lang.Float', + BIGDECIMAL = 'java.math.BigDecimal', + POLYGON = 'org.locationtech.jts.geom.Polygon', +} + +export interface IWFSMapping { + binding: JAVA_BINDINGS; // java type 'java.util.UUID' + name?: string; // property name that will be exposed by WFS service + minOccurs?: number; + maxOccurs?: number; +} + +export interface IPropWFSMapping extends IWFSMapping { + prop: string; // prop name for convinience + source: string; // DB column name. IMPORTANT: Will be derived from catalogDB decorator metadata + nillable: boolean; // is nullable by DB definitions +} + +export function wfs(wfsmapping?: IWFSMapping): PropertyDecorator { + return Reflect.metadata(wfsMetadataKey, wfsmapping); +} + +export function getWFSMapping(target: T, propertyKey: string): IWFSMapping | undefined { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + return Reflect.getMetadata(wfsMetadataKey, target, propertyKey) as IWFSMapping; +} diff --git a/src/models/common/index.ts b/src/models/common/index.ts index 2388405..9b37261 100644 --- a/src/models/common/index.ts +++ b/src/models/common/index.ts @@ -5,3 +5,4 @@ export * from './interfaces/ormCatalog.interface'; export * from './interfaces/propCatalogDBMapping.interface'; export * from './interfaces/propGraphQLMapping.interface'; export * from './decorators/fieldConfig/fieldConfig.decorator'; +export * from './decorators/wfs/wfs.decorator'; diff --git a/src/models/polygonParts/polygonPartRecord.ts b/src/models/polygonParts/polygonPartRecord.ts index b5aaf65..7da7c65 100644 --- a/src/models/polygonParts/polygonPartRecord.ts +++ b/src/models/polygonParts/polygonPartRecord.ts @@ -6,15 +6,23 @@ import { DataFileType, IPropSHPMapping, getInputDataMapping, inputDataMapping } import { catalogDB, getCatalogDBMapping } from '../layerMetadata/decorators/property/catalogDB.decorator'; import { getTsTypesMapping, tsTypes, TsTypes } from '../layerMetadata/decorators/property/tsTypes.decorator'; import { ICatalogDBEntityMapping, IOrmCatalog, IPYCSWMapping, ProductType } from '../layerMetadata'; -import { graphqlClass, IPropCatalogDBMapping } from '../common'; -import { getCatalogDBEntityMapping } from '../layerMetadata/decorators/class/catalogDBEntity.decorator'; +import { getWFSMapping, graphqlClass, IPropCatalogDBMapping, IPropWFSMapping, JAVA_BINDINGS, wfs } from '../common'; +import { catalogDBEntity, getCatalogDBEntityMapping } from '../layerMetadata/decorators/class/catalogDBEntity.decorator'; import { VALIDATIONS } from '../raster/constants'; interface IPropPYCSWMapping extends IPYCSWMapping { prop: string; } -@graphqlClass({ alias: 'PolygonPartRecord', fields: keys() }) +const POLYGON_PARTS_KEYS = keys(); +const POLYGON_PARTS_SERVED_KEYS = + keys>(); + +@catalogDBEntity({ + table: 'PPRecordsPartial', + className: 'PolygonPartRecord', +}) +@graphqlClass({ alias: 'PolygonPartRecord', fields: POLYGON_PARTS_KEYS }) export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { //#region METADATA: sourceId @catalogDB({ @@ -24,6 +32,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: true, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ dataFile: DataFileType.SHAPE_METADATA, valuePath: 'properties.Source', @@ -46,6 +57,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ dataFile: DataFileType.SHAPE_METADATA, valuePath: 'properties.SourceName', @@ -68,6 +82,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ dataFile: DataFileType.SHAPE_METADATA, valuePath: 'properties.SourceName', @@ -78,6 +95,7 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { @graphql() @fieldConfig({ category: FieldCategory.MAIN, + isAutoGenerated: true, infoMsgCode: ['info-field-tooltip.productId.pattern'], validation: [ { @@ -98,16 +116,15 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) - @inputDataMapping({ - dataFile: DataFileType.SHAPE_METADATA, - valuePath: 'properties.SourceName', + @wfs({ + binding: JAVA_BINDINGS.STRING, }) @tsTypes({ mappingType: TsTypes.PRODUCTTYPE, }) - @graphql() @fieldConfig({ category: FieldCategory.MAIN, + isAutoGenerated: true, }) //#endregion public productType!: ProductType; @@ -120,6 +137,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: true, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ dataFile: DataFileType.SHAPE_METADATA, valuePath: 'properties.Dsc', @@ -144,6 +164,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.TIMESTAMP, + }) @inputDataMapping({ isCustomLogic: false, dataFile: DataFileType.SHAPE_METADATA, @@ -167,7 +190,6 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { max: 'imagingTimeEndUTC', }, ], - isLifecycleEnvolved: true, }) //#endregion public imagingTimeBeginUTC!: Date; @@ -180,6 +202,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.TIMESTAMP, + }) @inputDataMapping({ isCustomLogic: false, dataFile: DataFileType.SHAPE_METADATA, @@ -198,7 +223,6 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { required: true, }, ], - isLifecycleEnvolved: true, }) //#endregion public imagingTimeEndUTC!: Date; @@ -210,6 +234,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { type: 'real', }, }) + @wfs({ + binding: JAVA_BINDINGS.FLOAT, + }) @inputDataMapping({ dataFile: DataFileType.SHAPE_METADATA, valuePath: 'properties.Ep90', @@ -237,7 +264,6 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { max: VALIDATIONS.horizontalAccuracyCE90.max, }, ], - isLifecycleEnvolved: true, }) //#endregion public horizontalAccuracyCE90!: number; @@ -253,6 +279,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { overrideType: TsTypes.STRING, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ isCustomLogic: false, dataFile: DataFileType.SHAPE_METADATA, @@ -264,7 +293,6 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { @graphql() @fieldConfig({ category: FieldCategory.GENERAL, - isLifecycleEnvolved: true, infoMsgCode: ['info-field-tooltip.sensors.tooltip', 'info-general-tooltip.required'], validation: [ { @@ -287,6 +315,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { overrideType: TsTypes.STRING, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ isCustomLogic: false, dataFile: DataFileType.SHAPE_METADATA, @@ -316,6 +347,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { overrideType: TsTypes.STRING, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @inputDataMapping({ isCustomLogic: false, dataFile: DataFileType.SHAPE_METADATA, @@ -340,6 +374,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { type: 'numeric', }, }) + @wfs({ + binding: JAVA_BINDINGS.BIGDECIMAL, + }) @tsTypes({ mappingType: TsTypes.NUMBER, }) @@ -376,6 +413,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { type: 'numeric', }, }) + @wfs({ + binding: JAVA_BINDINGS.BIGDECIMAL, + }) @tsTypes({ mappingType: TsTypes.NUMBER, }) @@ -407,6 +447,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { type: 'numeric', }, }) + @wfs({ + binding: JAVA_BINDINGS.BIGDECIMAL, + }) @tsTypes({ mappingType: TsTypes.NUMBER, }) @@ -435,9 +478,12 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { type: 'text', }, }) + @wfs({ + binding: JAVA_BINDINGS.POLYGON, + }) @inputDataMapping({ dataFile: DataFileType.PRODUCT, - valuePath: 'footprint', + valuePath: 'geometry', }) @tsTypes({ mappingType: TsTypes.OBJECT, @@ -469,16 +515,17 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { primary: true, }, }) + @wfs({ + binding: JAVA_BINDINGS.UUID, + }) @tsTypes({ mappingType: TsTypes.STRING, }) - @graphql() @fieldConfig({ category: FieldCategory.MAIN, isAutoGenerated: true, }) //#endregion - // eslint-disable-next-line @typescript-eslint/naming-convention public id!: string; //#region RECORD: partId @@ -489,6 +536,9 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.UUID, + }) @tsTypes({ mappingType: TsTypes.STRING, }) @@ -508,10 +558,12 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.UUID, + }) @tsTypes({ mappingType: TsTypes.STRING, }) - @graphql() @fieldConfig({ category: FieldCategory.MAIN, isAutoGenerated: true, @@ -527,12 +579,12 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.STRING, + }) @tsTypes({ mappingType: TsTypes.STRING, }) - @graphql({ - nullable: false, - }) @fieldConfig({ category: FieldCategory.MAIN, infoMsgCode: ['info-field-tooltip.productVersion.pattern'], @@ -556,10 +608,12 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { nullable: false, }, }) + @wfs({ + binding: JAVA_BINDINGS.TIMESTAMP, + }) @tsTypes({ mappingType: TsTypes.DATE, }) - @graphql() @fieldConfig({ category: FieldCategory.MAIN, isAutoGenerated: true, @@ -571,10 +625,30 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { return []; } + public static getWFSMappings(): IPropWFSMapping[] { + const ret: IPropWFSMapping[] = []; + const layer = new PolygonPartRecord(); + POLYGON_PARTS_SERVED_KEYS.forEach((prop) => { + const catalogDbMap = getCatalogDBMapping(layer, prop); + const wfsMap = getWFSMapping(layer, prop); + if (catalogDbMap && wfsMap) { + const { name, ...rest } = wfsMap; + ret.push({ + prop: prop, + name: name ?? prop, + source: catalogDbMap.column.name as string, + nillable: catalogDbMap.column.nullable ?? false, + ...rest, + }); + } + }); + return ret; + } + public static getShpMappings(includeCustomLogic = false): IPropSHPMapping[] { - const ret = []; + const ret: IPropSHPMapping[] = []; const layer = new PolygonPartRecord(); - for (const prop in layer) { + POLYGON_PARTS_SERVED_KEYS.forEach((prop) => { const shpMap = getInputDataMapping(layer, prop); const tsTypesMap = getTsTypesMapping(layer, prop); if (shpMap && tsTypesMap && (includeCustomLogic || shpMap.isCustomLogic === undefined || !shpMap.isCustomLogic)) { @@ -584,14 +658,14 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { ...tsTypesMap, }); } - } + }); return ret; } public static getFieldConfigs(): IPropFieldConfigInfo[] { - const ret = []; + const ret: IPropFieldConfigInfo[] = []; const layer = new PolygonPartRecord(); - for (const prop in layer) { + POLYGON_PARTS_SERVED_KEYS.forEach((prop) => { const fieldConfigMap = getFieldConfig(layer, prop); if (fieldConfigMap) { ret.push({ @@ -599,16 +673,17 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { ...fieldConfigMap, }); } - } + }); return ret; } public getORMCatalogMappings(): IPropCatalogDBMapping[] { - const ret = []; + const ret: IPropCatalogDBMapping[] = []; - for (const prop in this) { - const catalogDbMap = getCatalogDBMapping(this, prop); - const tsTypesMap = getTsTypesMapping(this, prop); + const layer = new PolygonPartRecord(); + POLYGON_PARTS_KEYS.forEach((prop) => { + const catalogDbMap = getCatalogDBMapping(layer, prop); + const tsTypesMap = getTsTypesMapping(layer, prop); if (catalogDbMap && tsTypesMap) { ret.push({ prop: prop, @@ -616,7 +691,7 @@ export class PolygonPartRecord implements IPolygonPart, IOrmCatalog { ...tsTypesMap, }); } - } + }); return ret; } diff --git a/tests/unit/polygonParts.spec.ts b/tests/unit/polygonParts.spec.ts index cf4fe4a..1853807 100644 --- a/tests/unit/polygonParts.spec.ts +++ b/tests/unit/polygonParts.spec.ts @@ -12,4 +12,22 @@ describe('PolygonParts class static methods', () => { expect(ppGQLMappings?.fields.length).toBeGreaterThan(0); }); + + it('getWFSMappings(): class property members HAS WFS mapped fields', () => { + const ppWFSMappings = PolygonPartRecord.getWFSMappings(); + + expect(ppWFSMappings.length).toBeGreaterThan(0); + }); + + it('getORMCatalogEntityMappings(): class HAS ORM entity mapping', () => { + const ppORMEntityMapping = new PolygonPartRecord().getORMCatalogEntityMappings(); + + expect(ppORMEntityMapping).toBeDefined(); + }); + + it('getORMCatalogMappings(): class property members HAS ORM mapped fields', () => { + const ppORMEntityFieldsMapping = new PolygonPartRecord().getORMCatalogMappings(); + + expect(ppORMEntityFieldsMapping.length).toBeGreaterThan(0); + }); });