Skip to content

Instantly share code, notes, and snippets.

@ahuggins-nhs
Last active August 18, 2020 14:41
Show Gist options
  • Save ahuggins-nhs/e8c627c2827ac48fc3b0b49b2d46fd2e to your computer and use it in GitHub Desktop.
Save ahuggins-nhs/e8c627c2827ac48fc3b0b49b2d46fd2e to your computer and use it in GitHub Desktop.
A field-to-property mapping utility
class FieldMap {
/**
* @param {string} fieldName
* @param {string} propertyName
* @param {string} objectName
* @param {boolean} [active=false]
*/
constructor (fieldName, propertyName, objectName, active = false) {
/**
* @private
* @type {string}
*/
this._fieldName = fieldName
/**
* @private
* @type {string}
*/
this._propertyName = propertyName
/**
* @private
* @type {string}
*/
this._objectName = objectName
/**
* @private
* @type {boolean}
*/
this._active = active
/**
* @private
* @type {boolean}
*/
this.modified = false
}
/** @param {boolean} _active */
set active (_active) {
if (this._active !== _active) {
this.modified = true
this._active = _active
}
}
/** @param {string} _fieldName */
set fieldName (_fieldName) {
if (this._fieldName !== _fieldName) {
this.modified = true
this._fieldName = _fieldName
}
}
/** @param {string} _propertyName */
set propertyName (_propertyName) {
if (this._propertyName !== _propertyName) {
this.modified = true
this._propertyName = _propertyName
}
}
/** Immutable property objectName.
* @param {string} _objectName
*/
set objectName (_objectName) {
// Makes objectName immutable.
}
get active () {
return this._active
}
get fieldName () {
this.active = true
return this._fieldName
}
get propertyName () {
this.active = true
return this._propertyName
}
get objectName () {
this.active = true
return this._objectName
}
toJSON () {
return {
fieldName: this._fieldName,
propertyName: this._propertyName,
objectName: this._objectName,
active: this._active
}
}
toTableRow () {
return {
PartitionKey: this._objectName,
RowKey: this._fieldName + '::' + this._propertyName,
...this.toJSON()
}
}
}
class FieldMapper {
/** @param {Array<{ PartitionKey?: string, RowKey?: string, fieldName: string, propertyName: string, objectName: string, active: boolean }>} tableRows */
constructor (tableRows = []) {
/** @type {Map<string, FieldMap>} */
this.fields = new Map()
/** @type {Map<string, FieldMapper>} */
this.mappers = new Map()
for (const tableRow of tableRows) {
this.setFieldMap(tableRow.fieldName, tableRow.propertyName, tableRow.objectName, tableRow.active)
}
this.isChild = false
}
/**
* @param {string} propertyName
* @returns {string}
*/
getFieldName (propertyName) {
return this.fields.get(propertyName).fieldName
}
/**
* @param {string} fieldName
* @returns {string}
*/
getPropertyName (fieldName) {
return this.fields.get(fieldName).propertyName
}
/** Get the field map instance for a field name or property name.
* @param {string} fieldNameOrPropertyName
* @returns {FieldMap}
*/
getFieldMap (fieldNameOrPropertyName) {
return this.fields.get(fieldNameOrPropertyName)
}
/** Get a field mapper instance for a specific object name.
* @param {string} objectName
* @returns {FieldMapper}
*/
getObjectMap (objectName) {
return this.mappers.get(objectName)
}
/** Method for creating and propagating field maps.
* @param {string} fieldName
* @param {string} propertyName
* @param {string} objectName
* @param {boolean} [active=false]
*/
setFieldMap (fieldName, propertyName, objectName, active = false) {
// Short-circuit for child field maps.
if (objectName instanceof FieldMap) {
this.fields.set(fieldName, objectName)
this.fields.set(propertyName, objectName)
return
} else {
if (this.isChild) return
}
const field = new FieldMap(fieldName, propertyName, objectName, active)
this.fields.set(fieldName, field)
this.fields.set(propertyName, field)
let mapper = this.mappers.get(objectName)
if (!(mapper instanceof FieldMapper)) {
mapper = new FieldMapper()
mapper.isChild = true
this.mappers.set(objectName, mapper)
}
mapper.setFieldMap(fieldName, propertyName, field)
}
/** Get all modified field maps to table rows.
* @param {boolean} [allMaps=false] - Optionally get all field maps.
* @returns {Array<{ PartitionKey: string, RowKey: string, fieldName: string, propertyName: string, objectName: string, active: boolean }>}
*/
toTableRows (allMaps = false) {
const tableRows = []
if (this.isChild) {
// Create a set so that there are no duplicate fieldMap references.
const fieldMaps = new Set(this.fields.values())
for (const fieldMap of fieldMaps) {
if (fieldMap.modified || allMaps) {
// Only create a table row if the data was modified.
tableRows.push(fieldMap.toTableRow())
}
}
} else {
// Parent should get tablerows from children.
const objectMaps = new Set(this.mappers.values())
for (const objectMap of objectMaps) {
tableRows.push(...objectMap.toTableRows(allMaps))
}
}
return tableRows
}
}
module.exports = {
FieldMapper
}
const test = new FieldMapper([{ fieldName: 'one', propertyName: 'two', objectName: 'three', active: false }])
console.log('Internal map:', test.fields)
console.log('Internal map:', test.mappers)
console.log('Number of table rows before modification:', test.toTableRows().length)
console.log('Field map references are the same instance:', test.getFieldMap('one') === test.getFieldMap('two'))
console.log('JSON string of field map:', JSON.stringify(test.getFieldMap('two')))
console.log('Get the field name of the property:', test.getFieldName('two')) // Makes the field map active and sets it to 'modified'
console.log('Number of table rows after modification:', test.toTableRows().length) // 1
console.log('Field mapper by object name:', test.getObjectMap('three'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment