property mapping validation #48
This commit is contained in:
parent
3e79f8ad77
commit
68ec5135cc
6 changed files with 146 additions and 23 deletions
|
|
@ -507,15 +507,15 @@ export default class MediaDbPlugin extends Plugin {
|
|||
for (const defaultProperty of defaultPropertyMappingModel.properties) {
|
||||
let newProperty = newPropertyMappingModel.properties.find(x => x.property === defaultProperty.property);
|
||||
if (newProperty === undefined) {
|
||||
// default property is an instance
|
||||
newProperties.push(defaultProperty);
|
||||
} else {
|
||||
newProperties.push(newProperty);
|
||||
// newProperty is just an object and take locked status from default property
|
||||
newProperties.push(new PropertyMapping(newProperty.property, newProperty.newProperty, newProperty.mapping, defaultProperty.locked));
|
||||
}
|
||||
}
|
||||
|
||||
newPropertyMappingModel.properties = newProperties;
|
||||
|
||||
newPropertyMappings.push(newPropertyMappingModel);
|
||||
newPropertyMappings.push(new PropertyMappingModel(newPropertyMappingModel.type, newProperties));
|
||||
}
|
||||
}
|
||||
loadedSettings.propertyMappingModels = newPropertyMappings;
|
||||
|
|
|
|||
|
|
@ -16,15 +16,23 @@ export class PropertyMapper {
|
|||
* @param obj
|
||||
*/
|
||||
convertObject(obj: object): object {
|
||||
console.log('test1');
|
||||
|
||||
if (!obj.hasOwnProperty('type')) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
console.log('test2');
|
||||
// @ts-ignore
|
||||
if (MEDIA_TYPES.contains(obj.type)) {
|
||||
console.log(obj.type);
|
||||
|
||||
// @ts-ignore
|
||||
if (MEDIA_TYPES.filter(x => x.toString() == obj.type).length < 1) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
console.log('test3');
|
||||
|
||||
// @ts-ignore
|
||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {containsOnlyLettersAndUnderscores} from '../utils/Utils';
|
||||
import {containsOnlyLettersAndUnderscores, PropertyMappingNameConflictError, PropertyMappingValidationError} from '../utils/Utils';
|
||||
import {MediaType} from '../utils/MediaType';
|
||||
|
||||
export enum PropertyMappingOption {
|
||||
|
|
@ -9,9 +9,73 @@ export enum PropertyMappingOption {
|
|||
|
||||
export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove];
|
||||
|
||||
export interface PropertyMappingModel {
|
||||
type: MediaType,
|
||||
properties: PropertyMapping[],
|
||||
export class PropertyMappingModel {
|
||||
type: MediaType;
|
||||
properties: PropertyMapping[];
|
||||
|
||||
constructor(type: MediaType, properties?: PropertyMapping[]) {
|
||||
this.type = type;
|
||||
this.properties = properties ?? [];
|
||||
}
|
||||
|
||||
validate(): { res: boolean, err?: Error } {
|
||||
// check properties
|
||||
for (const property of this.properties) {
|
||||
const propertyValidation = property.validate();
|
||||
if (!propertyValidation.res) {
|
||||
return {
|
||||
res: false,
|
||||
err: propertyValidation.err,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// check for name collisions
|
||||
for (const property of this.getMappedProperties()) {
|
||||
const propertiesWithSameTarget = this.getMappedProperties().filter(x => x.newProperty === property.newProperty);
|
||||
if (propertiesWithSameTarget.length === 0) {
|
||||
// if we get there, then something in this code is wrong
|
||||
} else if (propertiesWithSameTarget.length === 1) {
|
||||
// all good
|
||||
} else {
|
||||
// two or more properties are mapped to the same property
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingNameConflictError(`Multiple remapped properties (${propertiesWithSameTarget.map(x => x.toString()).toString()}) may not share the same name.`),
|
||||
};
|
||||
}
|
||||
}
|
||||
// remapped properties may not have the same name as any original property
|
||||
for (const property of this.getMappedProperties()) {
|
||||
const propertiesWithSameTarget = this.properties.filter(x => x.newProperty === property.property);
|
||||
if (propertiesWithSameTarget.length === 0) {
|
||||
// all good
|
||||
} else {
|
||||
// a mapped property shares the same name with an original property
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingNameConflictError(`Remapped property (${property}) may not share it's new name with an existing property.`),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
res: true,
|
||||
};
|
||||
}
|
||||
|
||||
getMappedProperties() {
|
||||
return this.properties.filter(x => x.mapping === PropertyMappingOption.Map);
|
||||
}
|
||||
|
||||
copy(): PropertyMappingModel {
|
||||
const copy = new PropertyMappingModel(this.type);
|
||||
for (const property of this.properties) {
|
||||
const propertyCopy = new PropertyMapping(property.property, property.newProperty, property.mapping, property.locked);
|
||||
copy.properties.push(propertyCopy);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyMapping {
|
||||
|
|
@ -49,16 +113,47 @@ export class PropertyMapping {
|
|||
*/
|
||||
}
|
||||
|
||||
validate(): string {
|
||||
validate(): { res: boolean, err?: Error } {
|
||||
// locked property may only be default
|
||||
if (this.locked) {
|
||||
if (this.mapping === PropertyMappingOption.Remove) {
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be removed.`),
|
||||
};
|
||||
}
|
||||
if (this.mapping === PropertyMappingOption.Map) {
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": locked property may not be remapped.`),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mapping === PropertyMappingOption.Default) {
|
||||
return {res: true};
|
||||
}
|
||||
if (this.mapping === PropertyMappingOption.Remove) {
|
||||
return {res: true};
|
||||
}
|
||||
|
||||
if (!this.property || !containsOnlyLettersAndUnderscores(this.property)) {
|
||||
return `Error in conversion rule "${this.toString()}": property may not be empty and only contain letters and underscores.`;
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": property may not be empty and only contain letters and underscores.`),
|
||||
};
|
||||
}
|
||||
|
||||
if (!this.newProperty || !containsOnlyLettersAndUnderscores(this.newProperty)) {
|
||||
return `Error in conversion rule "${this.toString()}": new property may not be empty and only contain letters and underscores.`;
|
||||
return {
|
||||
res: false,
|
||||
err: new PropertyMappingValidationError(`Error in property mapping "${this.toString()}": new property may not be empty and only contain letters and underscores.`),
|
||||
};
|
||||
}
|
||||
|
||||
return '';
|
||||
return {
|
||||
res: true,
|
||||
};
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
|
|
|
|||
|
|
@ -49,10 +49,15 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.media-db-plugin-property-binding-to {
|
||||
.media-db-plugin-property-mapping-to {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.media-db-plugin-property-mapping-validation {
|
||||
color: var(--text-error);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||
|
|
@ -81,18 +86,25 @@
|
|||
|
||||
{#if property.mapping === PropertyMappingOption.Map}
|
||||
<Icon iconName="arrow-right"/>
|
||||
<div class="media-db-plugin-property-binding-to">
|
||||
<div class="media-db-plugin-property-mapping-to">
|
||||
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{ /each }
|
||||
{ /each }
|
||||
</div>
|
||||
<button class="mod-cta media-db-plugin-property-mappings-save-button" on:click={() => save(model)}>Save
|
||||
{ #if !model.validate().res }
|
||||
<div class="media-db-plugin-property-mapping-validation">
|
||||
{model.validate().err?.message}
|
||||
</div>
|
||||
{/if}
|
||||
<button
|
||||
class="media-db-plugin-property-mappings-save-button {model.validate().res ? 'mod-cta' : 'mod-muted'}"
|
||||
on:click={() => { if(model.validate().res) save(model) }}>Save
|
||||
</button>
|
||||
</div>
|
||||
{ /each }
|
||||
{ /each }
|
||||
|
||||
<pre>{JSON.stringify(models, null, 4)}</pre>
|
||||
|
||||
|
|
|
|||
|
|
@ -142,10 +142,7 @@ export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings
|
|||
// console.log(metadataObj);
|
||||
// console.log(model);
|
||||
|
||||
const propertyMappingModel: PropertyMappingModel = {
|
||||
type: mediaType,
|
||||
properties: [],
|
||||
};
|
||||
const propertyMappingModel: PropertyMappingModel = new PropertyMappingModel(mediaType);
|
||||
|
||||
for (const key of Object.keys(metadataObj)) {
|
||||
propertyMappingModel.properties.push(
|
||||
|
|
@ -486,7 +483,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
new PropertyMappingModelsComponent({
|
||||
target: this.containerEl,
|
||||
props: {
|
||||
models: JSON.parse(JSON.stringify(this.plugin.settings.propertyMappingModels)),
|
||||
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
|
||||
save: (model: PropertyMappingModel) => {
|
||||
let propertyMappingModels: PropertyMappingModel[] = [];
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue