mirror of
https://github.com/strapi/strapi.git
synced 2025-10-29 17:04:13 +00:00
Refactor types
This commit is contained in:
parent
22ea624841
commit
e01234c008
@ -1,11 +1,9 @@
|
|||||||
/* eslint-disable import/no-extraneous-dependencies */
|
|
||||||
|
|
||||||
import knex, { Knex } from 'knex';
|
import knex, { Knex } from 'knex';
|
||||||
|
|
||||||
import SqliteClient from 'knex/lib/dialects/sqlite3/index';
|
import SqliteClient from 'knex/lib/dialects/sqlite3/index';
|
||||||
|
|
||||||
class LegacySqliteClient extends SqliteClient {
|
class LegacySqliteClient extends SqliteClient {
|
||||||
_driver() {
|
_driver() {
|
||||||
|
/* eslint-disable-next-line import/no-extraneous-dependencies */
|
||||||
return require('sqlite3');
|
return require('sqlite3');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { isString } from 'lodash/fp';
|
import { isString } from 'lodash/fp';
|
||||||
import type { Database } from '..';
|
import type { Database } from '..';
|
||||||
import type { ID } from '../typings';
|
import type { ID } from '../types';
|
||||||
|
|
||||||
type Params = Record<string, unknown>;
|
type Params = Record<string, unknown>;
|
||||||
type Data = Record<string, unknown>;
|
type Data = Record<string, unknown>;
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import {
|
|||||||
} from 'lodash/fp';
|
} from 'lodash/fp';
|
||||||
|
|
||||||
import { mapAsync } from '@strapi/utils';
|
import { mapAsync } from '@strapi/utils';
|
||||||
import * as types from '../types';
|
import * as types from '../utils/types';
|
||||||
import { createField } from '../fields';
|
import { createField } from '../fields';
|
||||||
import { createQueryBuilder } from '../query';
|
import { createQueryBuilder } from '../query';
|
||||||
import { createRepository } from './entity-repository';
|
import { createRepository } from './entity-repository';
|
||||||
@ -38,7 +38,7 @@ import {
|
|||||||
isOneToAny,
|
isOneToAny,
|
||||||
hasOrderColumn,
|
hasOrderColumn,
|
||||||
hasInverseOrderColumn,
|
hasInverseOrderColumn,
|
||||||
} from '../metadata/relations';
|
} from '../metadata';
|
||||||
import {
|
import {
|
||||||
deletePreviousOneToAnyRelations,
|
deletePreviousOneToAnyRelations,
|
||||||
deletePreviousAnyToOneRelations,
|
deletePreviousAnyToOneRelations,
|
||||||
@ -52,8 +52,8 @@ import {
|
|||||||
} from './relations/cloning/regular-relations';
|
} from './relations/cloning/regular-relations';
|
||||||
import { DatabaseError } from '../errors';
|
import { DatabaseError } from '../errors';
|
||||||
import type { Database } from '..';
|
import type { Database } from '..';
|
||||||
import type { Meta } from '../metadata/types';
|
import type { Meta } from '../metadata';
|
||||||
import type { ID } from '../typings';
|
import type { ID } from '../types';
|
||||||
|
|
||||||
type Params = {
|
type Params = {
|
||||||
where?: any;
|
where?: any;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import type { Knex } from 'knex';
|
|||||||
|
|
||||||
import { createQueryBuilder } from '../query';
|
import { createQueryBuilder } from '../query';
|
||||||
import type { Database } from '..';
|
import type { Database } from '..';
|
||||||
import type { MorphJoinTable, Relation } from '../metadata/types';
|
import type { MorphJoinTable, Relation } from '../types';
|
||||||
|
|
||||||
type Rows = Record<string, unknown>[];
|
type Rows = Record<string, unknown>[];
|
||||||
|
|
||||||
|
|||||||
@ -10,12 +10,11 @@ import {
|
|||||||
isAnyToOne,
|
isAnyToOne,
|
||||||
hasOrderColumn,
|
hasOrderColumn,
|
||||||
hasInverseOrderColumn,
|
hasInverseOrderColumn,
|
||||||
} from '../metadata/relations';
|
} from '../metadata';
|
||||||
import { createQueryBuilder } from '../query';
|
import { createQueryBuilder } from '../query';
|
||||||
import { addSchema } from '../utils/knex';
|
import { addSchema } from '../utils/knex';
|
||||||
import type { Database } from '..';
|
import type { Database } from '..';
|
||||||
import type { ID } from '../typings';
|
import type { ID, Relation } from '../types';
|
||||||
import type { Relation } from '../metadata/types';
|
|
||||||
|
|
||||||
declare module 'knex' {
|
declare module 'knex' {
|
||||||
namespace Knex {
|
namespace Knex {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { castArray, maxBy } from 'lodash/fp';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { InvalidRelationError } from '../errors';
|
import { InvalidRelationError } from '../errors';
|
||||||
import type { ID } from '../typings';
|
import type { ID } from '../types';
|
||||||
|
|
||||||
interface Link {
|
interface Link {
|
||||||
id: ID;
|
id: ID;
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
|
|
||||||
import { cleanInverseOrderColumn } from '../../regular-relations';
|
import { cleanInverseOrderColumn } from '../../regular-relations';
|
||||||
import type { Relation } from '../../../metadata/types';
|
import type { ID, Relation } from '../../../types';
|
||||||
import { ID } from '../../../typings';
|
|
||||||
|
|
||||||
const replaceRegularRelations = async ({
|
const replaceRegularRelations = async ({
|
||||||
targetId,
|
targetId,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import DatetimeField from './datetime';
|
|||||||
import TimestampField from './timestamp';
|
import TimestampField from './timestamp';
|
||||||
import BooleanField from './boolean';
|
import BooleanField from './boolean';
|
||||||
|
|
||||||
import type { Attribute } from '../metadata/types';
|
import type { Attribute } from '../types';
|
||||||
|
|
||||||
const typeToFieldMap: Record<string, typeof Field> = {
|
const typeToFieldMap: Record<string, typeof Field> = {
|
||||||
increments: Field,
|
increments: Field,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { Meta, Model } from '../metadata/types';
|
import type { Meta } from '../metadata';
|
||||||
|
|
||||||
export type Action =
|
export type Action =
|
||||||
| 'beforeCreate'
|
| 'beforeCreate'
|
||||||
|
|||||||
@ -1,11 +1,31 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import * as types from '../types';
|
import * as types from '../utils/types';
|
||||||
import { createRelation } from './relations';
|
import {
|
||||||
import { Metadata, Relation } from './types';
|
createRelation,
|
||||||
import type { Attribute, Model, Meta, ComponentLinkMeta } from './types';
|
getJoinTableName,
|
||||||
|
isPolymorphic,
|
||||||
|
isBidirectional,
|
||||||
|
isAnyToOne,
|
||||||
|
isOneToAny,
|
||||||
|
hasOrderColumn,
|
||||||
|
hasInverseOrderColumn,
|
||||||
|
isManyToAny,
|
||||||
|
} from './relations';
|
||||||
|
import { Metadata, Meta, ComponentLinkMeta } from './metadata';
|
||||||
|
import type { Attribute, Model, Relation } from '../types';
|
||||||
|
|
||||||
export { Metadata };
|
export type { Metadata, Meta };
|
||||||
|
export {
|
||||||
|
getJoinTableName,
|
||||||
|
isPolymorphic,
|
||||||
|
isBidirectional,
|
||||||
|
isAnyToOne,
|
||||||
|
isOneToAny,
|
||||||
|
hasOrderColumn,
|
||||||
|
hasInverseOrderColumn,
|
||||||
|
isManyToAny,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: check if there isn't an attribute with an id already
|
// TODO: check if there isn't an attribute with an id already
|
||||||
/**
|
/**
|
||||||
@ -21,17 +41,16 @@ export const createMetadata = (models: Model[] = []): Metadata => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
metadata.add({
|
metadata.add({
|
||||||
singularName: model.singularName,
|
...model,
|
||||||
uid: model.uid,
|
|
||||||
tableName: model.tableName,
|
|
||||||
attributes: {
|
attributes: {
|
||||||
id: {
|
id: {
|
||||||
type: 'increments',
|
type: 'increments',
|
||||||
},
|
},
|
||||||
...model.attributes,
|
...model.attributes,
|
||||||
},
|
},
|
||||||
lifecycles: model.lifecycles ?? ({} as Meta['lifecycles']),
|
lifecycles: model.lifecycles ?? {},
|
||||||
indexes: model.indexes || [],
|
indexes: model.indexes || [],
|
||||||
|
foreignKeys: model.foreignKeys || [],
|
||||||
columnToAttribute: {},
|
columnToAttribute: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -98,11 +117,13 @@ const hasComponentsOrDz = (model: Meta): model is ComponentLinkMeta => {
|
|||||||
|
|
||||||
// NOTE: we might just move the compo logic outside this layer too at some point
|
// NOTE: we might just move the compo logic outside this layer too at some point
|
||||||
const createCompoLinkModelMeta = (baseModelMeta: Meta): Meta => {
|
const createCompoLinkModelMeta = (baseModelMeta: Meta): Meta => {
|
||||||
|
const name = `${baseModelMeta.tableName}_components`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// TODO: make sure there can't be any conflicts with a prefix
|
// TODO: make sure there can't be any conflicts with a prefix
|
||||||
// singularName: 'compo',
|
singularName: name,
|
||||||
uid: `${baseModelMeta.tableName}_components`,
|
uid: name,
|
||||||
tableName: `${baseModelMeta.tableName}_components`,
|
tableName: name,
|
||||||
attributes: {
|
attributes: {
|
||||||
id: {
|
id: {
|
||||||
type: 'increments',
|
type: 'increments',
|
||||||
@ -161,6 +182,7 @@ const createCompoLinkModelMeta = (baseModelMeta: Meta): Meta => {
|
|||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
lifecycles: {},
|
||||||
columnToAttribute: {},
|
columnToAttribute: {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
44
packages/core/database/src/metadata/metadata.ts
Normal file
44
packages/core/database/src/metadata/metadata.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import type { Model } from '../types';
|
||||||
|
import type { ForeignKey, Index } from '../schema/types';
|
||||||
|
import type { Action, SubscriberFn } from '../lifecycles';
|
||||||
|
|
||||||
|
export interface ComponentLinkMeta extends Meta {
|
||||||
|
componentLink: Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Meta extends Model {
|
||||||
|
columnToAttribute: Record<string, string>;
|
||||||
|
componentLink?: Meta;
|
||||||
|
indexes: Index[];
|
||||||
|
foreignKeys: ForeignKey[];
|
||||||
|
lifecycles: Partial<Record<Action, SubscriberFn>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Metadata extends Map<string, Meta> {
|
||||||
|
get(key: string): Meta {
|
||||||
|
if (!super.has(key)) {
|
||||||
|
throw new Error(`Metadata for "${key}" not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.get(key) as Meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(meta: Meta) {
|
||||||
|
return this.set(meta.uid, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the DB metadata, throwing an error if a duplicate DB table name is detected
|
||||||
|
*/
|
||||||
|
validate() {
|
||||||
|
const seenTables = new Map();
|
||||||
|
for (const meta of this.values()) {
|
||||||
|
if (seenTables.get(meta.tableName)) {
|
||||||
|
throw new Error(
|
||||||
|
`DB table "${meta.tableName}" already exists. Change the collectionName of the related content type.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
seenTables.set(meta.tableName, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import type { Meta, RelationalAttribute, Relation, Metadata, MorphJoinTable } from './types';
|
import type { Meta, Metadata } from './metadata';
|
||||||
|
import type { RelationalAttribute, Relation, MorphJoinTable } from '../types';
|
||||||
|
|
||||||
interface JoinColumnOptions {
|
interface JoinColumnOptions {
|
||||||
attribute: (Relation.OneToOne | Relation.ManyToOne) & Relation.Owner;
|
attribute: (Relation.OneToOne | Relation.ManyToOne) & Relation.Owner;
|
||||||
@ -245,6 +246,7 @@ const createMorphToMany = (
|
|||||||
const typeColumnName = `${morphColumnName}_type`;
|
const typeColumnName = `${morphColumnName}_type`;
|
||||||
|
|
||||||
metadata.add({
|
metadata.add({
|
||||||
|
singularName: joinTableName,
|
||||||
uid: joinTableName,
|
uid: joinTableName,
|
||||||
tableName: joinTableName,
|
tableName: joinTableName,
|
||||||
attributes: {
|
attributes: {
|
||||||
@ -299,6 +301,7 @@ const createMorphToMany = (
|
|||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
lifecycles: {},
|
||||||
columnToAttribute: {},
|
columnToAttribute: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -429,6 +432,7 @@ const createJoinTable = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const metadataSchema: Meta = {
|
const metadataSchema: Meta = {
|
||||||
|
singularName: joinTableName,
|
||||||
uid: joinTableName,
|
uid: joinTableName,
|
||||||
tableName: joinTableName,
|
tableName: joinTableName,
|
||||||
attributes: {
|
attributes: {
|
||||||
@ -480,6 +484,7 @@ const createJoinTable = (
|
|||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
lifecycles: {},
|
||||||
columnToAttribute: {},
|
columnToAttribute: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,269 +0,0 @@
|
|||||||
import type { Action, SubscriberFn } from '../lifecycles';
|
|
||||||
import type { ForeignKey, Index } from '../schema/types';
|
|
||||||
|
|
||||||
export interface ColumnInfo {
|
|
||||||
unsigned?: boolean;
|
|
||||||
defaultTo?: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Attribute = ScalarAttribute | RelationalAttribute;
|
|
||||||
|
|
||||||
export type RelationalAttribute =
|
|
||||||
| Relation.OneToOne
|
|
||||||
| Relation.OneToMany
|
|
||||||
| Relation.ManyToOne
|
|
||||||
| Relation.ManyToMany
|
|
||||||
| Relation.MorphMany
|
|
||||||
| Relation.MorphOne
|
|
||||||
| Relation.MorphToOne
|
|
||||||
| Relation.MorphToMany;
|
|
||||||
|
|
||||||
export interface BasAttribute {
|
|
||||||
type: string;
|
|
||||||
columnName?: string;
|
|
||||||
default?: any;
|
|
||||||
column?: ColumnInfo;
|
|
||||||
required?: boolean;
|
|
||||||
unique?: boolean;
|
|
||||||
component?: string;
|
|
||||||
repeatable?: boolean;
|
|
||||||
columnType?: {
|
|
||||||
type: string;
|
|
||||||
args: unknown[];
|
|
||||||
};
|
|
||||||
searchable?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ScalarAttribute extends BasAttribute {
|
|
||||||
type:
|
|
||||||
| 'increments'
|
|
||||||
| 'password'
|
|
||||||
| 'email'
|
|
||||||
| 'string'
|
|
||||||
| 'enumeration'
|
|
||||||
| 'uid'
|
|
||||||
| 'richtext'
|
|
||||||
| 'text'
|
|
||||||
| 'json'
|
|
||||||
| 'integer'
|
|
||||||
| 'biginteger'
|
|
||||||
| 'float'
|
|
||||||
| 'decimal'
|
|
||||||
| 'boolean'
|
|
||||||
| 'date'
|
|
||||||
| 'time'
|
|
||||||
| 'datetime'
|
|
||||||
| 'timestamp';
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JoinColumn {
|
|
||||||
name: string;
|
|
||||||
referencedColumn: string;
|
|
||||||
referencedTable?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BaseJoinTable {
|
|
||||||
name: string;
|
|
||||||
joinColumn: JoinColumn;
|
|
||||||
orderBy?: Record<string, 'asc' | 'desc'>;
|
|
||||||
on?: Record<string, unknown>;
|
|
||||||
pivotColumns: string[];
|
|
||||||
inverseJoinColumn: {
|
|
||||||
name: string;
|
|
||||||
referencedColumn: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JoinTable extends BaseJoinTable {
|
|
||||||
orderColumnName?: string;
|
|
||||||
inverseOrderColumnName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderedJoinTable extends BaseJoinTable {
|
|
||||||
orderColumnName: string;
|
|
||||||
inverseOrderColumnName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
||||||
export namespace Relation {
|
|
||||||
export type Owner = {
|
|
||||||
inversedBy: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WithTarget = {
|
|
||||||
target: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Bidirectional = OneToOne | OneToMany | ManyToOne | ManyToMany;
|
|
||||||
|
|
||||||
type BaseBidirectional = {
|
|
||||||
type: 'relation';
|
|
||||||
relation: 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany';
|
|
||||||
target: string;
|
|
||||||
inversedBy?: string;
|
|
||||||
mappedBy?: string;
|
|
||||||
joinTable: BidirectionalAttributeJoinTable;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OneToOne = BaseBidirectional & {
|
|
||||||
relation: 'oneToOne';
|
|
||||||
useJoinTable?: boolean;
|
|
||||||
joinTable?: JoinTable;
|
|
||||||
joinColumn?: JoinColumn;
|
|
||||||
owner?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OneToMany = BaseBidirectional & {
|
|
||||||
relation: 'oneToMany';
|
|
||||||
joinTable: OrderedJoinTable;
|
|
||||||
joinColumn?: JoinColumn;
|
|
||||||
owner?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ManyToOne = BaseBidirectional & {
|
|
||||||
relation: 'manyToOne';
|
|
||||||
useJoinTable?: boolean;
|
|
||||||
joinTable?: JoinTable;
|
|
||||||
joinColumn?: JoinColumn;
|
|
||||||
owner?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ManyToMany = BaseBidirectional & {
|
|
||||||
relation: 'manyToMany';
|
|
||||||
joinTable: OrderedJoinTable;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Morph = MorphMany | MorphOne | MorphToOne | MorphToMany;
|
|
||||||
|
|
||||||
export type MorphMany = {
|
|
||||||
type: 'relation';
|
|
||||||
relation: 'morphMany';
|
|
||||||
target: string;
|
|
||||||
morphBy: string;
|
|
||||||
joinTable: MorphJoinTable;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MorphOne = {
|
|
||||||
type: 'relation';
|
|
||||||
relation: 'morphOne';
|
|
||||||
target: string;
|
|
||||||
morphBy: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MorphToOne = {
|
|
||||||
type: 'relation';
|
|
||||||
relation: 'morphToOne';
|
|
||||||
owner?: boolean;
|
|
||||||
morphColumn: MorphColumn;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MorphToMany = {
|
|
||||||
type: 'relation';
|
|
||||||
relation: 'morphToMany';
|
|
||||||
joinTable: MorphJoinTable;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BidirectionalAttributeJoinTable extends JoinTable {
|
|
||||||
orderColumnName: string;
|
|
||||||
inverseOrderColumnName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MorphColumn {
|
|
||||||
typeField?: string;
|
|
||||||
typeColumn: {
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
idColumn: {
|
|
||||||
name: string;
|
|
||||||
referencedColumn: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MorphJoinTable {
|
|
||||||
name: string;
|
|
||||||
joinColumn: JoinColumn;
|
|
||||||
orderBy?: Record<string, 'asc' | 'desc'>;
|
|
||||||
on?: Record<string, unknown>;
|
|
||||||
pivotColumns: string[];
|
|
||||||
morphColumn: MorphColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BaseRelationalAttribute {
|
|
||||||
type: 'relation';
|
|
||||||
target: string;
|
|
||||||
useJoinTable?: boolean;
|
|
||||||
joinTable?: JoinTable | MorphJoinTable;
|
|
||||||
morphBy?: string;
|
|
||||||
inversedBy?: string;
|
|
||||||
owner?: boolean;
|
|
||||||
morphColumn?: MorphColumn;
|
|
||||||
joinColumn?: JoinColumn;
|
|
||||||
// TODO: remove this
|
|
||||||
component?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MorphRelationalAttribute extends BaseRelationalAttribute {
|
|
||||||
relation: 'morphMany' | 'morphOne' | 'morphToOne' | 'morphToMany';
|
|
||||||
morphColumn: MorphColumn;
|
|
||||||
morphBy: string;
|
|
||||||
joinTable: MorphJoinTable;
|
|
||||||
target: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Meta {
|
|
||||||
singularName?: string;
|
|
||||||
uid: string;
|
|
||||||
tableName: string;
|
|
||||||
attributes: Record<string, Attribute>;
|
|
||||||
indexes: Index[];
|
|
||||||
foreignKeys?: ForeignKey[];
|
|
||||||
lifecycles?: Record<Action, SubscriberFn>;
|
|
||||||
columnToAttribute: Record<string, string>;
|
|
||||||
componentLink?: Meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ComponentLinkMeta extends Meta {
|
|
||||||
componentLink: Meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Model {
|
|
||||||
uid: string;
|
|
||||||
tableName: string;
|
|
||||||
singularName: string;
|
|
||||||
attributes: Record<string, Attribute>;
|
|
||||||
lifecycles?: Record<Action, SubscriberFn>;
|
|
||||||
indexes: Index[];
|
|
||||||
componentLink?: Meta;
|
|
||||||
columnToAttribute?: Record<string, string>;
|
|
||||||
foreignKeys?: Record<string, unknown>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Metadata extends Map<string, Meta> {
|
|
||||||
get(key: string): Meta {
|
|
||||||
if (!super.has(key)) {
|
|
||||||
throw new Error(`Metadata for "${key}" not found`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.get(key) as Meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(meta: Meta) {
|
|
||||||
return this.set(meta.uid, meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the DB metadata, throwing an error if a duplicate DB table name is detected
|
|
||||||
*/
|
|
||||||
validate() {
|
|
||||||
const seenTables = new Map();
|
|
||||||
for (const meta of this.values()) {
|
|
||||||
if (seenTables.get(meta.tableName)) {
|
|
||||||
throw new Error(
|
|
||||||
`DB table "${meta.tableName}" already exists. Change the collectionName of the related content type.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
seenTables.set(meta.tableName, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import * as types from '../../types';
|
import * as types from '../../utils/types';
|
||||||
import { createJoin } from './join';
|
import { createJoin } from './join';
|
||||||
import { toColumnName } from './transform';
|
import { toColumnName } from './transform';
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import { Rec, fromRow } from '../transform';
|
import { fromRow } from '../transform';
|
||||||
import type { QueryBuilder } from '../../query-builder';
|
import type { QueryBuilder } from '../../query-builder';
|
||||||
import type { Database } from '../../..';
|
import type { Database } from '../../..';
|
||||||
import type { Meta, RelationalAttribute, Relation } from '../../../metadata/types';
|
import type { Meta } from '../../../metadata';
|
||||||
import { ID } from '../../../typings';
|
import { ID, RelationalAttribute, Relation } from '../../../types';
|
||||||
|
|
||||||
type Context = {
|
type Context = {
|
||||||
db: Database;
|
db: Database;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import * as types from '../../../types';
|
import * as types from '../../../utils/types';
|
||||||
import type { Meta } from '../../../metadata/types';
|
import type { Meta } from '../../../metadata';
|
||||||
import type { QueryBuilder } from '../../query-builder';
|
import type { QueryBuilder } from '../../query-builder';
|
||||||
import type { Database } from '../../..';
|
import type { Database } from '../../..';
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
import type { Knex } from 'knex';
|
import type { Knex } from 'knex';
|
||||||
|
|
||||||
import * as types from '../../types';
|
import * as types from '../../utils/types';
|
||||||
import { toColumnName } from './transform';
|
import { toColumnName } from './transform';
|
||||||
import type { Ctx } from '../types';
|
import type { Ctx } from '../types';
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import type { Database } from '../../..';
|
|||||||
|
|
||||||
import { applyPopulate } from '../populate';
|
import { applyPopulate } from '../populate';
|
||||||
import { fromRow } from '../transform';
|
import { fromRow } from '../transform';
|
||||||
import { Meta } from '../../../metadata/types';
|
import { Meta } from '../../../metadata';
|
||||||
|
|
||||||
const knexQueryDone = Symbol('knexQueryDone');
|
const knexQueryDone = Symbol('knexQueryDone');
|
||||||
const knexPerformingQuery = Symbol('knexPerformingQuery');
|
const knexPerformingQuery = Symbol('knexPerformingQuery');
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import _ from 'lodash/fp';
|
import _ from 'lodash/fp';
|
||||||
|
|
||||||
import * as types from '../../types';
|
import * as types from '../../utils/types';
|
||||||
import { createField } from '../../fields';
|
import { createField } from '../../fields';
|
||||||
|
|
||||||
import type { Meta } from '../../metadata/types';
|
import type { Meta } from '../../metadata';
|
||||||
|
|
||||||
type Row = Record<string, unknown> | null;
|
type Row = Record<string, unknown> | null;
|
||||||
export type Rec = Record<string, unknown> | null;
|
export type Rec = Record<string, unknown> | null;
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import { isArray, castArray, keys, isPlainObject } from 'lodash/fp';
|
|||||||
import type { Knex } from 'knex';
|
import type { Knex } from 'knex';
|
||||||
|
|
||||||
import { isOperatorOfType } from '@strapi/utils';
|
import { isOperatorOfType } from '@strapi/utils';
|
||||||
import * as types from '../../types';
|
import * as types from '../../utils/types';
|
||||||
import { createField } from '../../fields';
|
import { createField } from '../../fields';
|
||||||
import { createJoin } from './join';
|
import { createJoin } from './join';
|
||||||
import { toColumnName } from './transform';
|
import { toColumnName } from './transform';
|
||||||
import { isKnexQuery } from '../../utils/knex';
|
import { isKnexQuery } from '../../utils/knex';
|
||||||
|
|
||||||
import type { Attribute } from '../../metadata/types';
|
|
||||||
import type { Ctx } from '../types';
|
import type { Ctx } from '../types';
|
||||||
|
import type { Attribute } from '../../types';
|
||||||
|
|
||||||
const isObj = (value: unknown): value is Record<string, unknown> => isPlainObject(value);
|
const isObj = (value: unknown): value is Record<string, unknown> => isPlainObject(value);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import * as types from '../types';
|
import * as types from '../utils/types';
|
||||||
|
|
||||||
import type { Metadata, Meta, Attribute } from '../metadata/types';
|
import type { Metadata, Meta } from '../metadata';
|
||||||
import type { Column, Schema, Table } from './types';
|
import type { Column, Schema, Table } from './types';
|
||||||
|
import type { Attribute } from '../types';
|
||||||
|
|
||||||
const createColumn = (name: string, attribute: Attribute): Column => {
|
const createColumn = (name: string, attribute: Attribute): Column => {
|
||||||
const { type, args = [], ...opts } = getColumnType(attribute);
|
const { type, args = [], ...opts } = getColumnType(attribute);
|
||||||
|
|||||||
@ -1,36 +1,223 @@
|
|||||||
import type { Attribute, ScalarAttribute, RelationalAttribute } from '../metadata/types';
|
import type { Action, SubscriberFn } from '../lifecycles';
|
||||||
|
import type { ForeignKey, Index } from '../schema/types';
|
||||||
|
|
||||||
const SCALAR_TYPES = [
|
export type ID = string | number;
|
||||||
'increments',
|
export interface ColumnInfo {
|
||||||
'password',
|
unsigned?: boolean;
|
||||||
'email',
|
defaultTo?: unknown;
|
||||||
'string',
|
}
|
||||||
'uid',
|
|
||||||
'richtext',
|
|
||||||
'text',
|
|
||||||
'json',
|
|
||||||
'enumeration',
|
|
||||||
'integer',
|
|
||||||
'biginteger',
|
|
||||||
'float',
|
|
||||||
'decimal',
|
|
||||||
'date',
|
|
||||||
'time',
|
|
||||||
'datetime',
|
|
||||||
'timestamp',
|
|
||||||
'boolean',
|
|
||||||
];
|
|
||||||
|
|
||||||
const STRING_TYPES = ['string', 'text', 'uid', 'email', 'enumeration', 'richtext'];
|
export type Attribute = ScalarAttribute | RelationalAttribute;
|
||||||
const NUMBER_TYPES = ['biginteger', 'integer', 'decimal', 'float'];
|
|
||||||
|
|
||||||
export const isString = (type: string) => STRING_TYPES.includes(type);
|
export type RelationalAttribute =
|
||||||
export const isNumber = (type: string) => NUMBER_TYPES.includes(type);
|
| Relation.OneToOne
|
||||||
export const isScalar = (type: string) => SCALAR_TYPES.includes(type);
|
| Relation.OneToMany
|
||||||
export const isComponent = (type: string) => type === 'component';
|
| Relation.ManyToOne
|
||||||
export const isDynamicZone = (type: string) => type === 'dynamiczone';
|
| Relation.ManyToMany
|
||||||
export const isRelation = (type: string) => type === 'relation';
|
| Relation.MorphMany
|
||||||
export const isScalarAttribute = (attribute: Attribute): attribute is ScalarAttribute =>
|
| Relation.MorphOne
|
||||||
isScalar(attribute.type);
|
| Relation.MorphToOne
|
||||||
export const isRelationalAttribute = (attribute: Attribute): attribute is RelationalAttribute =>
|
| Relation.MorphToMany;
|
||||||
isRelation(attribute.type);
|
|
||||||
|
export interface BasAttribute {
|
||||||
|
type: string;
|
||||||
|
columnName?: string;
|
||||||
|
default?: any;
|
||||||
|
column?: ColumnInfo;
|
||||||
|
required?: boolean;
|
||||||
|
unique?: boolean;
|
||||||
|
component?: string;
|
||||||
|
repeatable?: boolean;
|
||||||
|
columnType?: {
|
||||||
|
type: string;
|
||||||
|
args: unknown[];
|
||||||
|
};
|
||||||
|
searchable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScalarAttribute extends BasAttribute {
|
||||||
|
type:
|
||||||
|
| 'increments'
|
||||||
|
| 'password'
|
||||||
|
| 'email'
|
||||||
|
| 'string'
|
||||||
|
| 'enumeration'
|
||||||
|
| 'uid'
|
||||||
|
| 'richtext'
|
||||||
|
| 'text'
|
||||||
|
| 'json'
|
||||||
|
| 'integer'
|
||||||
|
| 'biginteger'
|
||||||
|
| 'float'
|
||||||
|
| 'decimal'
|
||||||
|
| 'boolean'
|
||||||
|
| 'date'
|
||||||
|
| 'time'
|
||||||
|
| 'datetime'
|
||||||
|
| 'timestamp';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JoinColumn {
|
||||||
|
name: string;
|
||||||
|
referencedColumn: string;
|
||||||
|
referencedTable?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseJoinTable {
|
||||||
|
name: string;
|
||||||
|
joinColumn: JoinColumn;
|
||||||
|
orderBy?: Record<string, 'asc' | 'desc'>;
|
||||||
|
on?: Record<string, unknown>;
|
||||||
|
pivotColumns: string[];
|
||||||
|
inverseJoinColumn: {
|
||||||
|
name: string;
|
||||||
|
referencedColumn: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JoinTable extends BaseJoinTable {
|
||||||
|
orderColumnName?: string;
|
||||||
|
inverseOrderColumnName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderedJoinTable extends BaseJoinTable {
|
||||||
|
orderColumnName: string;
|
||||||
|
inverseOrderColumnName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
export namespace Relation {
|
||||||
|
export type Owner = {
|
||||||
|
inversedBy: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WithTarget = {
|
||||||
|
target: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Bidirectional = OneToOne | OneToMany | ManyToOne | ManyToMany;
|
||||||
|
|
||||||
|
type BaseBidirectional = {
|
||||||
|
type: 'relation';
|
||||||
|
relation: 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany';
|
||||||
|
target: string;
|
||||||
|
inversedBy?: string;
|
||||||
|
mappedBy?: string;
|
||||||
|
joinTable: BidirectionalAttributeJoinTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OneToOne = BaseBidirectional & {
|
||||||
|
relation: 'oneToOne';
|
||||||
|
useJoinTable?: boolean;
|
||||||
|
joinTable?: JoinTable;
|
||||||
|
joinColumn?: JoinColumn;
|
||||||
|
owner?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OneToMany = BaseBidirectional & {
|
||||||
|
relation: 'oneToMany';
|
||||||
|
joinTable: OrderedJoinTable;
|
||||||
|
joinColumn?: JoinColumn;
|
||||||
|
owner?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ManyToOne = BaseBidirectional & {
|
||||||
|
relation: 'manyToOne';
|
||||||
|
useJoinTable?: boolean;
|
||||||
|
joinTable?: JoinTable;
|
||||||
|
joinColumn?: JoinColumn;
|
||||||
|
owner?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ManyToMany = BaseBidirectional & {
|
||||||
|
relation: 'manyToMany';
|
||||||
|
joinTable: OrderedJoinTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Morph = MorphMany | MorphOne | MorphToOne | MorphToMany;
|
||||||
|
|
||||||
|
export type MorphMany = {
|
||||||
|
type: 'relation';
|
||||||
|
relation: 'morphMany';
|
||||||
|
target: string;
|
||||||
|
morphBy: string;
|
||||||
|
joinTable: MorphJoinTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MorphOne = {
|
||||||
|
type: 'relation';
|
||||||
|
relation: 'morphOne';
|
||||||
|
target: string;
|
||||||
|
morphBy: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MorphToOne = {
|
||||||
|
type: 'relation';
|
||||||
|
relation: 'morphToOne';
|
||||||
|
owner?: boolean;
|
||||||
|
morphColumn: MorphColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MorphToMany = {
|
||||||
|
type: 'relation';
|
||||||
|
relation: 'morphToMany';
|
||||||
|
joinTable: MorphJoinTable;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BidirectionalAttributeJoinTable extends JoinTable {
|
||||||
|
orderColumnName: string;
|
||||||
|
inverseOrderColumnName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MorphColumn {
|
||||||
|
typeField?: string;
|
||||||
|
typeColumn: {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
idColumn: {
|
||||||
|
name: string;
|
||||||
|
referencedColumn: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MorphJoinTable {
|
||||||
|
name: string;
|
||||||
|
joinColumn: JoinColumn;
|
||||||
|
orderBy?: Record<string, 'asc' | 'desc'>;
|
||||||
|
on?: Record<string, unknown>;
|
||||||
|
pivotColumns: string[];
|
||||||
|
morphColumn: MorphColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseRelationalAttribute {
|
||||||
|
type: 'relation';
|
||||||
|
target: string;
|
||||||
|
useJoinTable?: boolean;
|
||||||
|
joinTable?: JoinTable | MorphJoinTable;
|
||||||
|
morphBy?: string;
|
||||||
|
inversedBy?: string;
|
||||||
|
owner?: boolean;
|
||||||
|
morphColumn?: MorphColumn;
|
||||||
|
joinColumn?: JoinColumn;
|
||||||
|
// TODO: remove this
|
||||||
|
component?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MorphRelationalAttribute extends BaseRelationalAttribute {
|
||||||
|
relation: 'morphMany' | 'morphOne' | 'morphToOne' | 'morphToMany';
|
||||||
|
morphColumn: MorphColumn;
|
||||||
|
morphBy: string;
|
||||||
|
joinTable: MorphJoinTable;
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Model {
|
||||||
|
uid: string;
|
||||||
|
tableName: string;
|
||||||
|
singularName: string;
|
||||||
|
attributes: Record<string, Attribute>;
|
||||||
|
indexes?: Index[];
|
||||||
|
foreignKeys?: ForeignKey[];
|
||||||
|
lifecycles?: Partial<Record<Action, SubscriberFn>>;
|
||||||
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export type ID = string | number;
|
|
||||||
36
packages/core/database/src/utils/types.ts
Normal file
36
packages/core/database/src/utils/types.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type { Attribute, ScalarAttribute, RelationalAttribute } from '../types';
|
||||||
|
|
||||||
|
const SCALAR_TYPES = [
|
||||||
|
'increments',
|
||||||
|
'password',
|
||||||
|
'email',
|
||||||
|
'string',
|
||||||
|
'uid',
|
||||||
|
'richtext',
|
||||||
|
'text',
|
||||||
|
'json',
|
||||||
|
'enumeration',
|
||||||
|
'integer',
|
||||||
|
'biginteger',
|
||||||
|
'float',
|
||||||
|
'decimal',
|
||||||
|
'date',
|
||||||
|
'time',
|
||||||
|
'datetime',
|
||||||
|
'timestamp',
|
||||||
|
'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
const STRING_TYPES = ['string', 'text', 'uid', 'email', 'enumeration', 'richtext'];
|
||||||
|
const NUMBER_TYPES = ['biginteger', 'integer', 'decimal', 'float'];
|
||||||
|
|
||||||
|
export const isString = (type: string) => STRING_TYPES.includes(type);
|
||||||
|
export const isNumber = (type: string) => NUMBER_TYPES.includes(type);
|
||||||
|
export const isScalar = (type: string) => SCALAR_TYPES.includes(type);
|
||||||
|
export const isComponent = (type: string) => type === 'component';
|
||||||
|
export const isDynamicZone = (type: string) => type === 'dynamiczone';
|
||||||
|
export const isRelation = (type: string) => type === 'relation';
|
||||||
|
export const isScalarAttribute = (attribute: Attribute): attribute is ScalarAttribute =>
|
||||||
|
isScalar(attribute.type);
|
||||||
|
export const isRelationalAttribute = (attribute: Attribute): attribute is RelationalAttribute =>
|
||||||
|
isRelation(attribute.type);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { getJoinTableName } from '../../metadata/relations';
|
import { getJoinTableName } from '../../metadata';
|
||||||
|
|
||||||
import type { Database } from '../..';
|
import type { Database } from '../..';
|
||||||
import type { Relation } from '../../metadata/types';
|
import type { Relation } from '../../types';
|
||||||
|
|
||||||
type Link = {
|
type Link = {
|
||||||
relation: Relation.Bidirectional & { inversedBy: string };
|
relation: Relation.Bidirectional & { inversedBy: string };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user