refactored entity schemas

This commit is contained in:
Umed Khudoiberdiev 2018-02-27 18:45:44 +05:00
parent ba90fd904e
commit 1606ab8afb
43 changed files with 427 additions and 271 deletions

View File

@ -29,7 +29,7 @@ If you want to disable this behavior use `queryBuilder.updateEntity(false)` meth
This feature is convenient for users who have uuid, create/update date, version columns or columns with DEFAULT value set.
* now `InsertQueryBuilder`, `UpdateQueryBuilder` and `DeleteQueryBuilder` call subscribers and listeners.
You can disable this behavior by setting `queryBuilder.callListeners(false)` method.
* `Repository` and `EntityManager` method `.findOne` is deprecated and will be removed in next 0.3.0 version.
* `Repository` and `EntityManager` method `.findOneById` is deprecated and will be removed in next 0.3.0 version.
Use `findOne(id)` method instead now.
* `InsertQueryBuilder` now returns `InsertResult` which contains extended information and metadata about runned query
* `UpdateQueryBuilder` now returns `UpdateResult` which contains extended information and metadata about runned query
@ -56,6 +56,7 @@ By default its true.
* added support for nested set and materialized path tree hierarchy patterns
* breaking change on how array parameters work in queries - now instead of (:param) new syntax must be used (:...param).
This fixed various issues on how real arrays must work
* changed the way how entity schemas are created (now more type-safe), now interface EntitySchema is a class
## 0.1.13

View File

