Skip to content

Commit

Permalink
Fix setting meta properties (#158)
Browse files Browse the repository at this point in the history
* Replace property metadata instead of pushing a new one

* Filter out duplicate property metadata

* Add test for checking metadata of child classes
  • Loading branch information
safo6m authored Apr 25, 2023
1 parent 7348ea0 commit d00fe16
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 11 deletions.
3 changes: 2 additions & 1 deletion projects/ngx-hal/src/lib/decorators/attribute.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ATTRIBUTE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty as ModelPropertyEnum } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
import { updatePropertyMetadata } from '../helpers/update-property-metadata/update-property-metadata.helper';
import {
AttributeOptions,
DEFAULT_ATTRIBUTE_OPTIONS,
Expand Down Expand Up @@ -31,6 +32,6 @@ export function Attribute(options: AttributeOptions = {}) {
attributeProperty.propertyClass = attributeOptions.useClass;
}

existingAttributeProperties.push(attributeProperty);
updatePropertyMetadata(existingAttributeProperties, attributeProperty);
};
}
3 changes: 2 additions & 1 deletion projects/ngx-hal/src/lib/decorators/has-many.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HAS_MANY_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
import { updatePropertyMetadata } from '../helpers/update-property-metadata/update-property-metadata.helper';
import { DEFAULT_HAS_MANY_OPTIONS, HasManyOptions } from '../interfaces/has-many-options.interface';
import { HasManyModelProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
Expand All @@ -24,6 +25,6 @@ export function HasMany(options: HasManyOptions) {
externalName: options.externalName || propertyName,
};

existingHasManyProperties.push(hasManyProperty);
updatePropertyMetadata(existingHasManyProperties, hasManyProperty);
};
}
3 changes: 2 additions & 1 deletion projects/ngx-hal/src/lib/decorators/has-one.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HAS_ONE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
import { updatePropertyMetadata } from '../helpers/update-property-metadata/update-property-metadata.helper';
import { DEFAULT_HAS_ONE_OPTIONS, HasOneOptions } from '../interfaces/has-one-options.interface';
import { HasOneModelProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
Expand All @@ -24,6 +25,6 @@ export function HasOne(options: HasOneOptions) {
externalName: options.externalName || propertyName,
};

existingHasOneProperties.push(hasOneProperty);
updatePropertyMetadata(existingHasOneProperties, hasOneProperty);
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HEADER_ATTRIBUTE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty as ModelPropertyEnum } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
import { updatePropertyMetadata } from '../helpers/update-property-metadata/update-property-metadata.helper';
import {
DEFAULT_HEADER_ATTRIBUTE_OPTIONS,
HeaderAttributeOptions,
Expand Down Expand Up @@ -37,6 +38,6 @@ export function HeaderAttribute(options: HeaderAttributeOptions = {}) {
attributeProperty.propertyClass = headerAttributeOptions.useClass;
}

existingHeaderAttributeProperties.push(attributeProperty);
updatePropertyMetadata(existingHeaderAttributeProperties, attributeProperty);
};
}
3 changes: 2 additions & 1 deletion projects/ngx-hal/src/lib/decorators/link.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LINK_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
import { updatePropertyMetadata } from '../helpers/update-property-metadata/update-property-metadata.helper';
import { LinkRelationshipOptions } from '../interfaces/link-relationship-options.interface';
import { LinkProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
Expand All @@ -19,6 +20,6 @@ export function Link(options: LinkRelationshipOptions = {}) {
externalName: options.externalName || propertyName,
};

existingLinkProperties.push(linkProperty);
updatePropertyMetadata(existingLinkProperties, linkProperty);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function getArrayObjProperty<T>(obj, propertyKey: string): Array<T> {
parentMeta = getArrayObjProperty(parentClass, propertyKey);
}
const meta: Array<T> = getObjProperty(obj, propertyKey);
const finalMeta = [].concat(parentMeta, meta);
const finalMeta = [].concat(meta, parentMeta);

return finalMeta;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ModelProperty } from '../../interfaces/model-property.interface';

// Modifies the original array
export function updatePropertyMetadata<T extends ModelProperty>(
modelProperties: Array<T>,
newModelProperty: T,
): Array<T> {
const existingProperty: T = modelProperties.find((property: T) => {
return property.name === newModelProperty.name;
});

if (existingProperty) {
const indexOfExistingProperty: number = modelProperties.indexOf(existingProperty);
modelProperties[indexOfExistingProperty] = newModelProperty;
} else {
modelProperties.push(newModelProperty);
}

return modelProperties;
}
8 changes: 8 additions & 0 deletions projects/ngx-hal/src/lib/mocks/mock-child-model-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ModelConfig } from '../decorators/model-config.decorator';
import { MockModel2 } from './mock-model-2';

