Object metadata API create one using workspace migration v2 (#13420)

# Introduction
In this PR we create basic transpilation methods and utils to handle
input to flat, entity to flat, object maps to flat. In order to
transpile everything into a common validation that will be implemented
in another PR

## FieldMetadataEntity typing
Added `never | null` to fields that should never be in order to ease
general abstracted method to pass null, as anw it's what is in the
database

## Todo
- ~~Create a feature flag~~
- Integration test for object creation through metadata api + pg col
introspection and snapshoting
This commit is contained in:
Paul Rastoin
2025-07-29 17:47:28 +02:00
committed by GitHub
parent 600df4fd90
commit c1bf0a1fbf
66 changed files with 1224 additions and 164 deletions
@@ -0,0 +1,79 @@
/**
* Deep merges two objects or arrays recursively
* - Objects are merged by combining their properties
* - Arrays are merged by concatenating them
* - Primitive values from target override source
* - Null values from target are preserved
* - Undefined values from target are ignored
* - Date and RegExp objects are treated as primitives (replaced, not merged)
*
* @param source The source object to merge from
* @param target The target object to merge into
* @returns A new merged object
*/
export const deepMerge = <T extends object>(
source: Required<T>,
target: Required<T>,
): T => {
// Handle null/undefined cases
if (!source) return target as T;
if (!target) return source;
// Create a new object to avoid mutations
const output = { ...source };
// Iterate through all keys in target
Object.keys(target).forEach((key) => {
const sourceValue = source[key as keyof T];
const targetValue = target[key as keyof T];
// Skip undefined values in target
if (targetValue === undefined) {
return;
}
// Handle null values - explicitly assign them
if (targetValue === null) {
output[key as keyof T] = null as T[keyof T];
return;
}
// Handle arrays - concatenate them
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
output[key as keyof T] = [...sourceValue, ...targetValue] as T[keyof T];
return;
}
// Handle Date and RegExp objects - treat them as primitives
if (
targetValue instanceof Date ||
targetValue instanceof RegExp ||
sourceValue instanceof Date ||
sourceValue instanceof RegExp
) {
output[key as keyof T] = targetValue as T[keyof T];
return;
}
// Handle nested objects - recurse
if (
sourceValue &&
targetValue &&
typeof sourceValue === 'object' &&
typeof targetValue === 'object' &&
!Array.isArray(sourceValue) &&
!Array.isArray(targetValue)
) {
output[key as keyof T] = deepMerge(
sourceValue as object,
targetValue as object,
) as T[keyof T];
return;
}
// For primitives
output[key as keyof T] = targetValue as T[keyof T];
});
return output;
};