@ -1,9 +1,17 @@
import "reflect-metadata";
import {ConnectionOptions, createConnection} from "../../src/index";
import {ConnectionOptions, createConnection, EntitySchema} from "../../src";
import {Post} from "./entity/Post";
import {PostDetails} from "./entity/PostDetails";
import {Category} from "./entity/Category";
import {Image} from "./entity/Image";
// NOTE: this example is not working yet, only concepts of how this feature must work described here
const PostEntity = new EntitySchema<Post>(require(__dirname + "/../../../../sample/sample24-schemas/schemas/post.json"));
const PostDetailsEntity = new EntitySchema<PostDetails>(require(__dirname + "/../../../../sample/sample24-schemas/schemas/post-details.json"));
const CategoryEntity = new EntitySchema<Category>(require(__dirname + "/../../../../sample/sample24-schemas/schemas/category.json"));
const ImageEntity = new EntitySchema<Image>(require(__dirname + "/../../../../sample/sample24-schemas/schemas/image.json"));
const options: ConnectionOptions = {
type: "mysql",
host: "localhost",
@ -13,11 +21,11 @@ const options: ConnectionOptions = {
database: "test",
synchronize: true,
// entitySchemaDirectories: [__dirname + "/schemas"],
entitySchemas: [
require(__dirname + "/../../../../sample/sample24-schemas/schemas/post.json"),
require(__dirname + "/../../../../sample/sample24-schemas/schemas/post-details.json"),
require(__dirname + "/../../../../sample/sample24-schemas/schemas/category.json"),
require(__dirname + "/../../../../sample/sample24-schemas/schemas/image.json")
entities: [
PostEntity,
PostDetailsEntity,
CategoryEntity,
ImageEntity,
]
};

View File

@ -25,7 +25,7 @@ export interface BaseConnectionOptions {
* Accepts both entity classes and directories where from entities need to be loaded.
* Directories support glob patterns.
*/
readonly entities?: (Function|string)[];
readonly entities?: ((Function|string|EntitySchema<any>))[];
/**
* Subscribers to be loaded for this connection.
@ -34,13 +34,6 @@ export interface BaseConnectionOptions {
*/
readonly subscribers?: Function[]|string[];
/**
* Entity schemas to be loaded for this connection.
* Accepts both entity schema classes and directories where from entity schemas need to be loaded.
* Directories support glob patterns.
*/
readonly entitySchemas?: EntitySchema[]|string[];
/**
* Migrations to be loaded for this connection.
* Accepts both migration classes and directories where from migrations need to be loaded.

View File

@ -33,6 +33,7 @@ import {PromiseUtils} from "../util/PromiseUtils";
import {SqljsEntityManager} from "../entity-manager/SqljsEntityManager";
import {RelationLoader} from "../query-builder/RelationLoader";
import {RelationIdLoader} from "../query-builder/RelationIdLoader";
import {EntitySchema} from "../";
/**
* Connection is a single database ORM connection to a specific database.
@ -298,14 +299,14 @@ export class Connection {
/**
* Checks if entity metadata exist for the given entity class, target name or table name.
*/
hasMetadata(target: Function|string): boolean {
hasMetadata(target: Function|EntitySchema<any>|string): boolean {
return !!this.findMetadata(target);
}
/**
* Gets entity metadata for the given entity class or schema name.
*/
getMetadata(target: Function|string): EntityMetadata {
getMetadata(target: Function|EntitySchema<any>|string): EntityMetadata {
const metadata = this.findMetadata(target);
if (!metadata)
throw new EntityMetadataNotFound(target);
@ -316,7 +317,7 @@ export class Connection {
/**
* Gets repository for the given entity.
*/
getRepository<Entity>(target: ObjectType<Entity>|string): Repository<Entity> {
getRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): Repository<Entity> {
return this.manager.getRepository(target);
}
@ -324,7 +325,7 @@ export class Connection {
* Gets tree repository for the given entity class or name.
* Only tree-type entities can have a TreeRepository, like ones decorated with @Tree decorator.
*/
getTreeRepository<Entity>(target: ObjectType<Entity>|string): TreeRepository<Entity> {
getTreeRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): TreeRepository<Entity> {
return this.manager.getTreeRepository(target);
}
@ -332,7 +333,7 @@ export class Connection {
* Gets mongodb-specific repository for the given entity class or name.
* Works only if connection is mongodb-specific.
*/
getMongoRepository<Entity>(target: ObjectType<Entity>|string): MongoRepository<Entity> {
getMongoRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): MongoRepository<Entity> {
if (!(this.driver instanceof MongoDriver))
throw new Error(`You can use getMongoRepository only for MongoDB connections.`);
@ -378,7 +379,7 @@ export class Connection {
/**
* Creates a new query builder that can be used to build a sql query.
*/
createQueryBuilder<Entity>(entityClass: ObjectType<Entity>|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity>;
createQueryBuilder<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity>;
/**
* Creates a new query builder that can be used to build a sql query.
@ -388,12 +389,12 @@ export class Connection {
/**
* Creates a new query builder that can be used to build a sql query.
*/
createQueryBuilder<Entity>(entityOrRunner?: ObjectType<Entity>|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity> {
createQueryBuilder<Entity>(entityOrRunner?: ObjectType<Entity>|EntitySchema<Entity>|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity> {
if (this instanceof MongoEntityManager)
throw new Error(`Query Builder is not supported by MongoDB.`);
if (alias) {
const metadata = this.getMetadata(entityOrRunner as Function|string);
const metadata = this.getMetadata(entityOrRunner as Function|EntitySchema<Entity>|string);
return new SelectQueryBuilder(this, queryRunner)
.select(alias)
.from(metadata.target, alias);
@ -448,10 +449,13 @@ export class Connection {
/**
* Finds exist entity metadata by the given entity class, target name or table name.
*/
protected findMetadata(target: Function|string): EntityMetadata|undefined {
protected findMetadata(target: Function|EntitySchema<any>|string): EntityMetadata|undefined {
return this.entityMetadatas.find(metadata => {
if (metadata.target === target)
return true;
if (target instanceof EntitySchema) {
return metadata.name === target.options.name;
}
if (typeof target === "string") {
if (target.indexOf(".") !== -1) {
return metadata.tablePath === target;
@ -477,7 +481,7 @@ export class Connection {
Object.assign(this, { subscribers: subscribers });
// build entity metadatas
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas(this.options.entities || [], this.options.entitySchemas || []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas(this.options.entities || []);
Object.assign(this, { entityMetadatas: entityMetadatas });
// create migration instances

View File

@ -1,4 +1,4 @@
import {importClassesFromDirectories, importJsonsFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {importClassesFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {OrmUtils} from "../util/OrmUtils";
import {getFromContainer} from "../container";
import {MigrationInterface} from "../migration/MigrationInterface";
@ -49,14 +49,17 @@ export class ConnectionMetadataBuilder {
/**
* Builds entity metadatas for the given classes or directories.
*/
buildEntityMetadatas(entities: (Function|string)[], schemas: (EntitySchema|string)[]): EntityMetadata[] {
const [entityClasses, entityDirectories] = OrmUtils.splitClassesAndStrings(entities || []);
buildEntityMetadatas(entities: (Function|EntitySchema<any>|string)[]): EntityMetadata[] {
// todo: instead we need to merge multiple metadata args storages
const [entityClassesOrSchemas, entityDirectories] = OrmUtils.splitClassesAndStrings(entities || []);
const entityClasses: Function[] = entityClassesOrSchemas.filter(entityClass => (entityClass instanceof EntitySchema) === false) as any;
const entitySchemas: EntitySchema<any>[] = entityClassesOrSchemas.filter(entityClass => entityClass instanceof EntitySchema) as any;
const allEntityClasses = [...entityClasses, ...importClassesFromDirectories(entityDirectories)];
const decoratorEntityMetadatas = new EntityMetadataBuilder(this.connection, getMetadataArgsStorage()).build(allEntityClasses);
const [entitySchemaClasses, entitySchemaDirectories] = OrmUtils.splitClassesAndStrings(schemas || []);
const allEntitySchemaClasses = [...entitySchemaClasses, ...importJsonsFromDirectories(entitySchemaDirectories)];
const metadataArgsStorageFromSchema = new EntitySchemaTransformer().transform(allEntitySchemaClasses);
const metadataArgsStorageFromSchema = new EntitySchemaTransformer().transform(entitySchemas);
const schemaEntityMetadatas = new EntityMetadataBuilder(this.connection, metadataArgsStorageFromSchema).build();
return [...decoratorEntityMetadatas, ...schemaEntityMetadatas];

View File

@ -34,7 +34,6 @@ export class ConnectionOptionsEnvReader {
entities: this.stringToArray(PlatformTools.getEnvVariable("TYPEORM_ENTITIES")),
migrations: this.stringToArray(PlatformTools.getEnvVariable("TYPEORM_MIGRATIONS")),
subscribers: this.stringToArray(PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS")),
entitySchemas: this.stringToArray(PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS")),
logging: this.transformLogging(PlatformTools.getEnvVariable("TYPEORM_LOGGING")),
logger: PlatformTools.getEnvVariable("TYPEORM_LOGGER"),
entityPrefix: PlatformTools.getEnvVariable("TYPEORM_ENTITY_PREFIX"),

View File

@ -30,7 +30,6 @@ export class ConnectionOptionsXmlReader {
synchronize: connection.synchronize ? connection.synchronize[0] : undefined,
entities: connection.entities ? connection.entities[0].entity : [],
subscribers: connection.subscribers ? connection.subscribers[0].entity : [],
entitySchemas: connection.entitySchemas ? connection.entitySchemas[0].entity : [],
logging: connection.logging[0] ? connection.logging[0].split(",") : undefined,
};
});

View File

@ -15,7 +15,7 @@ import {FindOptionsUtils} from "../find-options/FindOptionsUtils";
import {PlainObjectToNewEntityTransformer} from "../query-builder/transformer/PlainObjectToNewEntityTransformer";
import {PlainObjectToDatabaseEntityTransformer} from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer";
import {CustomRepositoryNotFoundError} from "../error/CustomRepositoryNotFoundError";
import {getMetadataArgsStorage, ObjectLiteral} from "../index";
import {EntitySchema, getMetadataArgsStorage, ObjectLiteral} from "../index";
import {AbstractRepository} from "../repository/AbstractRepository";
import {CustomRepositoryCannotInheritRepositoryError} from "../error/CustomRepositoryCannotInheritRepositoryError";
import {QueryRunner} from "../query-runner/QueryRunner";
@ -131,7 +131,7 @@ export class EntityManager {
/**
* Creates a new query builder that can be used to build a sql query.
*/
createQueryBuilder<Entity>(entityClass: ObjectType<Entity>|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity>;
createQueryBuilder<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|Function|string, alias: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity>;
/**
* Creates a new query builder that can be used to build a sql query.
@ -141,9 +141,9 @@ export class EntityManager {
/**
* Creates a new query builder that can be used to build a sql query.
*/
createQueryBuilder<Entity>(entityClass?: ObjectType<Entity>|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity> {
createQueryBuilder<Entity>(entityClass?: ObjectType<Entity>|EntitySchema<Entity>|Function|string|QueryRunner, alias?: string, queryRunner?: QueryRunner): SelectQueryBuilder<Entity> {
if (alias) {
return this.connection.createQueryBuilder(entityClass as Function|string, alias, queryRunner || this.queryRunner);
return this.connection.createQueryBuilder(entityClass as Function|EntitySchema<Entity>|string, alias, queryRunner || this.queryRunner);
} else {
return this.connection.createQueryBuilder(entityClass as QueryRunner|undefined || this.queryRunner);
@ -199,19 +199,19 @@ export class EntityManager {
* Creates a new entity instance and copies all entity properties from this object into a new entity.
* Note that it copies only properties that present in entity schema.
*/
create<Entity>(entityClass: ObjectType<Entity>|string, plainObject: DeepPartial<Entity>): Entity;
create<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, plainObject: DeepPartial<Entity>): Entity;
/**
* Creates a new entities and copies all entity properties from given objects into their new entities.
* Note that it copies only properties that present in entity schema.
*/
create<Entity>(entityClass: ObjectType<Entity>|string, plainObjects: DeepPartial<Entity>[]): Entity[];
create<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, plainObjects: DeepPartial<Entity>[]): Entity[];
/**
* Creates a new entity instance or instances.
* Can copy properties from the given object into new entities.
*/
create<Entity>(entityClass: ObjectType<Entity>|string, plainObjectOrObjects?: DeepPartial<Entity>|DeepPartial<Entity>[]): Entity|Entity[] {
create<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, plainObjectOrObjects?: DeepPartial<Entity>|DeepPartial<Entity>[]): Entity|Entity[] {
const metadata = this.connection.getMetadata(entityClass);
if (!plainObjectOrObjects)
@ -228,7 +228,7 @@ export class EntityManager {
/**
* Merges two entities into one new entity.
*/
merge<Entity>(entityClass: ObjectType<Entity>|string, mergeIntoEntity: Entity, ...entityLikes: DeepPartial<Entity>[]): Entity { // todo: throw exception if entity manager is released
merge<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, mergeIntoEntity: Entity, ...entityLikes: DeepPartial<Entity>[]): Entity { // todo: throw exception if entity manager is released
const metadata = this.connection.getMetadata(entityClass);
entityLikes.forEach(object => this.plainObjectToEntityTransformer.transform(mergeIntoEntity, object, metadata));
return mergeIntoEntity;
@ -240,7 +240,7 @@ export class EntityManager {
* and returns this new entity. This new entity is actually a loaded from the db entity with all properties
* replaced from the new object.
*/
async preload<Entity>(entityClass: ObjectType<Entity>|string, entityLike: DeepPartial<Entity>): Promise<Entity|undefined> {
async preload<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, entityLike: DeepPartial<Entity>): Promise<Entity|undefined> {
const metadata = this.connection.getMetadata(entityClass);
const plainObjectToDatabaseEntityTransformer = new PlainObjectToDatabaseEntityTransformer(this.connection.manager);
const transformedEntity = await plainObjectToDatabaseEntityTransformer.transform(entityLike, metadata);
@ -266,18 +266,18 @@ export class EntityManager {
* Saves all given entities in the database.
* If entities do not exist in the database then inserts, otherwise updates.
*/
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: ObjectType<Entity>|string, entities: T[], options?: SaveOptions): Promise<T[]>;
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: ObjectType<Entity>|EntitySchema<Entity>|string, entities: T[], options?: SaveOptions): Promise<T[]>;
/**
* Saves all given entities in the database.
* If entities do not exist in the database then inserts, otherwise updates.
*/
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: ObjectType<Entity>|string, entity: T, options?: SaveOptions): Promise<T>;
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: ObjectType<Entity>|EntitySchema<Entity>|string, entity: T, options?: SaveOptions): Promise<T>;
/**
* Saves a given entity in the database.
*/
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: (T|T[])|ObjectType<Entity>|string, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise<T|T[]> {
save<Entity, T extends DeepPartial<Entity>>(targetOrEntity: (T|T[])|ObjectType<Entity>|EntitySchema<Entity>|string, maybeEntityOrOptions?: T|T[], maybeOptions?: SaveOptions): Promise<T|T[]> {
// normalize mixed parameters
const target = (arguments.length > 1 && (targetOrEntity instanceof Function || typeof targetOrEntity === "string")) ? targetOrEntity as Function|string : undefined;
@ -302,7 +302,7 @@ export class EntityManager {
/**
* Removes a given entity from the database.
*/
remove<Entity>(targetOrEntity: ObjectType<Entity>|string, entity: Entity, options?: RemoveOptions): Promise<Entity>;
remove<Entity>(targetOrEntity: ObjectType<Entity>|EntitySchema<Entity>|string, entity: Entity, options?: RemoveOptions): Promise<Entity>;
/**
* Removes a given entity from the database.
@ -312,7 +312,7 @@ export class EntityManager {
/**
* Removes a given entity from the database.
*/
remove<Entity>(targetOrEntity: ObjectType<Entity>|string, entity: Entity[], options?: RemoveOptions): Promise<Entity[]>;
remove<Entity>(targetOrEntity: ObjectType<Entity>|EntitySchema<Entity>|string, entity: Entity[], options?: RemoveOptions): Promise<Entity[]>;
/**
* Removes a given entity from the database.
@ -341,7 +341,7 @@ export class EntityManager {
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
* You can execute bulk inserts using this method.
*/
async insert<Entity>(target: ObjectType<Entity>|string, entity: QueryPartialEntity<Entity>|(QueryPartialEntity<Entity>[]), options?: SaveOptions): Promise<InsertResult> {
async insert<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string, entity: QueryPartialEntity<Entity>|(QueryPartialEntity<Entity>[]), options?: SaveOptions): Promise<InsertResult> {
return this.createQueryBuilder()
.insert()
.into(target)
@ -355,7 +355,7 @@ export class EntityManager {
* Executes fast and efficient UPDATE query.
* Does not check if entity exist in the database.
*/
update<Entity>(target: ObjectType<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<UpdateResult> {
update<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<UpdateResult> {
if (typeof criteria === "string" ||
typeof criteria === "number" ||
criteria instanceof Date ||
@ -382,7 +382,7 @@ export class EntityManager {
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
delete<Entity>(targetOrEntity: ObjectType<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, options?: RemoveOptions): Promise<DeleteResult> {
delete<Entity>(targetOrEntity: ObjectType<Entity>|EntitySchema<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, options?: RemoveOptions): Promise<DeleteResult> {
if (typeof criteria === "string" ||
typeof criteria === "number" ||
criteria instanceof Date ||
@ -407,19 +407,19 @@ export class EntityManager {
* Counts entities that match given options.
* Useful for pagination.
*/
count<Entity>(entityClass: ObjectType<Entity>|string, options?: FindManyOptions<Entity>): Promise<number>;
count<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, options?: FindManyOptions<Entity>): Promise<number>;
/**
* Counts entities that match given conditions.
* Useful for pagination.
*/
count<Entity>(entityClass: ObjectType<Entity>|string, conditions?: DeepPartial<Entity>): Promise<number>;
count<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, conditions?: DeepPartial<Entity>): Promise<number>;
/**
* Counts entities that match given find options or conditions.
* Useful for pagination.
*/
async count<Entity>(entityClass: ObjectType<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<number> {
async count<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<number> {
const metadata = this.connection.getMetadata(entityClass);
const qb = this.createQueryBuilder(entityClass, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name);
return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getCount();
@ -428,17 +428,17 @@ export class EntityManager {
/**
* Finds entities that match given options.
*/
find<Entity>(entityClass: ObjectType<Entity>|string, options?: FindManyOptions<Entity>): Promise<Entity[]>;
find<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, options?: FindManyOptions<Entity>): Promise<Entity[]>;
/**
* Finds entities that match given conditions.
*/
find<Entity>(entityClass: ObjectType<Entity>|string, conditions?: DeepPartial<Entity>): Promise<Entity[]>;
find<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, conditions?: DeepPartial<Entity>): Promise<Entity[]>;
/**
* Finds entities that match given find options or conditions.
*/
async find<Entity>(entityClass: ObjectType<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
async find<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
const metadata = this.connection.getMetadata(entityClass);
const qb = this.createQueryBuilder(entityClass, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name);
@ -453,21 +453,21 @@ export class EntityManager {
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
findAndCount<Entity>(entityClass: ObjectType<Entity>|string, options?: FindManyOptions<Entity>): Promise<[Entity[], number]>;
findAndCount<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, options?: FindManyOptions<Entity>): Promise<[Entity[], number]>;
/**
* Finds entities that match given conditions.
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
findAndCount<Entity>(entityClass: ObjectType<Entity>|string, conditions?: DeepPartial<Entity>): Promise<[Entity[], number]>;
findAndCount<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, conditions?: DeepPartial<Entity>): Promise<[Entity[], number]>;
/**
* Finds entities that match given find options and conditions.
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
async findAndCount<Entity>(entityClass: ObjectType<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<[Entity[], number]> {
async findAndCount<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<[Entity[], number]> {
const metadata = this.connection.getMetadata(entityClass);
const qb = this.createQueryBuilder(entityClass, FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || metadata.name);
@ -481,19 +481,19 @@ export class EntityManager {
* Finds entities with ids.
* Optionally find options can be applied.
*/
findByIds<Entity>(entityClass: ObjectType<Entity>|string, ids: any[], options?: FindManyOptions<Entity>): Promise<Entity[]>;
findByIds<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, ids: any[], options?: FindManyOptions<Entity>): Promise<Entity[]>;
/**
* Finds entities with ids.
* Optionally conditions can be applied.
*/
findByIds<Entity>(entityClass: ObjectType<Entity>|string, ids: any[], conditions?: DeepPartial<Entity>): Promise<Entity[]>;
findByIds<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, ids: any[], conditions?: DeepPartial<Entity>): Promise<Entity[]>;
/**
* Finds entities with ids.
* Optionally find options or conditions can be applied.
*/
async findByIds<Entity>(entityClass: ObjectType<Entity>|string, ids: any[], optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
async findByIds<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, ids: any[], optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
// if no ids passed, no need to execute a query - just return an empty array of values
if (!ids.length)
@ -511,22 +511,22 @@ export class EntityManager {
/**
* Finds first entity that matches given find options.
*/
findOne<Entity>(entityClass: ObjectType<Entity>|string, id?: string|number|Date|ObjectID, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
findOne<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, id?: string|number|Date|ObjectID, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
/**
* Finds first entity that matches given find options.
*/
findOne<Entity>(entityClass: ObjectType<Entity>|string, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
findOne<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
/**
* Finds first entity that matches given conditions.
*/
findOne<Entity>(entityClass: ObjectType<Entity>|string, conditions?: DeepPartial<Entity>, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
findOne<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, conditions?: DeepPartial<Entity>, options?: FindOneOptions<Entity>): Promise<Entity|undefined>;
/**
* Finds first entity that matches given conditions.
*/
async findOne<Entity>(entityClass: ObjectType<Entity>|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions<Entity>|DeepPartial<Entity>, maybeOptions?: FindOneOptions<Entity>): Promise<Entity|undefined> {
async findOne<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions<Entity>|DeepPartial<Entity>, maybeOptions?: FindOneOptions<Entity>): Promise<Entity|undefined> {
let findOptions: FindOneOptions<any>|undefined = undefined;
if (FindOptionsUtils.isFindOneOptions(idOrOptionsOrConditions)) {
@ -568,22 +568,22 @@ export class EntityManager {
/**
* Finds first entity that matches given find options or rejects the returned promise on error.
*/
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|string, id?: string|number|Date|ObjectID, options?: FindOneOptions<Entity>): Promise<Entity>;
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, id?: string|number|Date|ObjectID, options?: FindOneOptions<Entity>): Promise<Entity>;
/**
* Finds first entity that matches given find options or rejects the returned promise on error.
*/
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|string, options?: FindOneOptions<Entity>): Promise<Entity>;
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, options?: FindOneOptions<Entity>): Promise<Entity>;
/**
* Finds first entity that matches given conditions or rejects the returned promise on error.
*/
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|string, conditions?: DeepPartial<Entity>, options?: FindOneOptions<Entity>): Promise<Entity>;
findOneOrFail<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, conditions?: DeepPartial<Entity>, options?: FindOneOptions<Entity>): Promise<Entity>;
/**
* Finds first entity that matches given conditions or rejects the returned promise on error.
*/
async findOneOrFail<Entity>(entityClass: ObjectType<Entity>|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions<Entity>|DeepPartial<Entity>, maybeOptions?: FindOneOptions<Entity>): Promise<Entity> {
async findOneOrFail<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string, idOrOptionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions<Entity>|DeepPartial<Entity>, maybeOptions?: FindOneOptions<Entity>): Promise<Entity> {
return this.findOne(entityClass, idOrOptionsOrConditions as any, maybeOptions).then((value) => {
if (value === undefined) {
return Promise.reject(new EntityNotFoundError(entityClass, idOrOptionsOrConditions));
@ -598,7 +598,7 @@ export class EntityManager {
* Note: this method uses TRUNCATE and may not work as you expect in transactions on some platforms.
* @see https://stackoverflow.com/a/5972738/925151
*/
async clear<Entity>(entityClass: ObjectType<Entity>|string): Promise<void> {
async clear<Entity>(entityClass: ObjectType<Entity>|EntitySchema<Entity>|string): Promise<void> {
const metadata = this.connection.getMetadata(entityClass);
const queryRunner = this.queryRunner || this.connection.createQueryRunner("master");
try {
@ -616,7 +616,7 @@ export class EntityManager {
* repository aggregator, where each repository is individually created for this entity manager.
* When single database connection is not used, repository is being obtained from the connection.
*/
getRepository<Entity>(target: ObjectType<Entity>|string): Repository<Entity> {
getRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): Repository<Entity> {
// throw exception if there is no repository with this target registered
if (!this.connection.hasMetadata(target))
@ -640,7 +640,7 @@ export class EntityManager {
* repository aggregator, where each repository is individually created for this entity manager.
* When single database connection is not used, repository is being obtained from the connection.
*/
getTreeRepository<Entity>(target: ObjectType<Entity>|string): TreeRepository<Entity> {
getTreeRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): TreeRepository<Entity> {
// tree tables aren't supported by some drivers (mongodb)
if (this.connection.driver.treeSupport === false)
@ -657,7 +657,7 @@ export class EntityManager {
/**
* Gets mongodb repository for the given entity class.
*/
getMongoRepository<Entity>(target: string|ObjectType<Entity>): MongoRepository<Entity> {
getMongoRepository<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string): MongoRepository<Entity> {
return this.connection.getMongoRepository<Entity>(target);
}

View File

@ -50,6 +50,7 @@ import {UpdateResult} from "../query-builder/result/UpdateResult";
import {RemoveOptions} from "../repository/RemoveOptions";
import {DeleteResult} from "../query-builder/result/DeleteResult";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {EntitySchema} from "../index";
/**
* Entity manager supposed to work with any entity, automatically find its repository and call its methods,
@ -85,7 +86,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Finds entities that match given find options or conditions.
*/
async find<Entity>(entityClassOrName: ObjectType<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
async find<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions);
const cursor = await this.createEntityCursor(entityClassOrName, query);
if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
@ -104,7 +105,7 @@ export class MongoEntityManager extends EntityManager {
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
async findAndCount<Entity>(entityClassOrName: ObjectType<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<[ Entity[], number ]> {
async findAndCount<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<[ Entity[], number ]> {
const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions);
const cursor = await this.createEntityCursor(entityClassOrName, query);
if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
@ -126,7 +127,7 @@ export class MongoEntityManager extends EntityManager {
* Finds entities by ids.
* Optionally find options can be applied.
*/
async findByIds<Entity>(entityClassOrName: ObjectType<Entity>|string, ids: any[], optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
async findByIds<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, ids: any[], optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
const metadata = this.connection.getMetadata(entityClassOrName);
const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions) || {};
const objectIdInstance = PlatformTools.load("mongodb").ObjectID;
@ -152,7 +153,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Finds first entity that matches given conditions and/or find options.
*/
async findOne<Entity>(entityClassOrName: ObjectType<Entity>|string,
async findOne<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string,
optionsOrConditions?: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|FindOneOptions<Entity>|DeepPartial<Entity>,
maybeOptions?: FindOneOptions<Entity>): Promise<Entity|undefined> {
const objectIdInstance = PlatformTools.load("mongodb").ObjectID;
@ -179,7 +180,7 @@ export class MongoEntityManager extends EntityManager {
* Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted.
* You can execute bulk inserts using this method.
*/
async insert<Entity>(target: ObjectType<Entity>|string, entity: QueryPartialEntity<Entity>|QueryPartialEntity<Entity>[], options?: SaveOptions): Promise<InsertResult> {
async insert<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string, entity: QueryPartialEntity<Entity>|QueryPartialEntity<Entity>[], options?: SaveOptions): Promise<InsertResult> {
// todo: convert entity to its database name
const result = new InsertResult();
if (entity instanceof Array) {
@ -204,7 +205,7 @@ export class MongoEntityManager extends EntityManager {
* Executes fast and efficient UPDATE query.
* Does not check if entity exist in the database.
*/
async update<Entity>(target: ObjectType<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<UpdateResult> {
async update<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, partialEntity: DeepPartial<Entity>, options?: SaveOptions): Promise<UpdateResult> {
if (criteria instanceof Array) {
await Promise.all((criteria as any[]).map(criteriaItem => {
return this.update(target, criteriaItem, partialEntity);
@ -224,7 +225,7 @@ export class MongoEntityManager extends EntityManager {
* Executes fast and efficient DELETE query.
* Does not check if entity exist in the database.
*/
async delete<Entity>(target: ObjectType<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, options?: RemoveOptions): Promise<DeleteResult> {
async delete<Entity>(target: ObjectType<Entity>|EntitySchema<Entity>|string, criteria: string|string[]|number|number[]|Date|Date[]|ObjectID|ObjectID[]|DeepPartial<Entity>, options?: RemoveOptions): Promise<DeleteResult> {
if (criteria instanceof Array) {
await Promise.all((criteria as any[]).map(criteriaItem => {
return this.delete(target, criteriaItem);
@ -244,7 +245,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Creates a cursor for a query that can be used to iterate over results from MongoDB.
*/
createCursor<Entity>(entityClassOrName: ObjectType<Entity>|string, query?: ObjectLiteral): Cursor<Entity> {
createCursor<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query?: ObjectLiteral): Cursor<Entity> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.cursor(metadata.tableName, query);
}
@ -253,7 +254,7 @@ export class MongoEntityManager extends EntityManager {
* Creates a cursor for a query that can be used to iterate over results from MongoDB.
* This returns modified version of cursor that transforms each result into Entity model.
*/
createEntityCursor<Entity>(entityClassOrName: ObjectType<Entity>|string, query?: ObjectLiteral): Cursor<Entity> {
createEntityCursor<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query?: ObjectLiteral): Cursor<Entity> {
const metadata = this.connection.getMetadata(entityClassOrName);
const cursor = this.createCursor(entityClassOrName, query);
@ -301,7 +302,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Execute an aggregation framework pipeline against the collection.
*/
aggregate<Entity>(entityClassOrName: ObjectType<Entity>|string, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor<Entity> {
aggregate<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, pipeline: ObjectLiteral[], options?: CollectionAggregationOptions): AggregationCursor<Entity> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.aggregate(metadata.tableName, pipeline, options);
}
@ -309,7 +310,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Perform a bulkWrite operation without a fluent API.
*/
bulkWrite<Entity>(entityClassOrName: ObjectType<Entity>|string, operations: ObjectLiteral[], options?: CollectionBluckWriteOptions): Promise<BulkWriteOpResultObject> {
bulkWrite<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, operations: ObjectLiteral[], options?: CollectionBluckWriteOptions): Promise<BulkWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.bulkWrite(metadata.tableName, operations, options);
}
@ -317,7 +318,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Count number of matching documents in the db to a query.
*/
count<Entity>(entityClassOrName: ObjectType<Entity>|string, query?: ObjectLiteral, options?: MongoCountPreferences): Promise<any> {
count<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query?: ObjectLiteral, options?: MongoCountPreferences): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.count(metadata.tableName, query, options);
}
@ -325,7 +326,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Creates an index on the db and collection.
*/
createCollectionIndex<Entity>(entityClassOrName: ObjectType<Entity>|string, fieldOrSpec: string|any, options?: MongodbIndexOptions): Promise<string> {
createCollectionIndex<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, fieldOrSpec: string|any, options?: MongodbIndexOptions): Promise<string> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.createCollectionIndex(metadata.tableName, fieldOrSpec, options);
}
@ -335,7 +336,7 @@ export class MongoEntityManager extends EntityManager {
* Earlier version of MongoDB will throw a command not supported error.
* Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
*/
createCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|string, indexSpecs: ObjectLiteral[]): Promise<void> {
createCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, indexSpecs: ObjectLiteral[]): Promise<void> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.createCollectionIndexes(metadata.tableName, indexSpecs);
}
@ -343,7 +344,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Delete multiple documents on MongoDB.
*/
deleteMany<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, options?: CollectionOptions): Promise<DeleteWriteOpResultObject> {
deleteMany<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, options?: CollectionOptions): Promise<DeleteWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.deleteMany(metadata.tableName, query, options);
}
@ -351,7 +352,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Delete a document on MongoDB.
*/
deleteOne<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, options?: CollectionOptions): Promise<DeleteWriteOpResultObject> {
deleteOne<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, options?: CollectionOptions): Promise<DeleteWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.deleteOne(metadata.tableName, query, options);
}
@ -359,7 +360,7 @@ export class MongoEntityManager extends EntityManager {
/**
* The distinct command returns returns a list of distinct values for the given key across a collection.
*/
distinct<Entity>(entityClassOrName: ObjectType<Entity>|string, key: string, query: ObjectLiteral, options?: { readPreference?: ReadPreference|string }): Promise<any> {
distinct<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, key: string, query: ObjectLiteral, options?: { readPreference?: ReadPreference|string }): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.distinct(metadata.tableName, key, query, options);
}
@ -367,7 +368,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Drops an index from this collection.
*/
dropCollectionIndex<Entity>(entityClassOrName: ObjectType<Entity>|string, indexName: string, options?: CollectionOptions): Promise<any> {
dropCollectionIndex<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, indexName: string, options?: CollectionOptions): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.dropCollectionIndex(metadata.tableName, indexName, options);
}
@ -375,7 +376,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Drops all indexes from the collection.
*/
dropCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|string): Promise<any> {
dropCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.dropCollectionIndexes(metadata.tableName);
}
@ -383,7 +384,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
*/
findOneAndDelete<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, options?: { projection?: Object, sort?: Object, maxTimeMS?: number }): Promise<FindAndModifyWriteOpResultObject> {
findOneAndDelete<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, options?: { projection?: Object, sort?: Object, maxTimeMS?: number }): Promise<FindAndModifyWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.findOneAndDelete(metadata.tableName, query, options);
}
@ -391,7 +392,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
*/
findOneAndReplace<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, replacement: Object, options?: FindOneAndReplaceOption): Promise<FindAndModifyWriteOpResultObject> {
findOneAndReplace<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, replacement: Object, options?: FindOneAndReplaceOption): Promise<FindAndModifyWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.findOneAndReplace(metadata.tableName, query, replacement, options);
}
@ -399,7 +400,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
*/
findOneAndUpdate<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, update: Object, options?: FindOneAndReplaceOption): Promise<FindAndModifyWriteOpResultObject> {
findOneAndUpdate<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, update: Object, options?: FindOneAndReplaceOption): Promise<FindAndModifyWriteOpResultObject> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.findOneAndUpdate(metadata.tableName, query, update, options);
}
@ -407,7 +408,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Execute a geo search using a geo haystack index on a collection.
*/
geoHaystackSearch<Entity>(entityClassOrName: ObjectType<Entity>|string, x: number, y: number, options?: GeoHaystackSearchOptions): Promise<any> {
geoHaystackSearch<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, x: number, y: number, options?: GeoHaystackSearchOptions): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.geoHaystackSearch(metadata.tableName, x, y, options);
}
@ -415,7 +416,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Execute the geoNear command to search for items in the collection.
*/
geoNear<Entity>(entityClassOrName: ObjectType<Entity>|string, x: number, y: number, options?: GeoNearOptions): Promise<any> {
geoNear<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, x: number, y: number, options?: GeoNearOptions): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.geoNear(metadata.tableName, x, y, options);
}
@ -423,7 +424,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Run a group command across a collection.
*/
group<Entity>(entityClassOrName: ObjectType<Entity>|string, keys: Object|Array<any>|Function|Code, condition: Object, initial: Object, reduce: Function|Code, finalize: Function|Code, command: boolean, options?: { readPreference?: ReadPreference | string }): Promise<any> {
group<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, keys: Object|Array<any>|Function|Code, condition: Object, initial: Object, reduce: Function|Code, finalize: Function|Code, command: boolean, options?: { readPreference?: ReadPreference | string }): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.group(metadata.tableName, keys, condition, initial, reduce, finalize, command, options);
}
@ -431,7 +432,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Retrieve all the indexes on the collection.
*/
collectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|string): Promise<any> {
collectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.collectionIndexes(metadata.tableName);
}
@ -439,7 +440,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Retrieve all the indexes on the collection.
*/
collectionIndexExists<Entity>(entityClassOrName: ObjectType<Entity>|string, indexes: string|string[]): Promise<boolean> {
collectionIndexExists<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, indexes: string|string[]): Promise<boolean> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.collectionIndexExists(metadata.tableName, indexes);
}
@ -447,7 +448,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Retrieves this collections index info.
*/
collectionIndexInformation<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: { full: boolean }): Promise<any> {
collectionIndexInformation<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: { full: boolean }): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.collectionIndexInformation(metadata.tableName, options);
}
@ -455,7 +456,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Initiate an In order bulk write operation, operations will be serially executed in the order they are added, creating a new operation for each switch in types.
*/
initializeOrderedBulkOp<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: CollectionOptions): OrderedBulkOperation {
initializeOrderedBulkOp<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: CollectionOptions): OrderedBulkOperation {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.initializeOrderedBulkOp(metadata.tableName, options);
}
@ -463,7 +464,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Initiate a Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.
*/
initializeUnorderedBulkOp<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: CollectionOptions): UnorderedBulkOperation {
initializeUnorderedBulkOp<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: CollectionOptions): UnorderedBulkOperation {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.initializeUnorderedBulkOp(metadata.tableName, options);
}
@ -471,7 +472,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Inserts an array of documents into MongoDB.
*/
insertMany<Entity>(entityClassOrName: ObjectType<Entity>|string, docs: ObjectLiteral[], options?: CollectionInsertManyOptions): Promise<InsertWriteOpResult> {
insertMany<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, docs: ObjectLiteral[], options?: CollectionInsertManyOptions): Promise<InsertWriteOpResult> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.insertMany(metadata.tableName, docs, options);
}
@ -479,7 +480,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Inserts a single document into MongoDB.
*/
insertOne<Entity>(entityClassOrName: ObjectType<Entity>|string, doc: ObjectLiteral, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult> {
insertOne<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, doc: ObjectLiteral, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.insertOne(metadata.tableName, doc, options);
}
@ -487,7 +488,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Returns if the collection is a capped collection.
*/
isCapped<Entity>(entityClassOrName: ObjectType<Entity>|string): Promise<any> {
isCapped<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.isCapped(metadata.tableName);
}
@ -495,7 +496,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Get the list of all indexes information for the collection.
*/
listCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: { batchSize?: number, readPreference?: ReadPreference|string }): CommandCursor {
listCollectionIndexes<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: { batchSize?: number, readPreference?: ReadPreference|string }): CommandCursor {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.listCollectionIndexes(metadata.tableName, options);
}
@ -503,7 +504,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
*/
mapReduce<Entity>(entityClassOrName: ObjectType<Entity>|string, map: Function|string, reduce: Function|string, options?: MapReduceOptions): Promise<any> {
mapReduce<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, map: Function|string, reduce: Function|string, options?: MapReduceOptions): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.mapReduce(metadata.tableName, map, reduce, options);
}
@ -512,7 +513,7 @@ export class MongoEntityManager extends EntityManager {
* Return N number of parallel cursors for a collection allowing parallel reading of entire collection.
* There are no ordering guarantees for returned results.
*/
parallelCollectionScan<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: ParallelCollectionScanOptions): Promise<Cursor<Entity>[]> {
parallelCollectionScan<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: ParallelCollectionScanOptions): Promise<Cursor<Entity>[]> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.parallelCollectionScan(metadata.tableName, options);
}
@ -520,7 +521,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Reindex all indexes on the collection Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
*/
reIndex<Entity>(entityClassOrName: ObjectType<Entity>|string): Promise<any> {
reIndex<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string): Promise<any> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.reIndex(metadata.tableName);
}
@ -528,7 +529,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Reindex all indexes on the collection Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
*/
rename<Entity>(entityClassOrName: ObjectType<Entity>|string, newName: string, options?: { dropTarget?: boolean }): Promise<Collection> {
rename<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, newName: string, options?: { dropTarget?: boolean }): Promise<Collection> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.rename(metadata.tableName, newName, options);
}
@ -536,7 +537,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Replace a document on MongoDB.
*/
replaceOne<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, doc: ObjectLiteral, options?: ReplaceOneOptions): Promise<UpdateWriteOpResult> {
replaceOne<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, doc: ObjectLiteral, options?: ReplaceOneOptions): Promise<UpdateWriteOpResult> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.replaceOne(metadata.tableName, query, doc, options);
}
@ -544,7 +545,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Get all the collection statistics.
*/
stats<Entity>(entityClassOrName: ObjectType<Entity>|string, options?: { scale: number }): Promise<CollStats> {
stats<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, options?: { scale: number }): Promise<CollStats> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.stats(metadata.tableName, options);
}
@ -552,7 +553,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Update multiple documents on MongoDB.
*/
updateMany<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, update: ObjectLiteral, options?: { upsert?: boolean, w?: any, wtimeout?: number, j?: boolean }): Promise<UpdateWriteOpResult> {
updateMany<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, update: ObjectLiteral, options?: { upsert?: boolean, w?: any, wtimeout?: number, j?: boolean }): Promise<UpdateWriteOpResult> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.updateMany(metadata.tableName, query, update, options);
}
@ -560,7 +561,7 @@ export class MongoEntityManager extends EntityManager {
/**
* Update a single document on MongoDB.
*/
updateOne<Entity>(entityClassOrName: ObjectType<Entity>|string, query: ObjectLiteral, update: ObjectLiteral, options?: ReplaceOneOptions): Promise<UpdateWriteOpResult> {
updateOne<Entity>(entityClassOrName: ObjectType<Entity>|EntitySchema<Entity>|string, query: ObjectLiteral, update: ObjectLiteral, options?: ReplaceOneOptions): Promise<UpdateWriteOpResult> {
const metadata = this.connection.getMetadata(entityClassOrName);
return this.queryRunner.updateOne(metadata.tableName, query, update, options);
}

View File

@ -45,4 +45,5 @@ export class SqljsEntityManager extends EntityManager {
exportDatabase(): Uint8Array {
return this.driver.export();
}
}

View File

@ -1,52 +1,11 @@
import {EntitySchemaTable} from "./EntitySchemaTable";
import {EntitySchemaIndex} from "./EntitySchemaIndex";
import {EntitySchemaColumn} from "./EntitySchemaColumn";
import {EntitySchemaRelation} from "./EntitySchemaRelation";
import {EntitySchemaOptions} from "./EntitySchemaOptions";
/**
* Interface for entity metadata mappings stored inside "schemas" instead of models decorated by decorators.
*/
export interface EntitySchema { // todo: make it-to-date
export class EntitySchema<T> {
/**
* Name of the schema it extends.
*/
extends?: string;
/**
* Target bind to this entity schema. Optional.
*/
target?: Function;
/**
* Entity name.
*/
name: string;
/**
* Entity table's options.
*/
table?: EntitySchemaTable;
/**
* Entity column's options.
*/
columns: {
[columnName: string]: EntitySchemaColumn
};
/**
* Entity relation's options.
*/
relations?: {
[relationName: string]: EntitySchemaRelation;
};
/**
* Entity indices options.
*/
indices?: {
[indexName: string]: EntitySchemaIndex;
};
constructor(public options: EntitySchemaOptions<T>) {
}
}

View File

@ -1,6 +1,6 @@
import {ColumnType} from "../driver/types/ColumnTypes";
export interface EntitySchemaColumn {
export interface EntitySchemaColumnOptions {
/**
* Indicates if this column is a primary column.

View File

@ -1,4 +1,4 @@
export interface EntitySchemaIndex {
export interface EntitySchemaIndexOptions {
/**
* Index column names.

View File

@ -0,0 +1,52 @@
import {EntitySchemaTableOptions} from "./EntitySchemaTableOptions";
import {EntitySchemaIndexOptions} from "./EntitySchemaIndexOptions";
import {EntitySchemaColumnOptions} from "./EntitySchemaColumnOptions";
import {EntitySchemaRelationOptions} from "./EntitySchemaRelationOptions";
/**
* Interface for entity metadata mappings stored inside "schemas" instead of models decorated by decorators.
*/
export class EntitySchemaOptions<T> {
/**
* Name of the schema it extends.
*/
extends?: string;
/**
* Target bind to this entity schema. Optional.
*/
target?: Function;
/**
* Entity name.
*/
name: string;
/**
* Entity table's options.
*/
table?: EntitySchemaTableOptions;
/**
* Entity column's options.
*/
columns: {
[P in keyof T]?: EntitySchemaColumnOptions;
};
/**
* Entity relation's options.
*/
relations?: {
[P in keyof T]?: EntitySchemaRelationOptions;
};
/**
* Entity indices options.
*/
indices?: {
[indexName: string]: EntitySchemaIndexOptions;
};
}

View File

@ -3,7 +3,7 @@ import {RelationType} from "../metadata/types/RelationTypes";
import {JoinTableMultipleColumnsOptions} from "../decorator/options/JoinTableMuplipleColumnsOptions";
import {OnDeleteType} from "../metadata/types/OnDeleteType";
export interface EntitySchemaRelation {
export interface EntitySchemaRelationOptions {
/**
* Indicates with which entity this relation is made.

View File

@ -1,7 +1,7 @@
import {TableType} from "../metadata/types/TableTypes";
import {OrderByCondition} from "../find-options/OrderByCondition";
export interface EntitySchemaTable {
export interface EntitySchemaTableOptions {
/**
* Table name.

View File

@ -24,15 +24,16 @@ export class EntitySchemaTransformer {
/**
* Transforms entity schema into new metadata args storage object.
*/
transform(schemas: EntitySchema[]): MetadataArgsStorage {
transform(schemas: EntitySchema<any>[]): MetadataArgsStorage {
const metadataArgsStorage = new MetadataArgsStorage();
schemas.forEach(schema => {
schemas.forEach(entitySchema => {
const options = entitySchema.options;
// add table metadata args from the schema
const table = schema.table || {} as any;
const table = options.table || {} as any;
const tableMetadata: TableMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
name: table.name,
type: table.type || "regular",
orderBy: table.orderBy
@ -40,8 +41,8 @@ export class EntitySchemaTransformer {
metadataArgsStorage.tables.push(tableMetadata);
// add columns metadata args from the schema
Object.keys(schema.columns).forEach(columnName => {
const tableColumn = schema.columns[columnName];
Object.keys(options.columns).forEach(columnName => {
const tableColumn = options.columns[columnName]!;
let mode: ColumnMode = "regular";
if (tableColumn.createDate)
mode = "createDate";
@ -57,7 +58,7 @@ export class EntitySchemaTransformer {
mode = "objectId";
const columnAgrs: ColumnMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
mode: mode,
propertyName: columnName,
options: {
@ -77,7 +78,7 @@ export class EntitySchemaTransformer {
if (tableColumn.generated) {
const generationArgs: GeneratedMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: columnName,
strategy: typeof tableColumn.generated === "string" ? tableColumn.generated : "increment"
};
@ -86,11 +87,11 @@ export class EntitySchemaTransformer {
});
// add relation metadata args from the schema
if (schema.relations) {
Object.keys(schema.relations).forEach(relationName => {
const relationSchema = schema.relations![relationName];
if (options.relations) {
Object.keys(options.relations).forEach(relationName => {
const relationSchema = options.relations![relationName]!;
const relation: RelationMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: relationName,
relationType: relationSchema.type,
isLazy: relationSchema.isLazy || false,
@ -111,13 +112,13 @@ export class EntitySchemaTransformer {
if (relationSchema.joinColumn) {
if (typeof relationSchema.joinColumn === "boolean") {
const joinColumn: JoinColumnMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: relationName
};
metadataArgsStorage.joinColumns.push(joinColumn);
} else {
const joinColumn: JoinColumnMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: relationName,
name: relationSchema.joinColumn.name,
referencedColumnName: relationSchema.joinColumn.referencedColumnName
@ -130,13 +131,13 @@ export class EntitySchemaTransformer {
if (relationSchema.joinTable) {
if (typeof relationSchema.joinTable === "boolean") {
const joinTable: JoinTableMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: relationName
};
metadataArgsStorage.joinTables.push(joinTable);
} else {
const joinTable: JoinTableMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
propertyName: relationName,
name: relationSchema.joinTable.name,
joinColumns: ((relationSchema.joinTable as JoinTableOptions).joinColumn ? [(relationSchema.joinTable as JoinTableOptions).joinColumn!] : (relationSchema.joinTable as JoinTableMultipleColumnsOptions).joinColumns) as any,
@ -149,11 +150,11 @@ export class EntitySchemaTransformer {
}
// add relation metadata args from the schema
if (schema.indices) {
Object.keys(schema.indices).forEach(indexName => {
const tableIndex = schema.indices![indexName];
if (options.indices) {
Object.keys(options.indices).forEach(indexName => {
const tableIndex = options.indices![indexName];
const indexAgrs: IndexMetadataArgs = {
target: schema.target || schema.name,
target: options.target || options.name,
name: indexName,
unique: tableIndex.unique,
sparse: tableIndex.sparse,

View File

@ -1,11 +1,20 @@
import {EntitySchema} from "../index";
/**
*/
export class EntityMetadataNotFound extends Error {
name = "EntityMetadataNotFound";
constructor(target: Function|string) {
constructor(target: Function|EntitySchema<any>|string) {
super();
const targetName = typeof target === "function" && (<any> target).name ? (<any> target).name : target;
let targetName: string;
if (target instanceof EntitySchema) {
targetName = target.options.name;
} else if (typeof target === "function") {
targetName = target.name;
} else {
targetName = target;
}
this.message = `No metadata for "${targetName}" was found.`;
Object.setPrototypeOf(this, EntityMetadataNotFound.prototype);
this.stack = new Error().stack;

View File

@ -1,4 +1,5 @@
import {ObjectType} from "../common/ObjectType";
import {EntitySchema} from "../index";
/**
* Thrown when no result could be found in methods which are not allowed to return undefined or an empty set.
@ -6,14 +7,19 @@ import {ObjectType} from "../common/ObjectType";
export class EntityNotFoundError extends Error {
name = "EntityNotFound";
constructor(entityClass: ObjectType<any>|string, criteria: any) {
constructor(entityClass: ObjectType<any>|EntitySchema<any>|string, criteria: any) {
super();
Object.setPrototypeOf(this, EntityNotFoundError.prototype);
const className = (typeof entityClass === "string") ? entityClass : entityClass.constructor.name;
let targetName: string;
if (entityClass instanceof EntitySchema) {
targetName = entityClass.options.name;
} else if (typeof entityClass === "function") {
targetName = entityClass.name;
} else {
targetName = entityClass;
}
const criteriaString = this.stringifyCriteria(criteria);
this.message = `Could not find any entity of type "${className}" matching: ${criteriaString}`;
Object.setPrototypeOf(this, EntityNotFoundError.prototype);
this.message = `Could not find any entity of type "${targetName}" matching: ${criteriaString}`;
this.stack = new Error().stack;
}

View File

@ -1,12 +1,21 @@
import {EntitySchema} from "../index";
/**
* Thrown when repository for the given class is not found.
*/
export class RepositoryNotFoundError extends Error {
name = "RepositoryNotFoundError";
constructor(connectionName: string, entityClass: Function|string) {
constructor(connectionName: string, entityClass: Function|EntitySchema<any>|string) {
super();
const targetName = typeof entityClass === "function" && (<any> entityClass).name ? (<any> entityClass).name : entityClass;
let targetName: string;
if (entityClass instanceof EntitySchema) {
targetName = entityClass.options.name;
} else if (typeof entityClass === "function") {
targetName = entityClass.name;
} else {
targetName = entityClass;
}
this.message = `No repository for "${targetName}" was found. Looks like this entity is not registered in ` +
`current "${connectionName}" connection?`;
Object.setPrototypeOf(this, RepositoryNotFoundError.prototype);

View File

@ -1,12 +1,21 @@
import {EntitySchema} from "../index";
/**
* Thrown when repository for the given class is not found.
*/
export class RepositoryNotTreeError extends Error {
name = "RepositoryNotTreeError";
constructor(entityClass: Function|string) {
constructor(target: Function|EntitySchema<any>|string) {
super();
const targetName = typeof entityClass === "function" && (<any> entityClass).name ? (<any> entityClass).name : entityClass;
let targetName: string;
if (target instanceof EntitySchema) {
targetName = target.options.name;
} else if (typeof target === "function") {
targetName = target.name;
} else {
targetName = target;
}
this.message = `Repository of the "${targetName}" class is not a TreeRepository. Try to apply @Tree decorator on your entity.`;
Object.setPrototypeOf(this, RepositoryNotTreeError.prototype);
this.stack = new Error().stack;

View File

@ -4,7 +4,7 @@ import {ObjectLiteral} from "../common/ObjectLiteral";
/**
* Defines a special criteria to find specific entity.
*/
export interface FindOneOptions<Entity> {
export interface FindOneOptions<Entity = any> {
/**
* Specifies what columns should be retrieved.

View File

@ -125,10 +125,10 @@ export {RemoveEvent} from "./subscriber/event/RemoveEvent";
export {EntitySubscriberInterface} from "./subscriber/EntitySubscriberInterface";
export {BaseEntity} from "./repository/BaseEntity";
export {EntitySchema} from "./entity-schema/EntitySchema";
export {EntitySchemaTable} from "./entity-schema/EntitySchemaTable";
export {EntitySchemaColumn} from "./entity-schema/EntitySchemaColumn";
export {EntitySchemaIndex} from "./entity-schema/EntitySchemaIndex";
export {EntitySchemaRelation} from "./entity-schema/EntitySchemaRelation";
export {EntitySchemaTableOptions} from "./entity-schema/EntitySchemaTableOptions";
export {EntitySchemaColumnOptions} from "./entity-schema/EntitySchemaColumnOptions";
export {EntitySchemaIndexOptions} from "./entity-schema/EntitySchemaIndexOptions";
export {EntitySchemaRelationOptions} from "./entity-schema/EntitySchemaRelationOptions";
export {ColumnType} from "./driver/types/ColumnTypes";
export {PromiseUtils} from "./util/PromiseUtils";

View File

@ -11,6 +11,7 @@ import {DeleteResult} from "./result/DeleteResult";
import {ReturningStatementNotSupportedError} from "../error/ReturningStatementNotSupportedError";
import {SqljsDriver} from "../driver/sqljs/SqljsDriver";
import {BroadcasterResult} from "../subscriber/BroadcasterResult";
import {EntitySchema} from "../index";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -106,7 +107,8 @@ export class DeleteQueryBuilder<Entity> extends QueryBuilder<Entity> implements
* Specifies FROM which entity's table select/update/delete will be executed.
* Also sets a main string alias of the selection data.
*/
from<T>(entityTarget: ObjectType<T>|string, aliasName?: string): DeleteQueryBuilder<T> {
from<T>(entityTarget: ObjectType<T>|EntitySchema<T>|string, aliasName?: string): DeleteQueryBuilder<T> {
entityTarget = entityTarget instanceof EntitySchema ? entityTarget.options.name : entityTarget;
const mainAlias = this.createFromAlias(entityTarget, aliasName);
this.expressionMap.setMainAlias(mainAlias);
return (this as any) as DeleteQueryBuilder<T>;

View File

@ -14,6 +14,7 @@ import {ReturningResultsEntityUpdator} from "./ReturningResultsEntityUpdator";
import {AbstractSqliteDriver} from "../driver/sqlite-abstract/AbstractSqliteDriver";
import {SqljsDriver} from "../driver/sqljs/SqljsDriver";
import {BroadcasterResult} from "../subscriber/BroadcasterResult";
import {EntitySchema} from "../";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -136,7 +137,8 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
/**
* Specifies INTO which entity's table insertion will be executed.
*/
into<T>(entityTarget: ObjectType<T>|string, columns?: string[]): InsertQueryBuilder<T> {
into<T>(entityTarget: ObjectType<T>|EntitySchema<T>|string, columns?: string[]): InsertQueryBuilder<T> {
entityTarget = entityTarget instanceof EntitySchema ? entityTarget.options.name : entityTarget;
const mainAlias = this.createFromAlias(entityTarget);
this.expressionMap.setMainAlias(mainAlias);
this.expressionMap.insertColumns = columns || [];

View File

@ -15,6 +15,7 @@ import {EntityMetadata} from "../metadata/EntityMetadata";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {SqljsDriver} from "../driver/sqljs/SqljsDriver";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
import {EntitySchema} from "../";
// todo: completely cover query builder with tests
// todo: entityOrProperty can be target name. implement proper behaviour if it is.
@ -186,7 +187,12 @@ export abstract class QueryBuilder<Entity> {
/**
* Creates UPDATE query for the given entity and applies given update values.
*/
update(entity: Function|string, updateSet?: QueryPartialEntity<Entity>): UpdateQueryBuilder<Entity>;
update<T>(entity: EntitySchema<T>, updateSet?: QueryPartialEntity<T>): UpdateQueryBuilder<T>;
/**
* Creates UPDATE query for the given entity and applies given update values.
*/
update(entity: Function|EntitySchema<Entity>|string, updateSet?: QueryPartialEntity<Entity>): UpdateQueryBuilder<Entity>;
/**
* Creates UPDATE query for the given table name and applies given update values.
@ -196,8 +202,9 @@ export abstract class QueryBuilder<Entity> {
/**
* Creates UPDATE query and applies given update values.
*/
update(entityOrTableNameUpdateSet?: string|Function|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder<any> {
update(entityOrTableNameUpdateSet?: string|Function|EntitySchema<any>|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder<any> {
const updateSet = maybeUpdateSet ? maybeUpdateSet : entityOrTableNameUpdateSet as ObjectLiteral|undefined;
entityOrTableNameUpdateSet = entityOrTableNameUpdateSet instanceof EntitySchema ? entityOrTableNameUpdateSet.options.name : entityOrTableNameUpdateSet;
if (entityOrTableNameUpdateSet instanceof Function || typeof entityOrTableNameUpdateSet === "string") {
const mainAlias = this.createFromAlias(entityOrTableNameUpdateSet);

View File

@ -91,7 +91,6 @@ describe("Connection", () => {
password: "test",
database: "test",
entities: [],
entitySchemas: [],
dropSchema: false,
schemaCreate: false,
enabledDrivers: ["mysql"],

View File

@ -16,7 +16,7 @@ describe("entity-metadata-validator", () => {
entities: [__dirname + "/entity/*{.js,.ts}"]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).to.throw(Error);
});

View File

@ -22,7 +22,7 @@ describe("entity-metadata-validator > initialized relations", () => {
entities: [Post, Category]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Post, Category], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Post, Category]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).to.throw(InitializedRelationError);
});
@ -37,7 +37,7 @@ describe("entity-metadata-validator > initialized relations", () => {
entities: [Image, ImageInfo]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Image, ImageInfo], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Image, ImageInfo]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).to.throw(InitializedRelationError);
});
@ -52,7 +52,7 @@ describe("entity-metadata-validator > initialized relations", () => {
entities: [Category]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Category], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Category]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).not.to.throw(InitializedRelationError);
});
@ -67,7 +67,7 @@ describe("entity-metadata-validator > initialized relations", () => {
entities: [Question, Category]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Question, Category], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([Question, Category]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).not.to.throw(InitializedRelationError);
});

View File

@ -0,0 +1,35 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src";
import {PostEntity} from "./entity/PostEntity";
import {CategoryEntity} from "./entity/CategoryEntity";
// import {expect} from "chai";
describe("entity schemas > basic functionality", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [
PostEntity,
CategoryEntity
],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should perform basic operations with entity", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(PostEntity);
const post = postRepository.create({
title: "First Post",
text: "About first post",
});
await postRepository.save(post);
const loadedPost = await connection.manager.findOne(PostEntity, { title: "First Post" });
loadedPost!.id.should.be.equal(1);
loadedPost!.title.should.be.equal("First Post");
loadedPost!.text.should.be.equal("About first post");
})));
});

View File

@ -0,0 +1,16 @@
import {EntitySchema} from "../../../../../src";
import {Category} from "../model/Category";
export const CategoryEntity = new EntitySchema<Category>({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true
},
name: {
type: String
}
}
});

View File

@ -0,0 +1,25 @@
import {EntitySchema} from "../../../../../src";
import {Post} from "../model/Post";
export const PostEntity = new EntitySchema<Post>({
name: "post",
columns: {
id: {
type: Number,
primary: true,
generated: true
},
title: {
type: String
},
text: {
type: String
}
},
relations: {
categories: {
type: "many-to-many",
target: "category" // CategoryEntity
}
}
});

View File

@ -0,0 +1,6 @@
export interface Category {
id: number;
name: string;
}

View File

@ -0,0 +1,10 @@
import {Category} from "./Category";
export interface Post {
id: number;
title: string;
text: string;
categories: Category[];
}

View File

@ -1,4 +1,6 @@
export const PersonSchema = {
import {EntitySchema} from "../../../../../src";
export const PersonSchema = new EntitySchema<any>({
name: "Person",
columns: {
Id: {
@ -26,4 +28,4 @@ export const PersonSchema = {
]
}
}
};
});

View File

@ -11,7 +11,7 @@ describe("indices > reading index from entity schema and updating database", ()
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entitySchemas: [<any>PersonSchema],
entities: [<any>PersonSchema],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

View File

@ -21,7 +21,7 @@ describe("persistence > order of persistence execution operations", () => {
entities: [__dirname + "/entity/*{.js,.ts}"]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).to.throw(Error);
});

View File

@ -16,7 +16,7 @@ describe("relations > eager relations > circular eager relations", () => {
entities: [__dirname + "/entity/*{.js,.ts}"]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"], []);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"]);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas, connection.driver)).to.throw(Error);
});

View File

@ -7,6 +7,7 @@ import {
import {
Category,
} from "./entity/Category";
import {EntitySchema} from "../../../../../src";
/**
* Because lazy relations are overriding prototype is impossible to run these tests on multiple connections.
@ -14,19 +15,20 @@ import {
*/
describe("basic-lazy-relations", () => {
let userSchema: any, profileSchema: any;
let UserSchema: any, ProfileSchema: any;
const appRoot = require("app-root-path");
const resourceDir = appRoot + "/test/functional/relations/lazy-relations/basic-lazy-relation/";
userSchema = require(resourceDir + "schema/user.json");
profileSchema = require(resourceDir + "schema/profile.json");
UserSchema = new EntitySchema<any>(require(resourceDir + "schema/user.json"));
ProfileSchema = new EntitySchema<any>(require(resourceDir + "schema/profile.json"));
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [
Post,
Category,
UserSchema,
ProfileSchema
],
entitySchemas: [ userSchema, profileSchema ],
enabledDrivers: ["postgres"] // we can properly test lazy-relations only on one platform
}));
beforeEach(() => reloadTestingDatabases(connections));

View File

@ -9,6 +9,7 @@ import {Question} from "./model/Question";
import {Blog} from "./entity/Blog";
import {Category} from "./entity/Category";
import {DeepPartial} from "../../../../src/common/DeepPartial";
import {EntitySchema} from "../../../../src";
describe("repository > basic methods", () => {
@ -20,11 +21,12 @@ describe("repository > basic methods", () => {
const resourceDir = __dirname + "/";
userSchema = require(resourceDir + "schema/user.json");
}
const UserEntity = new EntitySchema<any>(userSchema);
const QuestionEntity = new EntitySchema<any>(questionSchema as any);
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [Post, Blog, Category],
entitySchemas: [userSchema, questionSchema],
entities: [Post, Blog, Category, UserEntity, QuestionEntity],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

View File

@ -5,6 +5,7 @@ import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
import {User} from "./model/User";
import {EntityNotFoundError} from "../../../../src/error/EntityNotFoundError";
import {EntitySchema} from "../../../../src";
describe("repository > find methods", () => {
@ -16,11 +17,11 @@ describe("repository > find methods", () => {
const resourceDir = __dirname + "/";
userSchema = require(resourceDir + "schema/user.json");
}
const UserEntity = new EntitySchema<any>(userSchema);
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [Post],
entitySchemas: [userSchema],
entities: [Post, UserEntity],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

View File

@ -2,50 +2,50 @@ import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {expect} from "chai";
import {InsertResult} from "../../../src";
import {EntitySchema, InsertResult} from "../../../src";
describe("github issues > #1510 entity schema does not support mode=objectId", () => {
const UserEntity = new EntitySchema<any>({
name: "User",
table: {
name: "test_1510_users",
},
columns: {
_id: {
type: "int",
objectId: true,
primary: true,
generated: true,
},
name: {
type: String,
}
}
});
const UserWithoutObjectIDEntity = new EntitySchema<any>({
name: "UserWithoutObjectID",
table: {
name: "test_1510_users2",
},
columns: {
_id: {
type: "int",
primary: true,
generated: true,
},
name: {
type: String,
}
}
});
let connections: Connection[];
before(async () => {
return connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mongodb"],
entitySchemas: [
{
name: "User",
table: {
name: "test_1510_users",
},
columns: {
_id: {
type: "int",
objectId: true,
primary: true,
generated: true,
},
name: {
type: String,
}
}
},
{
name: "UserWithoutObjectID",
table: {
name: "test_1510_users2",
},
columns: {
_id: {
type: "int",
primary: true,
generated: true,
},
name: {
type: String,
}
}
}
]
entities: [__dirname + "/entity/*{.js,.ts}", UserEntity, UserWithoutObjectIDEntity],
enabledDrivers: ["mongodb"]
});
});
beforeEach(() => reloadTestingDatabases(connections));

View File

@ -47,18 +47,13 @@ export interface TestingOptions {
/**
* Entities needs to be included in the connection for the given test suite.
*/
entities?: string[]|Function[];
entities?: (string|Function|EntitySchema<any>)[];
/**
* Subscribers needs to be included in the connection for the given test suite.
*/
subscribers?: string[]|Function[];
/**
* Entity schemas needs to be included in the connection for the given test suite.
*/
entitySchemas?: string[]|EntitySchema[];
/**
* Indicates if schema sync should be performed or not.
*/
@ -135,7 +130,6 @@ export function setupSingleTestingConnection(driverType: DatabaseType, options:
name: options.name ? options.name : undefined,
entities: options.entities ? options.entities : [],
subscribers: options.subscribers ? options.subscribers : [],
entitySchemas: options.entitySchemas ? options.entitySchemas : [],
dropSchema: options.dropSchema ? options.dropSchema : false,
schemaCreate: options.schemaCreate ? options.schemaCreate : false,
enabledDrivers: [driverType],
@ -198,8 +192,7 @@ export function setupTestingConnections(options?: TestingOptions): ConnectionOpt
name: options && options.name ? options.name : connectionOptions.name,
entities: options && options.entities ? options.entities : [],
subscribers: options && options.subscribers ? options.subscribers : [],
entitySchemas: options && options.entitySchemas ? options.entitySchemas : [],
dropSchema: options && (options.entities || options.entitySchemas) ? options.dropSchema : false,
dropSchema: options && options.dropSchema !== undefined ? options.dropSchema : false,
cache: options ? options.cache : undefined,
});
if (options && options.driverSpecific)