Skip to content

Commit

Permalink
break: Extend query builders again (#135)
Browse files Browse the repository at this point in the history
* break: Extend query builders again

* fixes

---------

Co-authored-by: Nicola Marcacci Rossi <[email protected]>
  • Loading branch information
nickredmark and nicola-smartive authored Feb 8, 2024
1 parent bc6e8f7 commit 4d0122e
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 32 deletions.
57 changes: 35 additions & 22 deletions src/client/queries.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import upperFirst from 'lodash/upperFirst';
import { ManyToManyRelation } from '..';
import { EntityModel, Model, Models, Relation } from '../models/models';
import {
actionableRelations,
and,
getActionableRelations,
isQueriableBy,
isRelation,
isSimpleField,
Expand All @@ -27,41 +26,55 @@ export const getUpdateEntityQuery = (
.filter(isUpdatableBy(role))
.map(({ name }) => name)
.join(' ')}
${actionableRelations(model, 'update')
.filter(({ name }) => !fields || fields.includes(name))
.map(({ name }) => `${name} { id }`)}
${getActionableRelations(model, 'update')
.filter((name) => !fields || fields.includes(name))
.map((name) => `${name} { id }`)}
${additionalFields}
}
}`;

export const getEditEntityRelationsQuery = (
model: EntityModel,
action: 'create' | 'update' | 'filter',
fields?: string[],
ignoreFields?: string[],
additionalFields: Record<string, string> = {}
) => {
const relations = actionableRelations(model, action).filter(
({ name }) => (!fields || fields.includes(name)) && (!ignoreFields || !ignoreFields.includes(name))
);
export type RelationConstraints = Record<string, (source: any) => any>;

export const fieldIsSearchable = (model: EntityModel, fieldName: string) => {
const relation = model.getRelation(fieldName);
const targetModel = relation.targetModel;
const displayField = targetModel.getField(targetModel.displayField || 'id');
return displayField.searchable;
};

export const getSelectEntityRelationsQuery = (model: EntityModel, relationNames: string[]) => {
const relations = relationNames.map((name) => model.getRelation(name));

return (
!!relations.length &&
`query ${upperFirst(action)}${model.name}Relations {
`query Select${model.name}Relations(${relations
.map(
(relation) =>
`$${relation.name}Where: ${relation.targetModel.name}Where, $${relation.name}Limit: Int${
fieldIsSearchable(model, relation.name) ? `, $${relation.name}Search: String` : ''
}`
)
.join(', ')}) {
${relations
.map((relation) => {
let filters = '';
if (relation.targetModel.displayField) {
const displayField = relation.targetModel.fieldsByName[relation.targetModel.displayField];
if (displayField.orderable) {
filters = `(orderBy: [{ ${relation.targetModel.displayField}: ASC }])`;
if ('orderable' in displayField && displayField.orderable) {
filters += `, orderBy: [{ ${relation.targetModel.displayField}: ASC }]`;
}
}
return `${relation.name}: ${relation.targetModel.pluralField}${filters} {
if (fieldIsSearchable(model, relation.name)) {
filters += `, search: $${relation.name}Search`;
}
return `${relation.name}: ${relation.targetModel.pluralField}(where: $${relation.name}Where, limit: $${
relation.name
}Limit${filters}) {
id
display: ${relation.targetModel.displayField || 'id'}
${additionalFields[relation.name] || ''}
}`;
})
.join(' ')}
Expand Down Expand Up @@ -160,11 +173,11 @@ export const getEntityListQuery = (
${root ? '$id: ID!,' : ''}
$limit: Int!,
$where: ${model.name}Where!,
${model.fields.some(({ searchable }) => searchable) ? '$search: String,' : ''}
${model.relations.some(({ field: { searchable } }) => searchable) ? '$search: String,' : ''}
) {
${root ? `root: ${typeToField(root.model.name)}(where: { id: $id }) {` : ''}
data: ${root ? root.reverseRelationName : model.pluralField}(limit: $limit, where: $where, ${
model.fields.some(({ searchable }) => searchable) ? ', search: $search' : ''
model.relations.some(({ field: { searchable } }) => searchable) ? ', search: $search' : ''
}) {
${displayField(model)}
${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name }) => name)}
Expand Down
14 changes: 9 additions & 5 deletions src/models/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,15 @@ export const isUpdatableBy = (role: string) => (field: EntityField) =>
export const isCreatableBy = (role: string) => (field: EntityField) =>
field.creatable && (field.creatable === true || !field.creatable.roles || field.creatable.roles.includes(role));

export const actionableRelations = (model: EntityModel, action: 'create' | 'update' | 'filter') =>
model.relations.filter(
(relation) =>
relation.field[`${action === 'filter' ? action : action.slice(0, -1)}able` as 'filterable' | 'creatable' | 'updatable']
);
export const getActionableRelations = (model: EntityModel, action: 'create' | 'update' | 'filter') =>
model.relations
.filter(
(relation) =>
relation.field[
`${action === 'filter' ? action : action.slice(0, -1)}able` as 'filterable' | 'creatable' | 'updatable'
]
)
.map(({ name }) => name);

export const summonByName = <T extends { name: string }>(array: T[], value: string) => summonByKey(array, 'name', value);

Expand Down
5 changes: 2 additions & 3 deletions tests/unit/__snapshots__/queries.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`queries getEntityRelationsQuery applies filters 1`] = `
"query UpdateSomeObjectRelations {
another: anotherObjects(orderBy: [{ name: ASC }]) {
"query SelectSomeObjectRelations($anotherWhere: AnotherObjectWhere, $anotherLimit: Int) {
another: anotherObjects(where: $anotherWhere, limit: $anotherLimit, orderBy: [{ name: ASC }]) {
id
display: name
}
}"
`;
5 changes: 3 additions & 2 deletions tests/unit/queries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { getEditEntityRelationsQuery } from '../../src';
import { getActionableRelations, getSelectEntityRelationsQuery } from '../../src';
import { models } from '../utils/models';

describe('queries', () => {
describe('getEntityRelationsQuery', () => {
it('applies filters', () => {
expect(getEditEntityRelationsQuery(models.getModel('SomeObject', 'entity'), 'update')).toMatchSnapshot();
const model = models.getModel('SomeObject', 'entity');
expect(getSelectEntityRelationsQuery(model, getActionableRelations(model, 'update'))).toMatchSnapshot();
});
});
});

0 comments on commit 4d0122e

Please sign in to comment.