Skip to content

Commit

Permalink
data-lake.ts: deal with setting non-flat data
Browse files Browse the repository at this point in the history
  • Loading branch information
Williangalvani committed Dec 17, 2024
1 parent 6b192f2 commit 6fbbfb7
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 17 deletions.
55 changes: 38 additions & 17 deletions src/libs/actions/data-lake.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { v4 as uuid } from 'uuid'

import { flattenData } from '../data-lake/data-flattener'

/**
* A variable to be used on a Cockpit action
* @param { string } id - The id of the variable
Expand Down Expand Up @@ -52,28 +54,47 @@ export const getDataLakeVariableData = (id: string): string | number | boolean |
return dataLakeVariableData[id]
}

export const setDataLakeVariableData = (id: string, data: object | string | number | boolean): void => {
const newData = data
if (data === null) {
export const setDataLakeVariableData = (
id: string,
data: object | string | number | boolean | Array<string | number>
): void => {
if (data === null) return

// Handle already-flat primitive types first
if (typeof data === 'string' || typeof data === 'number') {
if (dataLakeVariableData[id] === undefined) {
createDataLakeVariable(new DataLakeVariable(id, id, typeof data))
}
dataLakeVariableData[id] = data
notifyDataLakeVariableListeners(id)
return
}

// Try to flatten complex data
const flattenedData = flattenData(data, (value, index) => {
setDataLakeVariableData(`${id}/${index}`, value)
})

if (!flattenedData) return

const { type, value } = flattenedData

// Only proceed with string or number types
if (type !== 'string' && type !== 'number') {
console.debug(`attempting to create a variable with type ${type}. Skipping`)
return
}

// Create variable if it doesn't exist
if (dataLakeVariableData[id] === undefined) {
console.trace(`Cockpit action variable with id '${id}' does not exist. Creating it.`)
const type_of_variable = typeof data
if (type_of_variable === 'object') {
// TODO: support strings
}
if (type_of_variable !== 'string' && type_of_variable !== 'number') {
console.debug(`attempting to create a variable with type ${type_of_variable}. Skipping`)
return
}
createDataLakeVariable(new DataLakeVariable(id, id, typeof data))
createDataLakeVariable(new DataLakeVariable(id, id, type))
}
if (newData === undefined || typeof newData === 'object') {
return

// Update the value and notify listeners
if (typeof value === 'string' || typeof value === 'number') {
dataLakeVariableData[id] = value
notifyDataLakeVariableListeners(id)
}
dataLakeVariableData[id] = newData
notifyDataLakeVariableListeners(id)
}

export const deleteDataLakeVariable = (id: string): void => {
Expand Down
90 changes: 90 additions & 0 deletions src/libs/data-lake/data-flattener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* The result of flattening complex data structures into simple types
*/
interface FlattenedData {
/**
* The determined type of the flattened data
*/
type: 'string' | 'number' | 'boolean' | 'object'
/**
* The resulting flattened value
*/
value: string | number | boolean | object | Array<string | number>
}

/**
* Type guard to check if a value is an array of numbers
* @param {unknown[]} data The data to check
* @returns {data is number[]} True if the array contains numbers
*/
function isNumberArray(data: unknown[]): data is number[] {
return typeof data[0] === 'number'
}

/**
* Type guard to check if a value is an array of strings
* @param {unknown[]} data The data to check
* @returns {data is string[]} True if the array contains strings
*/
function isStringArray(data: unknown[]): data is string[] {
return typeof data[0] === 'string'
}

/**
* Flattens complex data structures into simple types that can be stored in the data lake
* @param {object | string | number | boolean | Array<string | number>} data The data to flatten
* @param {(value: number, index: string) => void} [onArrayElement] Callback for handling individual array elements
* @returns {FlattenedData | null} The flattened data structure or null if unable to flatten
*/
export function flattenData(
data: object | string | number | boolean | Array<string | number>,
onArrayElement?: (value: number, index: string) => void
): FlattenedData | null {
const typeOfData = typeof data

if (typeOfData !== 'object') {
return {
type: typeOfData as 'string' | 'number' | 'boolean',
value: data,
}
}

// Handle arrays
if (Array.isArray(data)) {
if (data.length === 0) return null

if (isStringArray(data)) {
return {
type: 'string',
value: data.join(''),
}
}

if (isNumberArray(data) && onArrayElement) {
// Handle array of numbers by calling the callback for each element
data.forEach((value, index) => {
onArrayElement(value, index.toString())
})
return null
}
}

// Handle objects with special properties
const objData = data as Record<string, unknown>

if ('type' in objData && 'value' in objData) {
return {
type: typeof objData.type as 'string' | 'number' | 'boolean',
value: objData.value as string | number | boolean,
}
}

if ('bits' in objData) {
return {
type: typeof objData.bits as 'string' | 'number' | 'boolean',
value: objData.bits as string | number | boolean,
}
}

return null
}

0 comments on commit 6fbbfb7

Please sign in to comment.