Skip to content

Commit

Permalink
feat: set and unset $parent on create and set
Browse files Browse the repository at this point in the history
Closes #41
  • Loading branch information
philippfromme committed Apr 14, 2023
1 parent 3506546 commit b0dded9
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 0 deletions.
24 changes: 24 additions & 0 deletions lib/properties.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {
assign,
isArray,
isString
} from 'min-dash';

import Base from './base.js';

/**
* A utility that gets and sets properties of model elements.
*
Expand Down Expand Up @@ -36,6 +39,8 @@ Properties.prototype.set = function(target, name, value) {
// unset the property, if the specified value is undefined;
// delete from $attrs (for extensions) or the target itself
if (property) {
updateParent(target[propertyName], value, undefined);

delete target[propertyName];
} else {
delete target.$attrs[stripGlobal(name)];
Expand All @@ -45,6 +50,12 @@ Properties.prototype.set = function(target, name, value) {
// set the property, defining well defined properties on the fly
// or simply updating them in target.$attrs (for extensions)
if (property) {
const descriptor = this.model.getPropertyDescriptor(target, propertyName);

if (descriptor && !descriptor.isReference) {
updateParent(target[propertyName], value, target);
}

if (propertyName in target) {
target[propertyName] = value;
} else {
Expand Down Expand Up @@ -177,4 +188,17 @@ function defineProperty(target, property, value) {

function stripGlobal(name) {
return name.replace(/^:/, '');
}

function updateParent(oldValues, newValues, parent) {
setParent(oldValues, undefined);
setParent(newValues, parent);
}

function setParent(values, parent) {
if (isArray(values)) {
values.forEach(value => setParent(value, parent));
} else if (values instanceof Base) {
values.$parent = parent;
}
}
197 changes: 197 additions & 0 deletions test/spec/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,202 @@ describe('properties', function() {
});


describe('parent', function() {

describe('create', function() {

it('should set parent if model element', function() {

// when
var complexNesting = model.create('props:ComplexNesting', {
nested: model.create('props:Complex')
});

// then
expect(complexNesting.get('nested').$parent).to.equal(complexNesting);
});


it('should not set parent if not model element', function() {

// when
var complexNesting = model.create('props:ComplexNesting', {
foo: {}
});

// then
expect(complexNesting.get('foo').$parent).not.to.exist;
});

});


describe('set', function() {

describe('one', function() {

it('should set parent if model element', function() {

// given
var embedding = model.create('props:Embedding');

var embeddedComplex = model.create('props:Complex');

// when
embedding.set('embeddedComplex', embeddedComplex);

// then
expect(embedding.get('embeddedComplex')).to.equal(embeddedComplex);
expect(embeddedComplex.$parent).to.equal(embedding);
});


it('should unset parent if model element', function() {

// given
var embeddedComplex = model.create('props:Complex');

var embedding = model.create('props:Embedding', {
embeddedComplex
});

// assume
expect(embedding.get('embeddedComplex')).to.equal(embeddedComplex);
expect(embeddedComplex.$parent).to.equal(embedding);

// when
embedding.set('embeddedComplex', undefined);

// then
expect(embedding.get('embeddedComplex')).not.to.exist;
expect(embeddedComplex.$parent).not.to.exist;
});


it('should not set parent if not model element', function() {

// given
var embedding = model.create('props:Embedding');

// when
embedding.set('foo', {});

// then
expect(embedding.get('foo').$parent).not.to.exist;
});


it('should not unset parent if not model element', function() {

// given
var foo = { $parent: true };

var embedding = model.create('props:Embedding', {
foo
});

// assume
expect(foo.$parent).to.exist;

// when
embedding.set('foo', undefined);

// then
expect(foo.$parent).to.exist;
});


it('should not set parent if model element is reference', function() {

// given
var referencingSingle = model.create('props:ReferencingSingle');

var referencedComplex = model.create('props:Complex');

// when
referencingSingle.set('referencedComplex', referencedComplex);

// then
expect(referencingSingle.get('referencedComplex')).to.equal(referencedComplex);
expect(referencedComplex.$parent).not.to.exist;
});

});


describe('many', function() {

it('should set parent if model elements', function() {

// given
var containedColllection = model.create('props:ContainedCollection');

var children = [
model.create('props:Complex'),
model.create('props:Complex')
];

// when
containedColllection.set('children', children);

// then
expect(containedColllection.get('children')).to.eql(children);

containedColllection.get('children').forEach(child => {
expect(child.$parent).to.equal(containedColllection);
});
});


it('should unset parent if model elements', function() {

// given
var fooChild = model.create('props:Complex'),
barChild = model.create('props:Complex');

var containedColllection = model.create('props:ContainedCollection', {
children: [
fooChild,
barChild
]
});

// when
containedColllection.set('children', [
fooChild
]);

// then
expect(containedColllection.get('children')).to.eql([ fooChild ]);

expect(fooChild.$parent).to.equal(containedColllection);
expect(barChild.$parent).not.to.exist;
});


it('should not set parent if not model element', function() {

// given
var containedCollection = model.create('props:ContainedCollection');

// when
containedCollection.set('foos', [
{},
{}
]);

// then
containedCollection.get('foos').forEach(foo => {
expect(foo.$parent).not.to.exist;
});
});

});

});

});

forEach([
false,
true,
Expand Down Expand Up @@ -315,6 +511,7 @@ describe('properties', function() {
});

});

});


Expand Down

0 comments on commit b0dded9

Please sign in to comment.