Skip to content

Commit

Permalink
fix(hadron-document): allow expanding an element that has its type ch…
Browse files Browse the repository at this point in the history
…anged to array or object COMPASS-7929 (#6013)
  • Loading branch information
Anemy authored Jul 16, 2024
1 parent a3228d9 commit 092034f
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
36 changes: 20 additions & 16 deletions packages/hadron-document/src/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ const UNEDITABLE_TYPES = [
'DBRef',
];

export function isValueExpandable(
value: BSONValue
): value is BSONObject | BSONArray {
return isPlainObject(value) || isArray(value);
}

/**
* Represents an element in a document.
*/
Expand All @@ -58,6 +64,11 @@ export class Element extends EventEmitter {
added: boolean;
removed: boolean;
elements?: ElementList;
// With Arrays and Objects we store the value in the
// `elements` instead of currentValue. We use `originalExpandableValue`
// to store the original value that was passed in. This is necessary
// to be able to revert to the original value when the user cancels
// any changes.
originalExpandableValue?: BSONObject | BSONArray;
parent: Element | Document | null;
type: TypeCastTypes;
Expand Down Expand Up @@ -116,7 +127,7 @@ export class Element extends EventEmitter {
value = TypeChecker.cast(value, TypeChecker.type(value));
}

if (this._isExpandable(value)) {
if (isValueExpandable(value)) {
// NB: Important to set `originalExpandableValue` first as element
// generation will depend on it
this.originalExpandableValue = value;
Expand Down Expand Up @@ -168,10 +179,10 @@ export class Element extends EventEmitter {
*/
edit(value: BSONValue): void {
this.currentType = TypeChecker.type(value);
if (this._isExpandable(value) && !this._isExpandable(this.currentValue)) {
if (isValueExpandable(value) && !isValueExpandable(this.currentValue)) {
this.currentValue = null;
this.elements = this._generateElements(value);
} else if (!this._isExpandable(value) && this.elements) {
} else if (!isValueExpandable(value) && this.elements) {
this.currentValue = value;
this.elements = undefined;
} else {
Expand Down Expand Up @@ -455,6 +466,10 @@ export class Element extends EventEmitter {
}
}

_isExpandable(): boolean {
return this.currentType === 'Array' || this.currentType === 'Object';
}

/**
* Is the element the last in the elements.
*
Expand Down Expand Up @@ -726,7 +741,7 @@ export class Element extends EventEmitter {
* will most expand the element itself.
*/
expand(expandChildren = false): void {
if (!this._isExpandable(this.originalExpandableValue)) {
if (!this._isExpandable()) {
return;
}

Expand All @@ -743,7 +758,7 @@ export class Element extends EventEmitter {
* Collapses only the target element
*/
collapse(): void {
if (!this._isExpandable(this.originalExpandableValue)) {
if (!this._isExpandable()) {
return;
}

Expand Down Expand Up @@ -801,17 +816,6 @@ export class Element extends EventEmitter {
return !!element && element.isAdded() && element.isBlank();
}

/**
* Check if the value is expandable.
*
* @param value - The value to check.
*
* @returns If the value is expandable.
*/
_isExpandable(value: BSONValue): value is BSONObject | BSONArray {
return isPlainObject(value) || isArray(value);
}

/**
* Generates a sequence of child elements.
*
Expand Down
31 changes: 29 additions & 2 deletions packages/hadron-document/test/element.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from 'bson';
import { expect } from 'chai';
import { Document, Element, ElementEvents } from '../src/';
import { DATE_FORMAT } from '../src/element';
import { DATE_FORMAT, isValueExpandable } from '../src/element';
import moment from 'moment';
import Sinon from 'sinon';

Expand Down Expand Up @@ -2773,10 +2773,37 @@ describe('Element', function () {
expect(element.expanded).to.be.true;

for (const el of element.elements ?? []) {
if (el._isExpandable(el.originalExpandableValue)) {
if (isValueExpandable(el.originalExpandableValue)) {
expect(el.expanded).to.be.true;
}
}
});
});

context(
'when expanding an element that has been added with a changed type',
function () {
it('should expand the target element and its children', function () {
const element = new Element('names', {
firstName: 'A',
addresses: [1, 2],
});
expect(element.expanded).to.be.false;

element.insertEnd('pineapple', 'to be changed');
element.get('pineapple')?.changeType('Object');

element.insertEnd('pie', new Int32(123));
element.get('pie')?.changeType('Array');

expect(element.get('pineapple')?.expanded).to.be.false;
expect(element.get('pie')?.expanded).to.be.false;

element.expand(true);
expect(element.expanded).to.be.true;
expect(element.get('pineapple')?.expanded).to.be.true;
expect(element.get('pie')?.expanded).to.be.true;
});
}
);
});

0 comments on commit 092034f

Please sign in to comment.