@directus/api 21.0.0-rc.0 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/cache.d.ts +0 -1
- package/dist/cache.js +7 -22
- package/dist/controllers/tus.js +7 -5
- package/dist/database/get-ast-from-query/lib/parse-fields.d.ts +1 -1
- package/dist/database/get-ast-from-query/lib/parse-fields.js +10 -0
- package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/cockroachdb.js +4 -0
- package/dist/database/helpers/schema/dialects/mssql.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/mssql.js +4 -0
- package/dist/database/helpers/schema/dialects/oracle.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/oracle.js +4 -0
- package/dist/database/helpers/schema/dialects/postgres.d.ts +2 -1
- package/dist/database/helpers/schema/dialects/postgres.js +4 -0
- package/dist/database/helpers/schema/types.d.ts +5 -0
- package/dist/database/helpers/schema/types.js +3 -0
- package/dist/database/helpers/schema/utils/preprocess-bindings.d.ts +8 -0
- package/dist/database/helpers/schema/utils/preprocess-bindings.js +30 -0
- package/dist/database/index.js +14 -6
- package/dist/database/migrations/20240305A-change-useragent-type.js +1 -1
- package/dist/database/migrations/20240716A-update-files-date-fields.js +33 -0
- package/dist/database/migrations/20240806A-permissions-policies.d.ts +6 -0
- package/dist/database/migrations/20240806A-permissions-policies.js +338 -0
- package/dist/database/run-ast/lib/get-db-query.js +12 -2
- package/dist/database/run-ast/utils/apply-case-when.js +5 -4
- package/dist/database/run-ast/utils/with-preprocess-bindings.d.ts +2 -0
- package/dist/database/run-ast/utils/with-preprocess-bindings.js +14 -0
- package/dist/logger/index.js +1 -1
- package/dist/middleware/error-handler.d.ts +2 -2
- package/dist/middleware/error-handler.js +54 -51
- package/dist/permissions/lib/fetch-permissions.d.ts +1 -0
- package/dist/permissions/lib/fetch-permissions.js +3 -2
- package/dist/permissions/lib/fetch-policies.d.ts +7 -0
- package/dist/permissions/lib/fetch-policies.js +16 -1
- package/dist/permissions/modules/process-ast/lib/inject-cases.js +6 -6
- package/dist/permissions/modules/process-ast/types.d.ts +0 -6
- package/dist/permissions/modules/process-ast/utils/extract-paths-from-query.js +11 -1
- package/dist/permissions/utils/filter-policies-by-ip.d.ts +1 -1
- package/dist/services/assets.js +2 -5
- package/dist/services/fields.d.ts +3 -0
- package/dist/services/fields.js +29 -5
- package/dist/services/files/lib/get-sharp-instance.d.ts +2 -0
- package/dist/services/files/lib/get-sharp-instance.js +10 -0
- package/dist/services/files/utils/get-metadata.js +7 -6
- package/dist/services/files.js +5 -0
- package/dist/services/import-export.d.ts +3 -1
- package/dist/services/import-export.js +49 -5
- package/dist/services/mail/index.d.ts +1 -1
- package/dist/services/mail/index.js +9 -1
- package/dist/services/relations.d.ts +3 -1
- package/dist/services/relations.js +27 -5
- package/dist/services/tus/data-store.js +4 -5
- package/dist/services/tus/server.d.ts +1 -1
- package/dist/services/tus/server.js +9 -2
- package/dist/utils/apply-query.d.ts +8 -5
- package/dist/utils/apply-query.js +40 -5
- package/dist/utils/fetch-user-count/fetch-access-lookup.d.ts +2 -0
- package/dist/utils/fetch-user-count/fetch-access-lookup.js +3 -2
- package/dist/utils/fetch-user-count/fetch-user-count.js +10 -3
- package/dist/utils/fetch-user-count/get-user-count-query.js +1 -1
- package/dist/utils/get-schema.js +3 -3
- package/dist/utils/sanitize-schema.d.ts +1 -1
- package/package.json +38 -38
- package/dist/database/migrations/20240710A-permissions-policies.js +0 -169
- /package/dist/database/migrations/{20240710A-permissions-policies.d.ts → 20240716A-update-files-date-fields.d.ts} +0 -0
package/dist/app.js
CHANGED
|
@@ -50,7 +50,7 @@ import { createExpressLogger, useLogger } from './logger/index.js';
|
|
|
50
50
|
import authenticate from './middleware/authenticate.js';
|
|
51
51
|
import cache from './middleware/cache.js';
|
|
52
52
|
import cors from './middleware/cors.js';
|
|
53
|
-
import errorHandler from './middleware/error-handler.js';
|
|
53
|
+
import { errorHandler } from './middleware/error-handler.js';
|
|
54
54
|
import extractToken from './middleware/extract-token.js';
|
|
55
55
|
import rateLimiterGlobal from './middleware/rate-limiter-global.js';
|
|
56
56
|
import rateLimiter from './middleware/rate-limiter-ip.js';
|
package/dist/cache.d.ts
CHANGED
package/dist/cache.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
|
-
import { getSimpleHash } from '@directus/utils';
|
|
3
2
|
import Keyv from 'keyv';
|
|
4
3
|
import { useBus } from './bus/index.js';
|
|
5
4
|
import { useLogger } from './logger/index.js';
|
|
@@ -16,16 +15,16 @@ const require = createRequire(import.meta.url);
|
|
|
16
15
|
let cache = null;
|
|
17
16
|
let systemCache = null;
|
|
18
17
|
let localSchemaCache = null;
|
|
19
|
-
let sharedSchemaCache = null;
|
|
20
18
|
let lockCache = null;
|
|
21
19
|
let messengerSubscribed = false;
|
|
22
20
|
const messenger = useBus();
|
|
23
|
-
if (redisConfigAvailable() &&
|
|
21
|
+
if (redisConfigAvailable() && !messengerSubscribed) {
|
|
24
22
|
messengerSubscribed = true;
|
|
25
23
|
messenger.subscribe('schemaChanged', async (opts) => {
|
|
26
|
-
if (cache && opts?.['autoPurgeCache'] !== false) {
|
|
24
|
+
if (env['CACHE_STORE'] === 'memory' && env['CACHE_AUTO_PURGE'] && cache && opts?.['autoPurgeCache'] !== false) {
|
|
27
25
|
await cache.clear();
|
|
28
26
|
}
|
|
27
|
+
await localSchemaCache?.clear();
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
export function getCache() {
|
|
@@ -38,10 +37,6 @@ export function getCache() {
|
|
|
38
37
|
systemCache = getKeyvInstance(env['CACHE_STORE'], getMilliseconds(env['CACHE_SYSTEM_TTL']), '_system');
|
|
39
38
|
systemCache.on('error', (err) => logger.warn(err, `[system-cache] ${err}`));
|
|
40
39
|
}
|
|
41
|
-
if (sharedSchemaCache === null) {
|
|
42
|
-
sharedSchemaCache = getKeyvInstance(env['CACHE_STORE'], getMilliseconds(env['CACHE_SYSTEM_TTL']), '_schema_shared');
|
|
43
|
-
sharedSchemaCache.on('error', (err) => logger.warn(err, `[shared-schema-cache] ${err}`));
|
|
44
|
-
}
|
|
45
40
|
if (localSchemaCache === null) {
|
|
46
41
|
localSchemaCache = getKeyvInstance('memory', getMilliseconds(env['CACHE_SYSTEM_TTL']), '_schema');
|
|
47
42
|
localSchemaCache.on('error', (err) => logger.warn(err, `[schema-cache] ${err}`));
|
|
@@ -50,7 +45,7 @@ export function getCache() {
|
|
|
50
45
|
lockCache = getKeyvInstance(env['CACHE_STORE'], undefined, '_lock');
|
|
51
46
|
lockCache.on('error', (err) => logger.warn(err, `[lock-cache] ${err}`));
|
|
52
47
|
}
|
|
53
|
-
return { cache, systemCache,
|
|
48
|
+
return { cache, systemCache, localSchemaCache, lockCache };
|
|
54
49
|
}
|
|
55
50
|
export async function flushCaches(forced) {
|
|
56
51
|
const { cache } = getCache();
|
|
@@ -58,14 +53,13 @@ export async function flushCaches(forced) {
|
|
|
58
53
|
await cache?.clear();
|
|
59
54
|
}
|
|
60
55
|
export async function clearSystemCache(opts) {
|
|
61
|
-
const { systemCache, localSchemaCache, lockCache
|
|
56
|
+
const { systemCache, localSchemaCache, lockCache } = getCache();
|
|
62
57
|
// Flush system cache when forced or when system cache lock not set
|
|
63
58
|
if (opts?.forced || !(await lockCache.get('system-cache-lock'))) {
|
|
64
59
|
await lockCache.set('system-cache-lock', true, 10000);
|
|
65
60
|
await systemCache.clear();
|
|
66
61
|
await lockCache.delete('system-cache-lock');
|
|
67
62
|
}
|
|
68
|
-
await sharedSchemaCache.clear();
|
|
69
63
|
await localSchemaCache.clear();
|
|
70
64
|
// Since a lot of cached permission function rely on the schema it needs to be cleared as well
|
|
71
65
|
await clearPermissionCache();
|
|
@@ -82,20 +76,11 @@ export async function getSystemCache(key) {
|
|
|
82
76
|
return await getCacheValue(systemCache, key);
|
|
83
77
|
}
|
|
84
78
|
export async function setSchemaCache(schema) {
|
|
85
|
-
const { localSchemaCache
|
|
86
|
-
const schemaHash = getSimpleHash(JSON.stringify(schema));
|
|
87
|
-
await sharedSchemaCache.set('hash', schemaHash);
|
|
79
|
+
const { localSchemaCache } = getCache();
|
|
88
80
|
await localSchemaCache.set('schema', schema);
|
|
89
|
-
await localSchemaCache.set('hash', schemaHash);
|
|
90
81
|
}
|
|
91
82
|
export async function getSchemaCache() {
|
|
92
|
-
const { localSchemaCache
|
|
93
|
-
const sharedSchemaHash = await sharedSchemaCache.get('hash');
|
|
94
|
-
if (!sharedSchemaHash)
|
|
95
|
-
return;
|
|
96
|
-
const localSchemaHash = await localSchemaCache.get('hash');
|
|
97
|
-
if (!localSchemaHash || localSchemaHash !== sharedSchemaHash)
|
|
98
|
-
return;
|
|
83
|
+
const { localSchemaCache } = getCache();
|
|
99
84
|
return await localSchemaCache.get('schema');
|
|
100
85
|
}
|
|
101
86
|
export async function setCacheValue(cache, key, value, ttl) {
|
package/dist/controllers/tus.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
+
import { RESUMABLE_UPLOADS } from '../constants.js';
|
|
2
3
|
import getDatabase from '../database/index.js';
|
|
3
4
|
import { validateAccess } from '../permissions/modules/validate-access/validate-access.js';
|
|
4
|
-
import { getSchema } from '../utils/get-schema.js';
|
|
5
|
-
import { scheduleSynchronizedJob, validateCron } from '../utils/schedule.js';
|
|
6
5
|
import { createTusServer } from '../services/tus/index.js';
|
|
7
6
|
import asyncHandler from '../utils/async-handler.js';
|
|
8
|
-
import {
|
|
7
|
+
import { getSchema } from '../utils/get-schema.js';
|
|
8
|
+
import { scheduleSynchronizedJob, validateCron } from '../utils/schedule.js';
|
|
9
9
|
const mapAction = (method) => {
|
|
10
10
|
switch (method) {
|
|
11
11
|
case 'POST':
|
|
@@ -33,21 +33,23 @@ const checkFileAccess = asyncHandler(async (req, _res, next) => {
|
|
|
33
33
|
return next();
|
|
34
34
|
});
|
|
35
35
|
const handler = asyncHandler(async (req, res) => {
|
|
36
|
-
const tusServer = await createTusServer({
|
|
36
|
+
const [tusServer, cleanupServer] = await createTusServer({
|
|
37
37
|
schema: req.schema,
|
|
38
38
|
accountability: req.accountability,
|
|
39
39
|
});
|
|
40
40
|
await tusServer.handle(req, res);
|
|
41
|
+
cleanupServer();
|
|
41
42
|
});
|
|
42
43
|
export function scheduleTusCleanup() {
|
|
43
44
|
if (!RESUMABLE_UPLOADS.ENABLED)
|
|
44
45
|
return;
|
|
45
46
|
if (validateCron(RESUMABLE_UPLOADS.SCHEDULE)) {
|
|
46
47
|
scheduleSynchronizedJob('tus-cleanup', RESUMABLE_UPLOADS.SCHEDULE, async () => {
|
|
47
|
-
const tusServer = await createTusServer({
|
|
48
|
+
const [tusServer, cleanupServer] = await createTusServer({
|
|
48
49
|
schema: await getSchema(),
|
|
49
50
|
});
|
|
50
51
|
await tusServer.cleanUpExpiredUploads();
|
|
52
|
+
cleanupServer();
|
|
51
53
|
});
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -12,4 +12,4 @@ export interface ParseFieldsContext {
|
|
|
12
12
|
schema: SchemaOverview;
|
|
13
13
|
knex: Knex;
|
|
14
14
|
}
|
|
15
|
-
export declare function parseFields(options: ParseFieldsOptions, context: ParseFieldsContext): Promise<(NestedCollectionNode | FieldNode | FunctionFieldNode)[]>;
|
|
15
|
+
export declare function parseFields(options: ParseFieldsOptions, context: ParseFieldsContext): Promise<[] | (NestedCollectionNode | FieldNode | FunctionFieldNode)[]>;
|
|
@@ -88,6 +88,16 @@ export async function parseFields(options, context) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
if (name.includes(':')) {
|
|
92
|
+
const [key, scope] = name.split(':');
|
|
93
|
+
if (key in relationalStructure === false) {
|
|
94
|
+
relationalStructure[key] = { [scope]: [] };
|
|
95
|
+
}
|
|
96
|
+
else if (scope in relationalStructure[key] === false) {
|
|
97
|
+
relationalStructure[key][scope] = [];
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
91
101
|
children.push({ type: 'field', name, fieldKey, whenCase: [] });
|
|
92
102
|
}
|
|
93
103
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { KNEX_TYPES } from '@directus/constants';
|
|
2
|
-
import type { Options } from '../types.js';
|
|
2
|
+
import type { Options, Sql } from '../types.js';
|
|
3
3
|
import { SchemaHelper } from '../types.js';
|
|
4
4
|
export declare class SchemaHelperCockroachDb extends SchemaHelper {
|
|
5
5
|
changeToType(table: string, column: string, type: (typeof KNEX_TYPES)[number], options?: Options): Promise<void>;
|
|
6
6
|
constraintName(existingName: string): string;
|
|
7
7
|
getDatabaseSize(): Promise<number | null>;
|
|
8
|
+
preprocessBindings(queryParams: Sql): Sql;
|
|
8
9
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SchemaHelper } from '../types.js';
|
|
2
2
|
import { useEnv } from '@directus/env';
|
|
3
|
+
import { preprocessBindings } from '../utils/preprocess-bindings.js';
|
|
3
4
|
const env = useEnv();
|
|
4
5
|
export class SchemaHelperCockroachDb extends SchemaHelper {
|
|
5
6
|
async changeToType(table, column, type, options = {}) {
|
|
@@ -27,4 +28,7 @@ export class SchemaHelperCockroachDb extends SchemaHelper {
|
|
|
27
28
|
return null;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
31
|
+
preprocessBindings(queryParams) {
|
|
32
|
+
return preprocessBindings(queryParams, { format: (index) => `$${index + 1}` });
|
|
33
|
+
}
|
|
30
34
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import { SchemaHelper } from '../types.js';
|
|
2
|
+
import { SchemaHelper, type Sql } from '../types.js';
|
|
3
3
|
export declare class SchemaHelperMSSQL extends SchemaHelper {
|
|
4
4
|
applyLimit(rootQuery: Knex.QueryBuilder, limit: number): void;
|
|
5
5
|
applyOffset(rootQuery: Knex.QueryBuilder, offset: number): void;
|
|
6
6
|
formatUUID(uuid: string): string;
|
|
7
7
|
getDatabaseSize(): Promise<number | null>;
|
|
8
|
+
preprocessBindings(queryParams: Sql): Sql;
|
|
8
9
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SchemaHelper } from '../types.js';
|
|
2
|
+
import { preprocessBindings } from '../utils/preprocess-bindings.js';
|
|
2
3
|
export class SchemaHelperMSSQL extends SchemaHelper {
|
|
3
4
|
applyLimit(rootQuery, limit) {
|
|
4
5
|
// The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries,
|
|
@@ -26,4 +27,7 @@ export class SchemaHelperMSSQL extends SchemaHelper {
|
|
|
26
27
|
return null;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
preprocessBindings(queryParams) {
|
|
31
|
+
return preprocessBindings(queryParams, { format: (index) => `@p${index}` });
|
|
32
|
+
}
|
|
29
33
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { KNEX_TYPES } from '@directus/constants';
|
|
2
2
|
import type { Field, Relation, Type } from '@directus/types';
|
|
3
|
-
import type { Options } from '../types.js';
|
|
3
|
+
import type { Options, Sql } from '../types.js';
|
|
4
4
|
import { SchemaHelper } from '../types.js';
|
|
5
5
|
export declare class SchemaHelperOracle extends SchemaHelper {
|
|
6
6
|
changeToType(table: string, column: string, type: (typeof KNEX_TYPES)[number], options?: Options): Promise<void>;
|
|
@@ -8,4 +8,5 @@ export declare class SchemaHelperOracle extends SchemaHelper {
|
|
|
8
8
|
preRelationChange(relation: Partial<Relation>): void;
|
|
9
9
|
processFieldType(field: Field): Type;
|
|
10
10
|
getDatabaseSize(): Promise<number | null>;
|
|
11
|
+
preprocessBindings(queryParams: Sql): Sql;
|
|
11
12
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SchemaHelper } from '../types.js';
|
|
2
|
+
import { preprocessBindings } from '../utils/preprocess-bindings.js';
|
|
2
3
|
export class SchemaHelperOracle extends SchemaHelper {
|
|
3
4
|
async changeToType(table, column, type, options = {}) {
|
|
4
5
|
await this.changeToTypeByCopy(table, column, type, options);
|
|
@@ -38,4 +39,7 @@ export class SchemaHelperOracle extends SchemaHelper {
|
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
preprocessBindings(queryParams) {
|
|
43
|
+
return preprocessBindings(queryParams, { format: (index) => `:${index + 1}` });
|
|
44
|
+
}
|
|
41
45
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import { SchemaHelper } from '../types.js';
|
|
3
|
+
import { preprocessBindings } from '../utils/preprocess-bindings.js';
|
|
3
4
|
const env = useEnv();
|
|
4
5
|
export class SchemaHelperPostgres extends SchemaHelper {
|
|
5
6
|
async getDatabaseSize() {
|
|
@@ -11,4 +12,7 @@ export class SchemaHelperPostgres extends SchemaHelper {
|
|
|
11
12
|
return null;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
15
|
+
preprocessBindings(queryParams) {
|
|
16
|
+
return preprocessBindings(queryParams, { format: (index) => `$${index + 1}` });
|
|
17
|
+
}
|
|
14
18
|
}
|
|
@@ -8,6 +8,10 @@ export type Options = {
|
|
|
8
8
|
default?: any;
|
|
9
9
|
length?: number;
|
|
10
10
|
};
|
|
11
|
+
export type Sql = {
|
|
12
|
+
sql: string;
|
|
13
|
+
bindings: readonly Knex.Value[];
|
|
14
|
+
};
|
|
11
15
|
export declare abstract class SchemaHelper extends DatabaseHelper {
|
|
12
16
|
isOneOfClients(clients: DatabaseClient[]): boolean;
|
|
13
17
|
changeNullable(table: string, column: string, nullable: boolean): Promise<void>;
|
|
@@ -27,4 +31,5 @@ export declare abstract class SchemaHelper extends DatabaseHelper {
|
|
|
27
31
|
* @returns Size of the database in bytes
|
|
28
32
|
*/
|
|
29
33
|
getDatabaseSize(): Promise<number | null>;
|
|
34
|
+
preprocessBindings(queryParams: Sql): Sql;
|
|
30
35
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Sql } from '../types.js';
|
|
2
|
+
export type PreprocessBindingsOptions = {
|
|
3
|
+
format(index: number): string;
|
|
4
|
+
};
|
|
5
|
+
export declare function preprocessBindings(queryParams: (Partial<Sql> & Pick<Sql, 'sql'>) | string, options: PreprocessBindingsOptions): {
|
|
6
|
+
sql: string;
|
|
7
|
+
bindings: import("knex").Knex.Value[];
|
|
8
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isString } from 'lodash-es';
|
|
2
|
+
export function preprocessBindings(queryParams, options) {
|
|
3
|
+
const query = { bindings: [], ...(isString(queryParams) ? { sql: queryParams } : queryParams) };
|
|
4
|
+
const bindingIndices = new Array(query.bindings.length);
|
|
5
|
+
for (let i = 0; i < query.bindings.length; i++) {
|
|
6
|
+
const binding = query.bindings[i];
|
|
7
|
+
const prevIndex = query.bindings.findIndex((b, j) => j < i && b === binding);
|
|
8
|
+
if (prevIndex !== -1) {
|
|
9
|
+
bindingIndices[i] = prevIndex;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
bindingIndices[i] = i;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
let matchIndex = 0;
|
|
16
|
+
let currentBindingIndex = 0;
|
|
17
|
+
const sql = query.sql.replace(/(\\*)(\?)/g, function (_, escapes) {
|
|
18
|
+
if (escapes.length % 2) {
|
|
19
|
+
// Return an escaped question mark, so it stays escaped
|
|
20
|
+
return `${'\\'.repeat(escapes.length)}?`;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const bindingIndex = bindingIndices[matchIndex] === matchIndex ? currentBindingIndex++ : bindingIndices[matchIndex];
|
|
24
|
+
matchIndex++;
|
|
25
|
+
return options.format(bindingIndex);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const bindings = query.bindings.filter((_, i) => bindingIndices[i] === i);
|
|
29
|
+
return { ...query, sql, bindings };
|
|
30
|
+
}
|
package/dist/database/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEnv } from '@directus/env';
|
|
2
2
|
import { createInspector } from '@directus/schema';
|
|
3
|
+
import { isObject } from '@directus/utils';
|
|
3
4
|
import fse from 'fs-extra';
|
|
4
5
|
import knex from 'knex';
|
|
5
6
|
import { merge } from 'lodash-es';
|
|
@@ -106,6 +107,9 @@ export function getDatabase() {
|
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
if (client === 'mysql') {
|
|
110
|
+
// Remove the conflicting `filename` option, defined by default in the Docker Image
|
|
111
|
+
if (isObject(knexConfig.connection))
|
|
112
|
+
delete knexConfig.connection['filename'];
|
|
109
113
|
Object.assign(knexConfig, { client: 'mysql2' });
|
|
110
114
|
poolConfig.afterCreate = async (conn, callback) => {
|
|
111
115
|
logger.trace('Retrieving database version');
|
|
@@ -123,15 +127,19 @@ export function getDatabase() {
|
|
|
123
127
|
}
|
|
124
128
|
database = knex.default(knexConfig);
|
|
125
129
|
validateDatabaseCharset(database);
|
|
126
|
-
const times =
|
|
130
|
+
const times = new Map();
|
|
127
131
|
database
|
|
128
|
-
.on('query', (
|
|
129
|
-
times
|
|
132
|
+
.on('query', ({ __knexUid }) => {
|
|
133
|
+
times.set(__knexUid, performance.now());
|
|
130
134
|
})
|
|
131
135
|
.on('query-response', (_response, queryInfo) => {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
const time = times.get(queryInfo.__knexUid);
|
|
137
|
+
let delta;
|
|
138
|
+
if (time) {
|
|
139
|
+
delta = performance.now() - time;
|
|
140
|
+
times.delete(queryInfo.__knexUid);
|
|
141
|
+
}
|
|
142
|
+
logger.trace(`[${delta ? delta.toFixed(3) : '?'}ms] ${queryInfo.sql} [${(queryInfo.bindings ?? []).join(', ')}]`);
|
|
135
143
|
});
|
|
136
144
|
return database;
|
|
137
145
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getHelpers } from '../helpers/index.js';
|
|
2
|
+
export async function up(knex) {
|
|
3
|
+
const helper = getHelpers(knex).schema;
|
|
4
|
+
const isMysql = helper.isOneOfClients(['mysql']);
|
|
5
|
+
if (isMysql) {
|
|
6
|
+
// Knex creates invalid statement on MySQL, see https://github.com/knex/knex/issues/1888
|
|
7
|
+
await knex.schema.raw('ALTER TABLE `directus_files` CHANGE `uploaded_on` `created_on` TIMESTAMP NOT NULL DEFAULT current_timestamp();');
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
11
|
+
table.renameColumn('uploaded_on', 'created_on');
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
15
|
+
table.timestamp('uploaded_on');
|
|
16
|
+
});
|
|
17
|
+
await knex('directus_files').update('uploaded_on', knex.ref('created_on'));
|
|
18
|
+
}
|
|
19
|
+
export async function down(knex) {
|
|
20
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
21
|
+
table.dropColumn('uploaded_on');
|
|
22
|
+
});
|
|
23
|
+
const helper = getHelpers(knex).schema;
|
|
24
|
+
const isMysql = helper.isOneOfClients(['mysql']);
|
|
25
|
+
if (isMysql) {
|
|
26
|
+
await knex.schema.raw('ALTER TABLE `directus_files` CHANGE `created_on` `uploaded_on` TIMESTAMP NOT NULL DEFAULT current_timestamp();');
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
await knex.schema.alterTable('directus_files', (table) => {
|
|
30
|
+
table.renameColumn('created_on', 'uploaded_on');
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
import type { Permission } from '@directus/types';
|
|
3
|
+
export declare function mergePermissions(strategy: 'and' | 'or', ...permissions: Permission[][]): any[];
|
|
4
|
+
export declare function mergePermission(strategy: 'and' | 'or', currentPerm: Permission, newPerm: Permission): Omit<Permission, 'id' | 'system'>;
|
|
5
|
+
export declare function up(knex: Knex): Promise<void>;
|
|
6
|
+
export declare function down(knex: Knex): Promise<void>;
|