@ModelConfig({
type: 'MockChild2',
endpoint: 'MockChild2',
})
export class MockChildModel2 extends MockModel2 {}
19 changes: 19 additions & 0 deletions projects/ngx-hal/src/lib/mocks/mock-child-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Attribute } from '../decorators/attribute.decorator';
import { HasOne } from '../decorators/has-one.decorator';
import { ModelConfig } from '../decorators/model-config.decorator';
import { MockChildModel2 } from './mock-child-model-2';
import { MockModel } from './mock-model';

@ModelConfig({
type: 'MockChild',
endpoint: 'mock-child-model-endpoint',
})
export class MockChildModel extends MockModel {
@Attribute()
name: string;

@HasOne({
propertyClass: MockChildModel2,
})
mockModel2Connection: MockChildModel2;
}
24 changes: 19 additions & 5 deletions projects/ngx-hal/src/lib/models/hal.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,23 +371,37 @@ export abstract class HalModel<Datastore extends DatastoreService = DatastoreSer
}

private get attributeProperties(): Array<AttributeModelProperty> {
return getArrayObjProperty(this, ATTRIBUTE_PROPERTIES_METADATA_KEY);
return this.getPropertiesMetadata(ATTRIBUTE_PROPERTIES_METADATA_KEY);
}

private get headerAttributeProperties(): Array<HeaderAttributeModelProperty> {
return getArrayObjProperty(this, HEADER_ATTRIBUTE_PROPERTIES_METADATA_KEY);
return this.getPropertiesMetadata(HEADER_ATTRIBUTE_PROPERTIES_METADATA_KEY);
}

private get hasOneProperties(): Array<HasOneModelProperty> {
return getArrayObjProperty(this, HAS_ONE_PROPERTIES_METADATA_KEY);
return this.getPropertiesMetadata(HAS_ONE_PROPERTIES_METADATA_KEY);
}

private get hasManyProperties(): Array<HasManyModelProperty> {
return getArrayObjProperty(this, HAS_MANY_PROPERTIES_METADATA_KEY);
return this.getPropertiesMetadata(HAS_MANY_PROPERTIES_METADATA_KEY);
}

private get linkProperties(): Array<LinkProperty> {
return getArrayObjProperty(this, LINK_PROPERTIES_METADATA_KEY);
return this.getPropertiesMetadata(LINK_PROPERTIES_METADATA_KEY);
}

private getPropertiesMetadata<T extends ModelProperty>(propertyKey: string): Array<T> {
const propertiesMetadata: Array<T> = getArrayObjProperty(this, propertyKey);

const uniqueMetadata: Array<T> = [];

propertiesMetadata.forEach((property: T) => {
if (uniqueMetadata.map((metadata: T) => metadata.name).indexOf(property.name) === -1) {
uniqueMetadata.push(property);
}
});

return uniqueMetadata;
}

private initializeHasOneProperties(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { DatastoreService } from './datastore.service';
import { MockModelWithCustomNames } from '../../mocks/mock-model-with-custom-names';
import { MockModelAttributes } from '../../mocks/mock-model-attributes';
import { MockAttributesRel } from '../../mocks/mock-model-attributes-rel';
import { MockChildModel } from '../../mocks/mock-child-model';
import { MockChildModel2 } from '../../mocks/mock-child-model-2';

const BASE_NETWORK_URL = 'http://test.com';

Expand Down Expand Up @@ -89,6 +91,23 @@ describe('DatastoreService', () => {
expect(carModel.carParts.length).toBe(1);
expect(carModel.carParts[0].name).toBe(partName);
});

it('should return property metadata of the most specific class', () => {
const mockModel = new MockChildModel(
{
name: 'mock child model',
mockModel2Connection: new MockChildModel2({ name: 'mock 2 child' }, datastoreService),
},
datastoreService,
);

expect(mockModel.getPropertyData('mockModel2Connection').propertyClass).toBe(MockChildModel2);

const mockModel2ConnectionMetadata = mockModel['hasOneProperties']
.map((property) => property.name)
.filter((name) => name === 'mockModel2Connection');
expect(mockModel2ConnectionMetadata.length).toBe(1);
});
});

describe('request method', () => {
Expand Down

0 comments on commit d00fe16

Please sign in to comment.