source_utils_nodeUtils.bs
' ContentNode utility functions
' Provides reusable utilities for manipulating ContentNode objects
' Reset nodes to defaults, populate from AAs or other nodes
import "pkg:/source/utils/misc.bs"
namespace nodeUtils
' ============================================
' CONTENT NODE RESET UTILITIES
' ============================================
' Reset a ContentNode to its XML-defined defaults
'
' @param targetNode - The node to reset (must be a local reference)
' @param nodeType - The node type (e.g. "JellyfinServer", "JellyfinUser")
' @param preserveFields - Array of field names to preserve (e.g. ["settings"])
'
' Example:
' localServer = m.global.server
' nodeUtils.resetNodeToDefaults(localServer, "JellyfinServer", [])
'
' IMPORTANT: When resetting nodes on m.global, get a local reference first
' This minimizes rendezvous (only 1 rendezvous to get local ref, then 0 for reset)
sub resetNodeToDefaults(targetNode as object, nodeType as string, preserveFields = [] as object)
if not isValid(targetNode) or nodeType = ""
return
end if
' Create fresh node with XML defaults
freshNode = CreateObject("roSGNode", nodeType)
if not isValid(freshNode)
return
end if
' Get all default fields as associative array
defaultFields = freshNode.getFields()
' Build AA of fields to update (excluding preserved fields)
fieldsToUpdate = {}
for each fieldName in defaultFields
' Skip preserved fields
shouldPreserve = false
for each preservedField in preserveFields
if fieldName = preservedField
shouldPreserve = true
exit for
end if
end for
if not shouldPreserve
' Add field to update batch
fieldsToUpdate[fieldName] = defaultFields[fieldName]
end if
end for
' Update all fields at once using setFields() - single rendezvous
if fieldsToUpdate.Count() > 0
targetNode.setFields(fieldsToUpdate)
end if
end sub
' ============================================
' CONTENT NODE POPULATION UTILITIES
' ============================================
' Populate a ContentNode from an associative array
'
' @param targetNode - The node to populate (must be a local reference)
' @param dataAA - Associative array with field names/values
' @param skipFields - Array of field names to skip (e.g. ["settings"])
'
' Example:
' localServer = m.global.server
' mockData = MockDataLoader.LoadServer("default")
' nodeUtils.populateNodeFromAA(localServer, mockData, [])
'
' IMPORTANT: When populating nodes on m.global, get a local reference first
' This minimizes rendezvous
sub populateNodeFromAA(targetNode as object, dataAA as object, skipFields = [] as object)
if not isValid(targetNode) or not isValid(dataAA)
return
end if
' Build AA of fields to update (excluding skipped fields)
fieldsToUpdate = {}
for each key in dataAA
' Skip fields that should not be copied
shouldSkip = false
for each skipField in skipFields
if key = skipField
shouldSkip = true
exit for
end if
end for
if not shouldSkip
' Add field to update batch
fieldsToUpdate[key] = dataAA[key]
end if
end for
' Update all fields at once using setFields() - single rendezvous
if fieldsToUpdate.Count() > 0
targetNode.setFields(fieldsToUpdate)
end if
end sub
' Populate a ContentNode from another ContentNode's fields
'
' @param targetNode - The node to populate (must be a local reference)
' @param sourceNode - The node to copy from
' @param skipFields - Array of field names to skip (e.g. ["settings"])
'
' Example:
' localServer = m.global.server
' transformedServer = transformer.transformServerInfo(mockData)
' nodeUtils.populateNodeFromNode(localServer, transformedServer, [])
'
' IMPORTANT: When populating nodes on m.global, get a local reference first
' This minimizes rendezvous
sub populateNodeFromNode(targetNode as object, sourceNode as object, skipFields = [] as object)
if not isValid(targetNode) or not isValid(sourceNode)
return
end if
' Get all fields from source node as associative array
sourceFields = sourceNode.getFields()
' Use populateNodeFromAA to do the actual copying
populateNodeFromAA(targetNode, sourceFields, skipFields)
end sub
end namespace