mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Move system collection rows out of DB
This commit is contained in:
@@ -7,9 +7,6 @@ columns:
|
||||
type: string
|
||||
length: 64
|
||||
nullable: false
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
field:
|
||||
type: string
|
||||
length: 64
|
||||
@@ -25,9 +25,6 @@ columns:
|
||||
type: string
|
||||
length: 64
|
||||
nullable: false
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
item:
|
||||
type: string
|
||||
length: 255
|
||||
@@ -12,9 +12,6 @@ columns:
|
||||
type: string
|
||||
length: 64
|
||||
nullable: false
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
action:
|
||||
type: string
|
||||
length: 10
|
||||
@@ -19,9 +19,6 @@ columns:
|
||||
collection:
|
||||
type: string
|
||||
length: 64
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
search:
|
||||
type: string
|
||||
length: 100
|
||||
@@ -7,9 +7,6 @@ columns:
|
||||
type: string
|
||||
length: 64
|
||||
nullable: false
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
many_field:
|
||||
type: string
|
||||
length: 64
|
||||
@@ -21,9 +18,6 @@ columns:
|
||||
one_collection:
|
||||
type: string
|
||||
length: 64
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
one_field:
|
||||
type: string
|
||||
length: 64
|
||||
@@ -14,9 +14,6 @@ columns:
|
||||
type: string
|
||||
length: 64
|
||||
nullable: false
|
||||
references:
|
||||
table: directus_collections
|
||||
column: collection
|
||||
item:
|
||||
type: string
|
||||
length: 255
|
||||
@@ -25,33 +25,6 @@ type TableSeed = {
|
||||
};
|
||||
};
|
||||
|
||||
type RowSeed = {
|
||||
table: string;
|
||||
defaults: Record<string, any>;
|
||||
data: Record<string, any>[];
|
||||
};
|
||||
|
||||
type FieldSeed = {
|
||||
table: string;
|
||||
fields: {
|
||||
collection: string;
|
||||
field: string;
|
||||
special: string | null;
|
||||
interface: string | null;
|
||||
options: Record<string, any> | null;
|
||||
display: string | null;
|
||||
display_options: Record<string, any> | null;
|
||||
locked: boolean;
|
||||
readonly: boolean;
|
||||
hidden: boolean;
|
||||
sort: number | null;
|
||||
width: string | null;
|
||||
group: number | null;
|
||||
translations: Record<string, any> | null;
|
||||
note: string | null;
|
||||
}[];
|
||||
};
|
||||
|
||||
export default async function runSeed(database: Knex) {
|
||||
const exists = await database.schema.hasTable('directus_collections');
|
||||
|
||||
@@ -59,19 +32,13 @@ export default async function runSeed(database: Knex) {
|
||||
throw new Error('Database is already installed');
|
||||
}
|
||||
|
||||
await createTables(database);
|
||||
await insertRows(database);
|
||||
await insertFields(database);
|
||||
}
|
||||
|
||||
async function createTables(database: Knex) {
|
||||
const tableSeeds = await fse.readdir(path.resolve(__dirname, './01-tables/'));
|
||||
const tableSeeds = await fse.readdir(path.resolve(__dirname));
|
||||
|
||||
for (const tableSeedFile of tableSeeds) {
|
||||
const yamlRaw = await fse.readFile(
|
||||
path.resolve(__dirname, './01-tables', tableSeedFile),
|
||||
'utf8'
|
||||
);
|
||||
if (tableSeedFile === 'run.ts') continue;
|
||||
|
||||
const yamlRaw = await fse.readFile(path.resolve(__dirname, tableSeedFile), 'utf8');
|
||||
|
||||
const seedData = yaml.safeLoad(yamlRaw) as TableSeed;
|
||||
|
||||
await database.schema.createTable(seedData.table, (tableBuilder) => {
|
||||
@@ -129,60 +96,60 @@ async function createTables(database: Knex) {
|
||||
}
|
||||
}
|
||||
|
||||
async function insertRows(database: Knex) {
|
||||
const rowSeeds = await fse.readdir(path.resolve(__dirname, './02-rows/'));
|
||||
// async function insertRows(database: Knex) {
|
||||
// const rowSeeds = await fse.readdir(path.resolve(__dirname, './02-rows/'));
|
||||
|
||||
for (const rowSeedFile of rowSeeds) {
|
||||
const yamlRaw = await fse.readFile(
|
||||
path.resolve(__dirname, './02-rows', rowSeedFile),
|
||||
'utf8'
|
||||
);
|
||||
const seedData = yaml.safeLoad(yamlRaw) as RowSeed;
|
||||
// for (const rowSeedFile of rowSeeds) {
|
||||
// const yamlRaw = await fse.readFile(
|
||||
// path.resolve(__dirname, './02-rows', rowSeedFile),
|
||||
// 'utf8'
|
||||
// );
|
||||
// const seedData = yaml.safeLoad(yamlRaw) as RowSeed;
|
||||
|
||||
const dataWithDefaults = seedData.data.map((row) => {
|
||||
for (const [key, value] of Object.entries(row)) {
|
||||
if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
|
||||
row[key] = JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
// const dataWithDefaults = seedData.data.map((row) => {
|
||||
// for (const [key, value] of Object.entries(row)) {
|
||||
// if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
|
||||
// row[key] = JSON.stringify(value);
|
||||
// }
|
||||
// }
|
||||
|
||||
return merge({}, seedData.defaults, row);
|
||||
});
|
||||
// return merge({}, seedData.defaults, row);
|
||||
// });
|
||||
|
||||
await database.batchInsert(seedData.table, dataWithDefaults);
|
||||
}
|
||||
}
|
||||
// await database.batchInsert(seedData.table, dataWithDefaults);
|
||||
// }
|
||||
// }
|
||||
|
||||
async function insertFields(database: Knex) {
|
||||
const fieldSeeds = await fse.readdir(path.resolve(__dirname, './03-fields/'));
|
||||
// async function insertFields(database: Knex) {
|
||||
// const fieldSeeds = await fse.readdir(path.resolve(__dirname, './03-fields/'));
|
||||
|
||||
const defaultsYaml = await fse.readFile(
|
||||
path.resolve(__dirname, './03-fields/_defaults.yaml'),
|
||||
'utf8'
|
||||
);
|
||||
const defaults = yaml.safeLoad(defaultsYaml) as FieldSeed;
|
||||
// const defaultsYaml = await fse.readFile(
|
||||
// path.resolve(__dirname, './03-fields/_defaults.yaml'),
|
||||
// 'utf8'
|
||||
// );
|
||||
// const defaults = yaml.safeLoad(defaultsYaml) as FieldSeed;
|
||||
|
||||
for (const fieldSeedFile of fieldSeeds) {
|
||||
const yamlRaw = await fse.readFile(
|
||||
path.resolve(__dirname, './03-fields', fieldSeedFile),
|
||||
'utf8'
|
||||
);
|
||||
const seedData = yaml.safeLoad(yamlRaw) as FieldSeed;
|
||||
// for (const fieldSeedFile of fieldSeeds) {
|
||||
// const yamlRaw = await fse.readFile(
|
||||
// path.resolve(__dirname, './03-fields', fieldSeedFile),
|
||||
// 'utf8'
|
||||
// );
|
||||
// const seedData = yaml.safeLoad(yamlRaw) as FieldSeed;
|
||||
|
||||
if (fieldSeedFile === '_defaults.yaml') {
|
||||
continue;
|
||||
}
|
||||
// if (fieldSeedFile === '_defaults.yaml') {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
const dataWithDefaults = seedData.fields.map((row) => {
|
||||
for (const [key, value] of Object.entries(row)) {
|
||||
if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
|
||||
(row as any)[key] = JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
// const dataWithDefaults = seedData.fields.map((row) => {
|
||||
// for (const [key, value] of Object.entries(row)) {
|
||||
// if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
|
||||
// (row as any)[key] = JSON.stringify(value);
|
||||
// }
|
||||
// }
|
||||
|
||||
return merge({}, defaults, row);
|
||||
});
|
||||
// return merge({}, defaults, row);
|
||||
// });
|
||||
|
||||
await database.batchInsert('directus_fields', dataWithDefaults);
|
||||
}
|
||||
}
|
||||
// await database.batchInsert('directus_fields', dataWithDefaults);
|
||||
// }
|
||||
// }
|
||||
|
||||
11
api/src/database/system-data/collections/index.ts
Normal file
11
api/src/database/system-data/collections/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { requireYAML } from '../../../utils/require-yaml';
|
||||
import { merge } from 'lodash';
|
||||
import { CollectionMeta } from '../../../types';
|
||||
|
||||
const systemData = requireYAML(require.resolve('./collections.yaml'));
|
||||
|
||||
export const systemCollectionRows: CollectionMeta[] = systemData.data.map(
|
||||
(row: Record<string, any>) => {
|
||||
return merge({}, systemData.defaults, row);
|
||||
}
|
||||
);
|
||||
@@ -6,6 +6,8 @@ import { RequestHandler } from 'express';
|
||||
import asyncHandler from 'express-async-handler';
|
||||
import database from '../database';
|
||||
import { ForbiddenException } from '../exceptions';
|
||||
import { systemCollectionRows } from '../database/system-data/collections';
|
||||
import { Collection } from '../types';
|
||||
|
||||
const collectionExists: RequestHandler = asyncHandler(async (req, res, next) => {
|
||||
if (!req.params.collection) return next();
|
||||
@@ -18,13 +20,21 @@ const collectionExists: RequestHandler = asyncHandler(async (req, res, next) =>
|
||||
|
||||
req.collection = req.params.collection;
|
||||
|
||||
const collectionInfo = await database
|
||||
.select('singleton')
|
||||
.from('directus_collections')
|
||||
.where({ collection: req.collection })
|
||||
.first();
|
||||
if (req.collection.startsWith('directus_')) {
|
||||
const systemRow = systemCollectionRows.find((collection) => {
|
||||
return collection?.collection === req.collection;
|
||||
});
|
||||
|
||||
req.singleton = collectionInfo?.singleton === true || collectionInfo?.singleton === 1;
|
||||
req.singleton = !!systemRow?.singleton;
|
||||
} else {
|
||||
const collectionInfo = await database
|
||||
.select('singleton')
|
||||
.from('directus_collections')
|
||||
.where({ collection: req.collection })
|
||||
.first();
|
||||
|
||||
req.singleton = collectionInfo?.singleton === true || collectionInfo?.singleton === 1;
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import database, { schemaInspector } from '../database';
|
||||
import { AbstractServiceOptions, Accountability, Collection, Relation } from '../types';
|
||||
import {
|
||||
AbstractServiceOptions,
|
||||
Accountability,
|
||||
Collection,
|
||||
CollectionMeta,
|
||||
Relation,
|
||||
} from '../types';
|
||||
import Knex from 'knex';
|
||||
import { ForbiddenException, InvalidPayloadException } from '../exceptions';
|
||||
import SchemaInspector from 'knex-schema-inspector';
|
||||
@@ -7,6 +13,7 @@ import { FieldsService } from '../services/fields';
|
||||
import { ItemsService } from '../services/items';
|
||||
import cache from '../cache';
|
||||
import { toArray } from '../utils/to-array';
|
||||
import { systemCollectionRows } from '../database/system-data/collections';
|
||||
|
||||
export class CollectionsService {
|
||||
knex: Knex;
|
||||
@@ -106,6 +113,7 @@ export class CollectionsService {
|
||||
knex: this.knex,
|
||||
accountability: this.accountability,
|
||||
});
|
||||
|
||||
const collectionKeys = toArray(collection);
|
||||
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
@@ -135,7 +143,9 @@ export class CollectionsService {
|
||||
const tables = tablesInDatabase.filter((table) => collectionKeys.includes(table.name));
|
||||
const meta = (await collectionItemsService.readByQuery({
|
||||
filter: { collection: { _in: collectionKeys } },
|
||||
})) as Collection['meta'][];
|
||||
})) as CollectionMeta[];
|
||||
|
||||
meta.push(...systemCollectionRows);
|
||||
|
||||
const collections: Collection[] = [];
|
||||
|
||||
@@ -173,7 +183,9 @@ export class CollectionsService {
|
||||
const tablesToFetchInfoFor = tablesInDatabase.map((table) => table.name);
|
||||
const meta = (await collectionItemsService.readByQuery({
|
||||
filter: { collection: { _in: tablesToFetchInfoFor } },
|
||||
})) as Collection['meta'][];
|
||||
})) as CollectionMeta[];
|
||||
|
||||
meta.push(...systemCollectionRows);
|
||||
|
||||
const collections: Collection[] = [];
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
Field,
|
||||
Relation,
|
||||
Query,
|
||||
AbstractService,
|
||||
} from '../types';
|
||||
import {
|
||||
GraphQLString,
|
||||
@@ -49,6 +48,7 @@ import { UsersService } from './users';
|
||||
import { WebhooksService } from './webhooks';
|
||||
|
||||
import { getRelationType } from '../utils/get-relation-type';
|
||||
import { systemCollectionRows } from '../database/system-data/collections';
|
||||
|
||||
export class GraphQLService {
|
||||
accountability: Accountability | null;
|
||||
@@ -504,11 +504,16 @@ export class GraphQLService {
|
||||
});
|
||||
}
|
||||
|
||||
const collectionInfo = await this.knex
|
||||
.select('singleton')
|
||||
.from('directus_collections')
|
||||
.where({ collection: collection })
|
||||
.first();
|
||||
const collectionInfo =
|
||||
(await this.knex
|
||||
.select('singleton')
|
||||
.from('directus_collections')
|
||||
.where({ collection: collection })
|
||||
.first()) ||
|
||||
systemCollectionRows.find(
|
||||
(collectionMeta) => collectionMeta?.collection === collection
|
||||
);
|
||||
|
||||
const result =
|
||||
collectionInfo?.singleton === true
|
||||
? await service.readSingleton(query)
|
||||
|
||||
@@ -3,6 +3,7 @@ import database from '../database';
|
||||
import Knex from 'knex';
|
||||
import { InvalidPayloadException, ForbiddenException } from '../exceptions';
|
||||
import SchemaInspector from 'knex-schema-inspector';
|
||||
import { systemCollectionRows } from '../database/system-data/collections';
|
||||
|
||||
export class UtilsService {
|
||||
knex: Knex;
|
||||
@@ -16,11 +17,12 @@ export class UtilsService {
|
||||
async sort(collection: string, { item, to }: { item: PrimaryKey; to: PrimaryKey }) {
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
|
||||
const sortFieldResponse = await this.knex
|
||||
.select('sort_field')
|
||||
.from('directus_collections')
|
||||
.where({ collection })
|
||||
.first();
|
||||
const sortFieldResponse =
|
||||
(await this.knex
|
||||
.select('sort_field')
|
||||
.from('directus_collections')
|
||||
.where({ collection })
|
||||
.first()) || systemCollectionRows;
|
||||
|
||||
const sortField = sortFieldResponse?.sort_field;
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { Field } from './field';
|
||||
import { Table } from 'knex-schema-inspector/lib/types/table';
|
||||
|
||||
export type CollectionMeta = {
|
||||
collection: string;
|
||||
note: string | null;
|
||||
hidden: boolean;
|
||||
singleton: boolean;
|
||||
icon: string | null;
|
||||
translations: Record<string, string>;
|
||||
};
|
||||
|
||||
export type Collection = {
|
||||
collection: string;
|
||||
fields?: Field[];
|
||||
meta: {
|
||||
collection: string;
|
||||
note: string | null;
|
||||
hidden: boolean;
|
||||
singleton: boolean;
|
||||
icon: string | null;
|
||||
translations: Record<string, string>;
|
||||
} | null;
|
||||
meta: CollectionMeta | null;
|
||||
schema: Table;
|
||||
};
|
||||
|
||||
8
api/src/utils/require-yaml.ts
Normal file
8
api/src/utils/require-yaml.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import fse from 'fs-extra';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export function requireYAML(filepath: string) {
|
||||
const yamlRaw = fse.readFileSync(filepath, 'utf8');
|
||||
|
||||
return yaml.safeLoad(yamlRaw) as Record<string, any>;
|
||||
}
|
||||
Reference in New Issue
Block a user