Refactor backend folder structure (#4505)
* Refactor backend folder structure Co-authored-by: Charles Bochet <charles@twenty.com> * fix tests * fix * move yoga hooks --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
||||
import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util';
|
||||
|
||||
describe('stringifyWithoutKeyQuote', () => {
|
||||
test('should stringify object correctly without quotes around keys', () => {
|
||||
const obj = { name: 'John', age: 30, isAdmin: false };
|
||||
const result = stringifyWithoutKeyQuote(obj);
|
||||
|
||||
expect(result).toBe('{name:"John",age:30,isAdmin:false}');
|
||||
});
|
||||
|
||||
test('should handle nested objects', () => {
|
||||
const obj = {
|
||||
name: 'John',
|
||||
age: 30,
|
||||
address: { city: 'New York', zipCode: 10001 },
|
||||
};
|
||||
const result = stringifyWithoutKeyQuote(obj);
|
||||
|
||||
expect(result).toBe(
|
||||
'{name:"John",age:30,address:{city:"New York",zipCode:10001}}',
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle arrays', () => {
|
||||
const obj = {
|
||||
name: 'John',
|
||||
age: 30,
|
||||
hobbies: ['reading', 'movies', 'hiking'],
|
||||
};
|
||||
const result = stringifyWithoutKeyQuote(obj);
|
||||
|
||||
expect(result).toBe(
|
||||
'{name:"John",age:30,hobbies:["reading","movies","hiking"]}',
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle empty objects', () => {
|
||||
const obj = {};
|
||||
const result = stringifyWithoutKeyQuote(obj);
|
||||
|
||||
expect(result).toBe('{}');
|
||||
});
|
||||
|
||||
test('should handle numbers, strings, and booleans', () => {
|
||||
const num = 10;
|
||||
const str = 'Hello';
|
||||
const bool = false;
|
||||
|
||||
expect(stringifyWithoutKeyQuote(num)).toBe('10');
|
||||
expect(stringifyWithoutKeyQuote(str)).toBe('"Hello"');
|
||||
expect(stringifyWithoutKeyQuote(bool)).toBe('false');
|
||||
});
|
||||
|
||||
test('should handle null and undefined', () => {
|
||||
expect(stringifyWithoutKeyQuote(null)).toBe('null');
|
||||
expect(stringifyWithoutKeyQuote(undefined)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
GraphQLResolveInfo,
|
||||
SelectionSetNode,
|
||||
Kind,
|
||||
SelectionNode,
|
||||
FieldNode,
|
||||
InlineFragmentNode,
|
||||
ValueNode,
|
||||
} from 'graphql';
|
||||
|
||||
const isFieldNode = (node: SelectionNode): node is FieldNode =>
|
||||
node.kind === Kind.FIELD;
|
||||
|
||||
const isInlineFragmentNode = (
|
||||
node: SelectionNode,
|
||||
): node is InlineFragmentNode => node.kind === Kind.INLINE_FRAGMENT;
|
||||
|
||||
const findFieldNode = (
|
||||
selectionSet: SelectionSetNode | undefined,
|
||||
key: string,
|
||||
): FieldNode | null => {
|
||||
if (!selectionSet) return null;
|
||||
|
||||
let field: FieldNode | null = null;
|
||||
|
||||
for (const selection of selectionSet.selections) {
|
||||
// We've found the field
|
||||
if (isFieldNode(selection) && selection.name.value === key) {
|
||||
return selection;
|
||||
}
|
||||
|
||||
// Recursively search for the field in nested selections
|
||||
if (
|
||||
(isFieldNode(selection) || isInlineFragmentNode(selection)) &&
|
||||
selection.selectionSet
|
||||
) {
|
||||
field = findFieldNode(selection.selectionSet, key);
|
||||
|
||||
// If we find the field in a nested selection, stop searching
|
||||
if (field) break;
|
||||
}
|
||||
}
|
||||
|
||||
return field;
|
||||
};
|
||||
|
||||
const parseValueNode = (
|
||||
valueNode: ValueNode,
|
||||
variables: GraphQLResolveInfo['variableValues'],
|
||||
) => {
|
||||
switch (valueNode.kind) {
|
||||
case Kind.VARIABLE:
|
||||
return variables[valueNode.name.value];
|
||||
case Kind.INT:
|
||||
case Kind.FLOAT:
|
||||
return Number(valueNode.value);
|
||||
case Kind.STRING:
|
||||
case Kind.BOOLEAN:
|
||||
case Kind.ENUM:
|
||||
return valueNode.value;
|
||||
case Kind.LIST:
|
||||
return valueNode.values.map((value) => parseValueNode(value, variables));
|
||||
case Kind.OBJECT:
|
||||
return valueNode.fields.reduce((obj, field) => {
|
||||
obj[field.name.value] = parseValueNode(field.value, variables);
|
||||
|
||||
return obj;
|
||||
}, {});
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFieldArgumentsByKey = (
|
||||
info: GraphQLResolveInfo,
|
||||
fieldKey: string,
|
||||
): Record<string, any> => {
|
||||
// Start from the first top-level field node and search recursively
|
||||
const targetField = findFieldNode(info.fieldNodes[0].selectionSet, fieldKey);
|
||||
|
||||
// If the field is not found, throw an error
|
||||
if (!targetField) {
|
||||
throw new Error(`Field "${fieldKey}" not found.`);
|
||||
}
|
||||
|
||||
// Extract the arguments from the field we've found
|
||||
const args: Record<string, any> = {};
|
||||
|
||||
if (targetField.arguments && targetField.arguments.length) {
|
||||
for (const arg of targetField.arguments) {
|
||||
args[arg.name.value] = parseValueNode(arg.value, info.variableValues);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export const stringifyWithoutKeyQuote = (obj: any) => {
|
||||
const jsonString = JSON.stringify(obj);
|
||||
const jsonWithoutQuotes = jsonString?.replace(/"(\w+)"\s*:/g, '$1:');
|
||||
|
||||
return jsonWithoutQuotes;
|
||||
};
|
||||
Reference in New Issue
Block a user