Merge main

This commit is contained in:
rijkvanzanten
2020-10-09 15:46:04 -04:00
2 changed files with 104 additions and 77 deletions

View File

@@ -76,7 +76,7 @@ export default async function runAST(
// and nesting is done, we parse through the output structure, and filter out all non-requested
// fields
if (options?.child !== true) {
items = removeTemporaryFields(items, ast);
items = removeTemporaryFields(items, ast, primaryKeyField);
}
return items;
@@ -241,7 +241,8 @@ function mergeWithParentItems(
function removeTemporaryFields(
rawItem: Item | Item[],
ast: AST | O2MNode | M2ONode
ast: AST | O2MNode | M2ONode,
primaryKeyField: string
): Item | Item[] {
const rawItems: Item[] = Array.isArray(rawItem) ? rawItem : [rawItem];
@@ -257,14 +258,16 @@ function removeTemporaryFields(
for (const rawItem of rawItems) {
if (rawItem === null) return rawItem;
const item = fields.includes('*') ? rawItem : pick(rawItem, fields);
const item = fields.length > 0 ? pick(rawItem, fields) : rawItem[primaryKeyField];
for (const nestedCollection of nestedCollections) {
if (item[nestedCollection.fieldKey] !== null && nestedCollection.type !== 'm2a') {
/** @TODO REMOVE M2A CHECK HERE */
item[nestedCollection.fieldKey] = removeTemporaryFields(
rawItem[nestedCollection.fieldKey],
nestedCollection
nestedCollection,
nestedCollection.parentKey
);
}
}

View File

@@ -62,74 +62,16 @@ export default async function getASTFromQuery(
delete query.fields;
delete query.deep;
ast.children = (await parseFields(collection, fields, deep)).filter(
filterEmptyChildCollections
);
ast.children = await parseFields(collection, fields, deep);
return ast;
function convertWildcards(parentCollection: string, fields: string[]) {
const allowedFields = permissions
? permissions
.find((permission) => parentCollection === permission.collection)
?.fields?.split(',')
: ['*'];
if (!allowedFields || allowedFields.length === 0) return [];
for (let index = 0; index < fields.length; index++) {
const fieldKey = fields[index];
if (fieldKey.includes('*') === false) continue;
if (fieldKey === '*') {
if (allowedFields.includes('*')) continue;
fields.splice(index, 1, ...allowedFields);
}
// Swap *.* case for *,<relational-field>.*,<another-relational>.*
if (fieldKey.includes('.') && fieldKey.split('.')[0] === '*') {
const parts = fieldKey.split('.');
const relationalFields = allowedFields.includes('*')
? relations
.filter(
(relation) =>
relation.many_collection === parentCollection ||
relation.one_collection === parentCollection
)
.map((relation) => {
const isM2O = relation.many_collection === parentCollection;
return isM2O ? relation.many_field : relation.one_field;
})
: allowedFields.filter((fieldKey) => !!getRelation(parentCollection, fieldKey));
const nonRelationalFields = allowedFields.filter(
(fieldKey) => relationalFields.includes(fieldKey) === false
);
fields.splice(
index,
1,
...[
...relationalFields.map((relationalField) => {
return `${relationalField}.${parts.slice(1).join('.')}`;
}),
...nonRelationalFields,
]
);
}
}
return fields;
}
async function parseFields(
parentCollection: string,
fields: string[],
deep?: Record<string, Query>
) {
fields = convertWildcards(parentCollection, fields);
fields = await convertWildcards(parentCollection, fields);
if (!fields) return [];
@@ -138,9 +80,17 @@ export default async function getASTFromQuery(
const relationalStructure: Record<string, string[]> = {};
for (const field of fields) {
if (field.includes('.') === false) {
children.push({ type: 'field', name: field });
} else {
const isRelational =
field.includes('.') ||
!!relations.find(
(relation) =>
(relation.many_collection === parentCollection &&
relation.many_field === field) ||
(relation.one_collection === parentCollection &&
relation.one_field === field)
);
if (isRelational) {
// field is relational
const parts = field.split('.');
@@ -148,7 +98,11 @@ export default async function getASTFromQuery(
relationalStructure[parts[0]] = [];
}
relationalStructure[parts[0]].push(parts.slice(1).join('.'));
if (parts.length > 1) {
relationalStructure[parts[0]].push(parts.slice(1).join('.'));
}
} else {
children.push({ type: 'field', name: field });
}
}
@@ -192,9 +146,7 @@ export default async function getASTFromQuery(
parentKey: await schemaInspector.primary(parentCollection),
relation: relation,
query: deep?.[relationalField] || {},
children: (await parseFields(relatedCollection, nestedFields)).filter(
filterEmptyChildCollections
),
children: await parseFields(relatedCollection, nestedFields),
};
}
@@ -204,6 +156,68 @@ export default async function getASTFromQuery(
return children;
}
async function convertWildcards(parentCollection: string, fields: string[]) {
const allowedFields = permissions
? permissions
.find((permission) => parentCollection === permission.collection)
?.fields?.split(',')
: ['*'];
if (!allowedFields || allowedFields.length === 0) return [];
for (let index = 0; index < fields.length; index++) {
const fieldKey = fields[index];
if (fieldKey.includes('*') === false) continue;
if (fieldKey === '*') {
// Set to all fields in collection
if (allowedFields.includes('*')) {
const fieldsInCollection = await getFieldsInCollection(parentCollection);
fields.splice(index, 1, ...fieldsInCollection);
} else {
// Set to all allowed fields
fields.splice(index, 1, ...allowedFields);
}
}
// Swap *.* case for *,<relational-field>.*,<another-relational>.*
if (fieldKey.includes('.') && fieldKey.split('.')[0] === '*') {
const parts = fieldKey.split('.');
const relationalFields = allowedFields.includes('*')
? relations
.filter(
(relation) =>
relation.many_collection === parentCollection ||
relation.one_collection === parentCollection
)
.map((relation) => {
const isM2O = relation.many_collection === parentCollection;
return isM2O ? relation.many_field : relation.one_field;
})
: allowedFields.filter((fieldKey) => !!getRelation(parentCollection, fieldKey));
const nonRelationalFields = allowedFields.filter(
(fieldKey) => relationalFields.includes(fieldKey) === false
);
fields.splice(
index,
1,
...[
...relationalFields.map((relationalField) => {
return `${relationalField}.${parts.slice(1).join('.')}`;
}),
...nonRelationalFields,
]
);
}
}
return fields;
}
function getRelation(collection: string, field: string) {
const relation = relations.find((relation) => {
return (
@@ -229,12 +243,6 @@ export default async function getASTFromQuery(
}
}
function filterEmptyChildCollections(childNode: FieldNode | NestedCollectionNode) {
if (childNode.type === 'field') return true;
if (childNode.children.length > 0) return true;
return false;
}
function getRelationType(
relatedCollection: string,
relationalField: string,
@@ -253,4 +261,20 @@ export default async function getASTFromQuery(
return 'o2m';
}
async function getFieldsInCollection(collection: string) {
const columns = (await schemaInspector.columns(collection)).map((column) => column.column);
const fields = (
await database.select('field').from('directus_fields').where({ collection })
).map((field) => field.field);
const fieldsInCollection = [
...columns,
...fields.filter((field) => {
return columns.includes(field) === false;
}),
];
return fieldsInCollection;
}
}