Add toArray util

This commit is contained in:
rijkvanzanten
2020-10-15 18:00:27 -04:00
parent cac329c783
commit 592ab925db
13 changed files with 44 additions and 29 deletions

View File

@@ -12,6 +12,7 @@ import { UsersService, AuthenticationService } from '../services';
import grantConfig from '../grant';
import { RouteNotFoundException } from '../exceptions';
import { respond } from '../middleware/respond';
import { toArray } from '../utils/to-array';
const router = Router();
@@ -213,7 +214,7 @@ router.post(
router.get(
'/oauth',
asyncHandler(async (req, res, next) => {
const providers = env.OAUTH_PROVIDERS as string[];
const providers = toArray(env.OAUTH_PROVIDERS);
res.locals.payload = { data: providers.length > 0 ? providers : null };
return next();
}),

View File

@@ -6,6 +6,7 @@ import { Query, Item } from '../types';
import { PayloadService } from '../services/payload';
import applyQuery from '../utils/apply-query';
import Knex, { QueryBuilder } from 'knex';
import { toArray } from '../utils/to-array';
type RunASTOptions = {
query?: AST['query'];
@@ -172,7 +173,7 @@ function applyParentFilters(
nestedCollectionNodes: NestedCollectionNode[],
parentItem: Item | Item[]
) {
const parentItems = Array.isArray(parentItem) ? parentItem : [parentItem];
const parentItems = toArray(parentItem);
for (const nestedNode of nestedCollectionNodes) {
if (!nestedNode.relation) continue;
@@ -245,8 +246,8 @@ function mergeWithParentItems(
nestedNode: NestedCollectionNode,
o2mLimit?: number | null
) {
const nestedItems = Array.isArray(nestedItem) ? nestedItem : [nestedItem];
const parentItems = clone(Array.isArray(parentItem) ? parentItem : [parentItem]);
const nestedItems = toArray(nestedItem);
const parentItems = clone(toArray(parentItem));
if (nestedNode.type === 'm2o') {
for (const parentItem of parentItems) {
@@ -307,7 +308,7 @@ function removeTemporaryFields(
primaryKeyField: string,
parentItem?: Item
): null | Item | Item[] {
const rawItems = cloneDeep(Array.isArray(rawItem) ? rawItem : [rawItem]);
const rawItems = cloneDeep(toArray(rawItem));
const items: Item[] = [];
if (ast.type === 'm2a') {

View File

@@ -2,13 +2,14 @@ import { ErrorRequestHandler } from 'express';
import { BaseException } from '../exceptions';
import logger from '../logger';
import env from '../env';
import { toArray } from '../utils/to-array';
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
let payload: any = {
errors: [],
};
const errors = Array.isArray(err) ? err : [err];
const errors = toArray(err);
if (errors.some((err) => err instanceof BaseException === false)) {
res.status(500);

View File

@@ -18,6 +18,7 @@ import { uniq, merge, flatten } from 'lodash';
import generateJoi from '../utils/generate-joi';
import { ItemsService } from './items';
import { parseFilter } from '../utils/parse-filter';
import { toArray } from '../utils/to-array';
export class AuthorizationService {
knex: Knex;
@@ -199,7 +200,7 @@ export class AuthorizationService {
): Promise<Partial<Item>[] | Partial<Item>> {
const validationErrors: FailedValidationException[] = [];
let payloads = Array.isArray(payload) ? payload : [payload];
let payloads = toArray(payload);
let permission: Permission | undefined;

View File

@@ -6,6 +6,7 @@ import SchemaInspector from 'knex-schema-inspector';
import { FieldsService } from '../services/fields';
import { ItemsService } from '../services/items';
import cache from '../cache';
import { toArray } from '../utils/to-array';
export class CollectionsService {
knex: Knex;
@@ -23,7 +24,7 @@ export class CollectionsService {
throw new ForbiddenException('Only admins can perform this action.');
}
const payloads = (Array.isArray(data) ? data : [data]).map((collection) => {
const payloads = toArray(data).map((collection) => {
if (!collection.fields) collection.fields = [];
collection.fields = collection.fields.map((field) => {
@@ -105,7 +106,7 @@ export class CollectionsService {
knex: this.knex,
accountability: this.accountability,
});
const collectionKeys = Array.isArray(collection) ? collection : [collection];
const collectionKeys = toArray(collection);
if (this.accountability && this.accountability.admin !== true) {
const permissions = await this.knex
@@ -212,7 +213,7 @@ export class CollectionsService {
throw new InvalidPayloadException(`"meta" key is required`);
}
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
for (const key of keys) {
const exists =
@@ -232,7 +233,7 @@ export class CollectionsService {
return key;
}
const payloads = Array.isArray(data) ? data : [data];
const payloads = toArray(data);
const collectionUpdates = payloads.map((collection) => {
return {
@@ -264,7 +265,7 @@ export class CollectionsService {
const tablesInDatabase = await schemaInspector.tables();
const collectionKeys = Array.isArray(collection) ? collection : [collection];
const collectionKeys = toArray(collection);
for (const collectionKey of collectionKeys) {
if (tablesInDatabase.includes(collectionKey) === false) {

View File

@@ -9,6 +9,7 @@ import { AbstractServiceOptions, File, PrimaryKey } from '../types';
import { clone } from 'lodash';
import cache from '../cache';
import { ForbiddenException } from '../exceptions';
import { toArray } from '../utils/to-array';
export class FilesService extends ItemsService {
constructor(options?: AbstractServiceOptions) {
@@ -89,14 +90,14 @@ export class FilesService extends ItemsService {
delete(key: PrimaryKey): Promise<PrimaryKey>;
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
let files = await super.readByKey(keys, { fields: ['id', 'storage'] });
if (!files) {
throw new ForbiddenException();
}
files = Array.isArray(files) ? files : [files];
files = toArray(files);
for (const file of files) {
const disk = storage.disk(file.storage);

View File

@@ -16,6 +16,7 @@ import Knex from 'knex';
import cache from '../cache';
import emitter from '../emitter';
import logger from '../logger';
import { toArray } from '../utils/to-array';
import { PayloadService } from './payload';
import { AuthorizationService } from './authorization';
@@ -50,7 +51,7 @@ export class ItemsService implements AbstractService {
const primaryKeyField = await this.schemaInspector.primary(this.collection);
const columns = await this.schemaInspector.columns(this.collection);
let payloads = clone(Array.isArray(data) ? data : [data]);
let payloads = clone(toArray(data));
const savedPrimaryKeys = await this.knex.transaction(async (trx) => {
const payloadService = new PayloadService(this.collection, {
@@ -224,7 +225,7 @@ export class ItemsService implements AbstractService {
): Promise<null | Item | Item[]> {
query = clone(query);
const primaryKeyField = await this.schemaInspector.primary(this.collection);
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
if (keys.length === 1) {
query.single = true;
@@ -270,7 +271,7 @@ export class ItemsService implements AbstractService {
// Updating one or more items to the same payload
if (data && key) {
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
let payload = clone(data);
@@ -404,7 +405,7 @@ export class ItemsService implements AbstractService {
knex: trx,
});
const payloads = Array.isArray(data) ? data : [data];
const payloads = toArray(data);
for (const single of payloads as Partial<Item>[]) {
let payload = clone(single);
@@ -432,7 +433,7 @@ export class ItemsService implements AbstractService {
const itemsService = new ItemsService(this.collection, { knex: this.knex });
let itemsToUpdate = await itemsService.readByQuery(readQuery);
itemsToUpdate = Array.isArray(itemsToUpdate) ? itemsToUpdate : [itemsToUpdate];
itemsToUpdate = toArray(itemsToUpdate);
const keys: PrimaryKey[] = itemsToUpdate.map(
(item: Partial<Item>) => item[primaryKeyField]
@@ -445,7 +446,7 @@ export class ItemsService implements AbstractService {
upsert(data: Partial<Item>): Promise<PrimaryKey>;
async upsert(data: Partial<Item> | Partial<Item>[]): Promise<PrimaryKey | PrimaryKey[]> {
const primaryKeyField = await this.schemaInspector.primary(this.collection);
const payloads = Array.isArray(data) ? data : [data];
const payloads = toArray(data);
const primaryKeys: PrimaryKey[] = [];
for (const payload of payloads) {
@@ -473,7 +474,7 @@ export class ItemsService implements AbstractService {
delete(key: PrimaryKey): Promise<PrimaryKey>;
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
const keys = (Array.isArray(key) ? key : [key]) as PrimaryKey[];
const keys = toArray(key);
const primaryKeyField = await this.schemaInspector.primary(this.collection);
if (this.accountability && this.accountability.admin !== true) {
@@ -537,7 +538,7 @@ export class ItemsService implements AbstractService {
const itemsService = new ItemsService(this.collection);
let itemsToDelete = await itemsService.readByQuery(readQuery);
itemsToDelete = Array.isArray(itemsToDelete) ? itemsToDelete : [itemsToDelete];
itemsToDelete = toArray(itemsToDelete);
const keys: PrimaryKey[] = itemsToDelete.map(
(item: Partial<Item>) => item[primaryKeyField]

View File

@@ -16,6 +16,7 @@ import SchemaInspector from 'knex-schema-inspector';
import getLocalType from '../utils/get-local-type';
import { format, formatISO } from 'date-fns';
import { ForbiddenException } from '../exceptions';
import { toArray } from '../utils/to-array';
type Action = 'create' | 'read' | 'update';
@@ -141,7 +142,7 @@ export class PayloadService {
action: Action,
payload: Partial<Item> | Partial<Item>[]
): Promise<Partial<Item> | Partial<Item>[]> {
let processedPayload = (Array.isArray(payload) ? payload : [payload]) as Partial<Item>[];
let processedPayload = toArray(payload);
if (processedPayload.length === 0) return [];
@@ -338,7 +339,7 @@ export class PayloadService {
.from('directus_relations')
.where({ one_collection: this.collection });
const payloads = clone(Array.isArray(payload) ? payload : [payload]);
const payloads = clone(toArray(payload));
for (let i = 0; i < payloads.length; i++) {
let payload = payloads[i];

View File

@@ -1,6 +1,7 @@
import { ItemsService } from './items';
import { AbstractServiceOptions, Query, PrimaryKey, PermissionsAction, Relation } from '../types';
import { PermissionsService } from './permissions';
import { toArray } from '../utils/to-array';
/**
* @TODO update foreign key constraints when relations are updated
@@ -62,7 +63,7 @@ export class RelationsService extends ItemsService {
'read'
);
relations = Array.isArray(relations) ? relations : [relations];
relations = toArray(relations);
return relations.filter((relation) => {
let collectionsAllowed = true;

View File

@@ -4,6 +4,7 @@ import { PermissionsService } from './permissions';
import { UsersService } from './users';
import { PresetsService } from './presets';
import { UnprocessableEntityException } from '../exceptions';
import { toArray } from '../utils/to-array';
export class RolesService extends ItemsService {
constructor(options?: AbstractServiceOptions) {
@@ -13,7 +14,7 @@ export class RolesService extends ItemsService {
delete(key: PrimaryKey): Promise<PrimaryKey>;
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
// Make sure there's at least one admin role left after this deletion is done
const otherAdminRoles = await this.knex

View File

@@ -13,6 +13,7 @@ import { Accountability, PrimaryKey, Item, AbstractServiceOptions } from '../typ
import Knex from 'knex';
import env from '../env';
import cache from '../cache';
import { toArray } from '../utils/to-array';
export class UsersService extends ItemsService {
knex: Knex;
@@ -39,7 +40,7 @@ export class UsersService extends ItemsService {
* This is just an extra bit of hardcoded security. We don't want anybody to be able to disable 2fa through
* the regular /users endpoint. Period. You should only be able to manage the 2fa status through the /tfa endpoint.
*/
const payloads = Array.isArray(data) ? data : [data];
const payloads = toArray(data);
for (const payload of payloads) {
if (payload.hasOwnProperty('tfa_secret')) {
@@ -57,7 +58,7 @@ export class UsersService extends ItemsService {
delete(key: PrimaryKey): Promise<PrimaryKey>;
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
const keys = Array.isArray(key) ? key : [key];
const keys = toArray(key);
// Make sure there's at least one admin user left after this deletion is done
const otherAdminUsers = await this.knex

View File

@@ -7,6 +7,7 @@ import {
import env from './env';
import { validateEnv } from './utils/validate-env';
import { getConfigFromEnv } from './utils/get-config-from-env';
import { toArray } from './utils/to-array';
/** @todo dynamically load these storage adapters */
import { AmazonWebServicesS3Storage } from '@slynova/flydrive-s3';
@@ -25,7 +26,7 @@ function getStorageConfig(): StorageManagerConfig {
disks: {},
};
const locations = env.STORAGE_LOCATIONS as string[];
const locations = toArray(env.STORAGE_LOCATIONS);
locations.forEach((location: string) => {
location = location.trim();

View File

@@ -0,0 +1,3 @@
export function toArray<T = any>(val: T | T[]): T[] {
return Array.isArray(val) ? val : [val];
}