Merge pull request #337 from typeorm/query-builder-refactoring

refactored query builder - refactored JOIN part
This commit is contained in:
Umed Khudoiberdiev 2017-06-03 14:52:31 +05:00 committed by GitHub
commit be7244a025
578 changed files with 34444 additions and 7823 deletions

View File

@ -18,6 +18,14 @@ each for its own `findOne*` or `find*` methods
* table decorators were not removed in the release, however they will be removed in next. Be sure to replace them before that.
* `QueryBuilder#setFirstResult` has been renamed to `QueryBuilder#skip`
* `QueryBuilder#setMaxResults` has been renamed to `QueryBuilder#take`
* renamed `entityManager` to `manager` in `Connection`, `AbstractRepository` and event objects
* renamed `persist` to `save` in `EntityManager` and `Repository` objects
* `@AbstractEntity` is deprecated. Now there is no need to mark class with a decorator, it can extend any class with columns
* `SpecificRepository` is deprecated for now
* `transaction` method has been removed from `Repository`. Use `EntityManager#transaction` method instead
* custom repositories do not support container anymore
* added ActiveRecord support (by extending EntityModel) class
### NEW FEATURES

View File

@ -362,7 +362,7 @@ createConnection(/*...*/).then(connection => {
photo.views = 1;
photo.isPublished = true;
connection.entityManager
connection.manager
.persist(photo)
.then(photo => {
console.log("Photo has been saved");
@ -388,7 +388,7 @@ createConnection(/*...*/).then(async connection => {
photo.views = 1;
photo.isPublished = true;
await connection.entityManager.persist(photo);
await connection.manager.persist(photo);
console.log("Photo has been saved");
}).catch(error => console.log(error));
@ -405,7 +405,7 @@ import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let savedPhotos = await connection.entityManager.find(Photo);
let savedPhotos = await connection.manager.find(Photo);
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));

View File

@ -424,7 +424,7 @@ createConnection(/*...*/).then(connection => {
photo.views = 1;
photo.isPublished = true;
connection.entityManager
connection.manager
.persist(photo)
.then(photo => {
console.log("Photo has been saved");
@ -450,7 +450,7 @@ createConnection(/*...*/).then(async connection => {
photo.views = 1;
photo.isPublished = true;
await connection.entityManager.persist(photo);
await connection.manager.persist(photo);
console.log("Photo has been saved");
}).catch(error => console.log(error));
@ -470,7 +470,7 @@ import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let savedPhotos = await connection.entityManager.find(Photo);
let savedPhotos = await connection.manager.find(Photo);
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));

View File

@ -1,8 +1,8 @@
{
"name": "typeorm",
"private": true,
"version": "0.1.0-alpha.1",
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases.",
"version": "0.1.0-alpha.3",
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL, MongoDB databases.",
"license": "MIT",
"readmeFilename": "README.md",
"author": {
@ -36,13 +36,13 @@
"websql-orm"
],
"devDependencies": {
"@types/chai": "^3.4.35",
"@types/chai-as-promised": "0.0.29",
"@types/mocha": "^2.2.39",
"@types/chai": "^3.5.2",
"@types/chai-as-promised": "0.0.30",
"@types/mocha": "^2.2.41",
"@types/mongodb": "^2.1.41",
"@types/node": "^7.0.5",
"@types/node": "^7.0.16",
"@types/promises-a-plus": "0.0.27",
"@types/sinon": "^1.16.35",
"@types/sinon": "^2.2.0",
"chai": "^3.4.1",
"chai-as-promised": "^6.0.0",
"del": "^2.2.2",
@ -52,33 +52,33 @@
"gulp-mocha": "^3.0.1",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.5.4",
"gulp-shell": "^0.6.1",
"gulp-sourcemaps": "^2.4.1",
"gulp-tslint": "^7.1.0",
"gulp-typescript": "^3.1.5",
"gulp-uglify": "^2.0.0",
"gulpclass": "0.1.1",
"mocha": "^3.2.0",
"mongodb": "^2.2.24",
"gulp-shell": "^0.6.3",
"gulp-sourcemaps": "^2.6.0",
"gulp-tslint": "^8.0.0",
"gulp-typescript": "^3.1.6",
"gulp-uglify": "^2.1.2",
"gulpclass": "^0.1.2",
"mocha": "^2.5.3",
"mongodb": "^2.2.26",
"mssql": "^3.3.0",
"mysql": "^2.12.0",
"mysql2": "^1.2.0",
"pg": "^6.1.2",
"remap-istanbul": "^0.9.1",
"sinon": "^1.17.7",
"sinon-chai": "^2.8.0",
"pg": "^6.1.5",
"remap-istanbul": "^0.9.5",
"sinon": "^2.2.0",
"sinon-chai": "^2.10.0",
"sqlite3": "^3.1.8",
"ts-node": "^2.1.0",
"tslint": "^4.4.2",
"ts-node": "^3.0.3",
"tslint": "^5.2.0",
"tslint-stylish": "^2.1.0",
"typescript": "^2.2.1"
"typescript": "^2.3.2"
},
"dependencies": {
"app-root-path": "^2.0.1",
"glob": "^7.1.1",
"reflect-metadata": "^0.1.9",
"reflect-metadata": "^0.1.10",
"yargonaut": "^1.1.2",
"yargs": "^6.6.0"
"yargs": "^8.0.1"
},
"scripts": {
"test": "node_modules/.bin/gulp tests"

View File

@ -43,7 +43,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved: ", post))
.catch(error => console.log("Cannot save. Error: ", error));

View File

@ -46,7 +46,7 @@ createConnection(options).then(connection => {
post.images.push(image);
post.categories = [category1, category2];
postRepository.persist(post).then(result => {
postRepository.save(post).then(result => {
/*const qb = postRepository.createQueryBuilder("post")
.leftJoinAndSelect("post.details", "details")

View File

@ -44,11 +44,11 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(EverythingEntity);
postRepository
.persist(entity)
.save(entity)
.then(entity => {
console.log("EverythingEntity has been saved. Lets insert a new one to update it later");
delete entity.id;
return postRepository.persist(entity);
return postRepository.save(entity);
})
.then(entity => {
console.log("Second entity has been inserted. Lets update it");
@ -72,13 +72,13 @@ createConnection(options).then(connection => {
entity.jsonColumn = [{ olleh: "hello" }, { dlrow: "world" }];
entity.alsoJson = { olleh: "hello", dlrow: "world" };
return postRepository.persist(entity);
return postRepository.save(entity);
})
.then(entity => {
console.log("Entity has been updated. Persist once again to make find and remove then");
delete entity.id;
return postRepository.persist(entity);
return postRepository.save(entity);
})
.then(entity => {
return postRepository.findOneById(entity.id);

View File

@ -27,7 +27,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved"))
.catch(error => console.log("Cannot save. Error: ", error));

View File

@ -6,12 +6,12 @@ import {snakeCase} from "../../../src/util/StringUtils";
@NamingStrategy("custom_strategy")
export class CustomNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface {
tableName(className: string, customName: string): string {
return customName ? customName : snakeCase(className);
tableName(targetName: string, userSpecifiedName: string): string {
return userSpecifiedName ? userSpecifiedName : snakeCase(targetName);
}
columnName(propertyName: string, customName: string): string {
return customName ? customName : snakeCase(propertyName);
columnName(propertyName: string, customName: string, embeddedPrefixes: string[]): string {
return snakeCase(embeddedPrefixes.concat(customName ? customName : propertyName).join("_"));
}
columnNameCustomized(customName: string): string {

View File

@ -62,14 +62,14 @@ createConnection(options).then(connection => {
let blogRepository = connection.getRepository(Blog);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved");
return postRepository.findOneById(post.id);
})
.then(loadedPost => {
console.log("post is loaded: ", loadedPost);
return blogRepository.persist(blog);
return blogRepository.save(blog);
})
.then(blog => {
console.log("Blog has been saved");
@ -77,7 +77,7 @@ createConnection(options).then(connection => {
})
.then(loadedBlog => {
console.log("blog is loaded: ", loadedBlog);
return blogRepository.persist(blog);
return blogRepository.save(blog);
})
.catch(error => console.log("Cannot save. Error: ", error.stack ? error.stack : error));

View File

@ -1,11 +1,9 @@
import {Column} from "../../../src/index";
import {AbstractEntity} from "../../../src/decorator/entity/AbstractEntity";
import {BasePost} from "./BasePost";
import {PostAuthor} from "./PostAuthor";
import {ManyToOne} from "../../../src/decorator/relations/ManyToOne";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
@AbstractEntity()
export class BaseObject extends BasePost {
@PrimaryColumn("double", { generated: true })

View File

@ -1,7 +1,5 @@
import {PrimaryGeneratedColumn, Column} from "../../../src/index";
import {AbstractEntity} from "../../../src/decorator/entity/AbstractEntity";
@AbstractEntity()
export class BasePost {
@PrimaryGeneratedColumn()

View File

@ -29,7 +29,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved"))
.catch(error => console.log("Cannot save. Error: ", error));

View File

@ -32,7 +32,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved"));
}, error => console.log("Cannot connect: ", error));

View File

@ -1,8 +1,6 @@
import {PrimaryGeneratedColumn, Column} from "../../../src/index";
import {Index} from "../../../src/decorator/Index";
import {AbstractEntity} from "../../../src/decorator/entity/AbstractEntity";
@AbstractEntity()
@Index("my_index_with_id_and_text", ["id", "text"])
export class BasePost {

View File

@ -28,12 +28,12 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log(`Post has been saved: `, post);
console.log(`Post's version is ${post.version}. Lets change post's text and update it:`);
post.title = "updating title";
return postRepository.persist(post);
return postRepository.save(post);
}).then(post => {
console.log(`Post has been updated. Post's version is ${post.version}`);

View File

@ -37,7 +37,7 @@ createConnection(options).then(connection => {
// same as: post.author = Promise.resolve(author);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved. Lets save post from inverse side.");
console.log(post);
@ -47,14 +47,14 @@ createConnection(options).then(connection => {
secondPost.title = "About second post";
author.posts = Promise.resolve([secondPost]);
return authorRepository.persist(author);
return authorRepository.save(author);
})
.then((author: any) => { // temporary
console.log("Author with a new post has been saved. Lets try to update post in the author");
return author.posts!.then((posts: any) => { // temporary
posts![0]!.title = "should be updated second post";
return authorRepository.persist(author!);
return authorRepository.save(author!);
});
})
.then(updatedAuthor => {
@ -67,7 +67,7 @@ createConnection(options).then(connection => {
console.log("Now lets delete a post");
posts[0].author = Promise.resolve(null);
posts[1].author = Promise.resolve(null);
return postRepository.persist(posts[0]);
return postRepository.save(posts[0]);
})
.then(posts => {
console.log("Two post's author has been removed.");
@ -87,7 +87,7 @@ createConnection(options).then(connection => {
category2
]);
return postRepository.persist(post);
return postRepository.save(post);
})
.then(posts => {
console.log("Post has been saved with its categories. ");
@ -100,7 +100,7 @@ createConnection(options).then(connection => {
return posts[0].categories.then((categories: any) => { // temporary
categories!.splice(0, 1);
// console.log(posts[0]);
return postRepository.persist(posts[0]);
return postRepository.save(posts[0]);
});
})
.then(posts => {

View File

@ -49,7 +49,7 @@ createConnection(options).then(connection => {
post.categories = [category1, category2];
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved.");
console.log(post);

View File

@ -39,7 +39,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved. Lets try to find this post using query builder: ");
return postRepository

View File

@ -23,7 +23,7 @@ const options: ConnectionOptions = {
createConnection(options).then(connection => {
let entityManager = connection.entityManager;
let entityManager = connection.manager;
let postRepository = connection.getRepository(Post);
let authorRepository = connection.getRepository(Author);
@ -46,12 +46,12 @@ createConnection(options).then(connection => {
post.categories = [category1, category2];
Promise.all<any>([
authorRepository.persist(author),
categoryRepository.persist(category1),
categoryRepository.persist(category2),
authorRepository.save(author),
categoryRepository.save(category1),
categoryRepository.save(category2),
])
.then(() => {
return postRepository.persist(post);
return postRepository.save(post);
})
.then(() => {
console.log("Everything has been saved.");

View File

@ -41,7 +41,7 @@ createConnection(options).then(connection => {
post.categories = [category1, category2];
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved. Lets load it now.");
return postRepository.find({

View File

@ -42,7 +42,7 @@ createConnection(options).then(connection => {
category1.childCategories = [childCategory1, childCategory2];
return categoryRepository
.persist(category1)
.save(category1)
.then(category => {
console.log("Categories has been saved. Lets now load it and all its descendants:");
return categoryRepository.findDescendants(category1);

View File

@ -44,7 +44,7 @@ createConnection(options).then(connection => {
author2.name = "Bakhrom";
postRepository
.persist(post)
.save(post)
.then(post => {
return postRepository
.createQueryBuilder("post")
@ -63,7 +63,7 @@ createConnection(options).then(connection => {
post.author = author2;
return postRepository.persist(post);
return postRepository.save(post);
})
.then(updatedPost => {
return postRepository
@ -80,7 +80,7 @@ createConnection(options).then(connection => {
console.log("updating with: ", author);
loadedPost!.title = "Umed's post";
loadedPost!.author = author;
return postRepository.persist(loadedPost!);
return postRepository.save(loadedPost!);
})
.then(updatedPost => {
return postRepository
@ -94,7 +94,7 @@ createConnection(options).then(connection => {
console.log(loadedPost);
console.log("Now lets remove post's author:");
post.author = null;
return postRepository.persist(post);
return postRepository.save(post);
})
.then(updatedPost => {
return postRepository
@ -108,7 +108,7 @@ createConnection(options).then(connection => {
console.log(loadedPost);
console.log("Finally bakhrom's post:");
post.author = author2;
return postRepository.persist(post);
return postRepository.save(post);
})
.then(updatedPost => {
return postRepository

View File

@ -39,7 +39,7 @@ createConnection(options).then(connection => {
};
postRepository
.persist(post)
.save(post)
.then(result => {
console.log(result);
})

View File

@ -29,7 +29,7 @@ createConnection(options).then(connection => {
if (!author) {
author = new Author();
author.name = "Umed";
return authorRepository.persist(author).then(savedAuthor => {
return authorRepository.save(author).then(savedAuthor => {
return authorRepository.findOneById(1);
});
}
@ -41,7 +41,7 @@ createConnection(options).then(connection => {
post = new Post();
post.title = "Hello post";
post.text = "This is post contents";
return postRepository.persist(post).then(savedPost => {
return postRepository.save(post).then(savedPost => {
return postRepository.findOneById(1);
});
}
@ -52,7 +52,7 @@ createConnection(options).then(connection => {
.then(results => {
const [author, post] = results;
author.posts = [post];
return authorRepository.persist(author);
return authorRepository.save(author);
})
.then(savedAuthor => {
console.log("Author has been saved: ", savedAuthor);

View File

@ -34,7 +34,7 @@ createConnection(options).then(connection => {
question.counters.metadata = "#question #question-counter";
questionRepository
.persist(question)
.save(question)
.then(savedQuestion => {
console.log("question has been saved: ", savedQuestion);
@ -47,7 +47,7 @@ createConnection(options).then(connection => {
loadedQuestion!.counters.commentCount = 7;
loadedQuestion!.counters.metadata = "#updated question";
return questionRepository.persist(loadedQuestion!);
return questionRepository.save(loadedQuestion!);
})
.then(updatedQuestion => {
console.log("question has been updated: ", updatedQuestion);

View File

@ -1,7 +1,5 @@
import {Column} from "../../../src/index";
import {EmbeddableEntity} from "../../../src/decorator/entity/EmbeddableEntity";
@EmbeddableEntity()
export class Counters {
@Column()

View File

@ -29,7 +29,7 @@ createConnection(options).then(async connection => {
post.text = "this is test post!";
console.log("saving the post: ");
await postRepository.persist(post);
await postRepository.save(post);
console.log("Post has been saved: ", post);
console.log("now loading the post: ");

View File

@ -38,7 +38,7 @@ createConnection(options).then(async connection => {
employee.salary = 200000;
console.log("saving the employee: ");
await employeeRepository.persist(employee);
await employeeRepository.save(employee);
console.log("employee has been saved: ", employee);
console.log("now loading the employee: ");
@ -55,7 +55,7 @@ createConnection(options).then(async connection => {
homesitter.numberOfKids = 5;
console.log("saving the homesitter: ");
await homesitterRepository.persist(homesitter);
await homesitterRepository.save(homesitter);
console.log("homesitter has been saved: ", homesitter);
console.log("now loading the homesitter: ");
@ -72,7 +72,7 @@ createConnection(options).then(async connection => {
student.faculty = "computer science";
console.log("saving the student: ");
await studentRepository.persist(student);
await studentRepository.save(student);
console.log("student has been saved: ", student);
console.log("now loading the student: ");

View File

@ -38,13 +38,13 @@ createConnection(options).then(async connection => {
employee.salary = 300000;
console.log("saving the employee: ");
await employeeRepository.persist(employee);
await employeeRepository.save(employee);
console.log("employee has been saved: ", employee);
console.log("updating the employee: ");
employee.firstName = "zuma";
employee.lastName += "a";
await employeeRepository.persist(employee);
await employeeRepository.save(employee);
console.log("employee has been updated: ", employee);
console.log("now loading the employee: ");
@ -52,7 +52,7 @@ createConnection(options).then(async connection => {
console.log("loaded employee: ", loadedEmployee);
loadedEmployee.firstName = "dima";
await employeeRepository.persist(loadedEmployee);
await employeeRepository.save(loadedEmployee);
const allEmployees = await employeeRepository.findAndCount();
console.log("all employees: ", allEmployees);

View File

@ -44,7 +44,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved"))
.catch(error => console.log("Cannot save. Error: ", error));

View File

@ -42,7 +42,7 @@ createConnection(options).then(async connection => {
]);
console.log("saving posts");
await postRepository.persist([post1, post2, post3, post4]);
await postRepository.save([post1, post2, post3, post4]);
console.log("loading the post. pay attention on order: ");
const allPosts = await postRepository.find();

View File

@ -39,7 +39,7 @@ createConnection(options).then(async connection => {
let postRepository = connection.getRepository(Post);
await postRepository.persist(post);
await postRepository.save(post);
console.log("Post has been saved");
}).catch(error => console.log("Error: ", error));

View File

@ -33,7 +33,7 @@ createConnection(options).then(async connection => {
let postRepository = connection.getRepository(Post);
await postRepository.persist(post);
await postRepository.save(post);
console.log("Database schema was created and data has been inserted into the database.");
// close connection now

View File

@ -5,6 +5,8 @@ import {Author} from "./entity/Author";
import {MigrationExecutor} from "../../src/migration/MigrationExecutor";
import {PostRepository} from "./repository/PostRepository";
import {AuthorRepository} from "./repository/AuthorRepository";
import {UserRepository} from "./repository/UserRepository";
import {User} from "./entity/User";
const options: ConnectionOptions = {
driver: {
@ -19,28 +21,12 @@ const options: ConnectionOptions = {
logging: {
logQueries: true,
},
entities: [Post, Author],
entities: [Post, Author, User],
};
createConnection(options).then(async connection => {
const post = connection
.getCustomRepository(PostRepository)
.create();
post.title = "Hello Repositories!";
await connection
.entityManager
.getCustomRepository(PostRepository)
.persist(post);
const loadedPost = await connection
.entityManager
.getCustomRepository(PostRepository)
.findMyPost();
console.log("Post persisted! Loaded post: ", loadedPost);
// first type of custom repository
const author = await connection
.getCustomRepository(AuthorRepository)
@ -52,4 +38,33 @@ createConnection(options).then(async connection => {
console.log("Author persisted! Loaded author: ", loadedAuthor);
// second type of custom repository
const post = connection
.getCustomRepository(PostRepository)
.create();
post.title = "Hello Repositories!";
await connection
.manager
.getCustomRepository(PostRepository)
.save(post);
const loadedPost = await connection
.manager
.getCustomRepository(PostRepository)
.findMyPost();
console.log("Post persisted! Loaded post: ", loadedPost);
// third type of custom repository
const userRepository = connection.manager.getCustomRepository(UserRepository);
await userRepository.createAndSave("Umed", "Khudoiberdiev");
const loadedUser = await userRepository.findByName("Umed", "Khudoiberdiev");
console.log("User loaded: ", loadedUser);
}).catch(error => console.log("Error: ", error));

View File

@ -0,0 +1,15 @@
import {PrimaryGeneratedColumn, Column, Entity} from "../../../src/index";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
}

View File

@ -3,7 +3,7 @@ import {AbstractRepository} from "../../../src/repository/AbstractRepository";
import {Author} from "../entity/Author";
/**
* Second type of custom repository - extends abstract repository (also can not extend anything).
* First type of custom repository - extends abstract repository.
*/
@EntityRepository(Author)
export class AuthorRepository extends AbstractRepository<Author> {
@ -13,7 +13,7 @@ export class AuthorRepository extends AbstractRepository<Author> {
author.firstName = firstName;
author.lastName = lastName;
return this.entityManager.persist(author);
return this.manager.save(author);
}
findMyAuthor() {

View File

@ -3,7 +3,7 @@ import {Post} from "../entity/Post";
import {EntityRepository} from "../../../src/decorator/EntityRepository";
/**
* First type of custom repository - extends standard repository.
* Second type of custom repository - extends standard repository.
*/
@EntityRepository(Post)
export class PostRepository extends Repository<Post> {

View File

@ -0,0 +1,26 @@
import {EntityRepository} from "../../../src/decorator/EntityRepository";
import {EntityManager} from "../../../src/entity-manager/EntityManager";
import {User} from "../entity/User";
/**
* Third type of custom repository - extends nothing and accepts entity manager as a first constructor parameter.
*/
@EntityRepository()
export class UserRepository {
constructor(private entityManager: EntityManager) {
}
async createAndSave(firstName: string, lastName: string) {
const user = await this.entityManager.create(User, { firstName, lastName });
return this.entityManager.save(user);
}
async findByName(firstName: string, lastName: string) {
return this.entityManager.createQueryBuilder(User, "user")
.where("user.firstName = :firstName AND user.lastName = :lastName")
.setParameters({ firstName, lastName })
.getOne();
}
}

View File

@ -23,7 +23,7 @@ createConnection(options).then(async connection => {
post.title = "hello";
post.likesCount = 100;
await connection.getRepository(Post).persist(post);
await connection.getRepository(Post).save(post);
console.log("Post has been saved: ", post);
const loadedPost = await connection.getRepository(Post).findOne({

View File

@ -1,6 +1,6 @@
import {Column, Entity} from "../../../src/index";
import {ObjectIdColumn} from "../../../src/decorator/columns/ObjectIdColumn";
import {ObjectID} from "mongodb";
import {ObjectID} from "../../../src/driver/mongodb/typings";
@Entity("sample34_post")
export class Post {

View File

@ -34,7 +34,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => console.log("Post has been saved"))
.catch(error => console.log("Cannot save. Error: ", error));

View File

@ -40,7 +40,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved");
return postRepository.findOneById(post.id);
@ -60,7 +60,7 @@ createConnection(options).then(connection => {
console.log("load finished. Now lets update entity");
loadedPost!.text = "post updated";
loadedPost!.author.name = "Bakha";
return postRepository.persist(loadedPost!);
return postRepository.save(loadedPost!);
})
.then(loadedPost => {
console.log("---------------------------");

View File

@ -54,14 +54,14 @@ createConnection(options).then(connection => {
let blogRepository = connection.getRepository(Blog);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved");
return postRepository.findOneById(post.id);
})
.then(loadedPost => {
console.log("post is loaded: ", loadedPost);
return blogRepository.persist(blog);
return blogRepository.save(blog);
})
.then(blog => {
console.log("Blog has been saved");
@ -69,7 +69,7 @@ createConnection(options).then(connection => {
})
.then(loadedBlog => {
console.log("blog is loaded: ", loadedBlog);
return blogRepository.persist(blog);
return blogRepository.save(blog);
})
.catch(error => console.log("Cannot save. Error: ", error.stack ? error.stack : error));

View File

@ -1,7 +1,5 @@
import {PrimaryGeneratedColumn, Column} from "../../../src/index";
import {AbstractEntity} from "../../../src/decorator/entity/AbstractEntity";
@AbstractEntity()
export class BasePost {
@PrimaryGeneratedColumn()

View File

@ -49,7 +49,7 @@ createConnection(options).then(connection => {
.skip(5)
.take(10);
Promise.all(posts.map(post => postRepository.persist(post)))
Promise.all(posts.map(post => postRepository.save(post)))
.then(savedPosts => {
console.log("Posts has been saved. Lets try to load some posts");
return qb.getMany();

View File

@ -27,7 +27,7 @@ createConnection(options).then(connection => {
mainCategory.manyCategories.push(category1);
mainCategory.oneManyCategory = category1;
categoryRepository.persist(mainCategory)
categoryRepository.save(mainCategory)
.then(savedCategory => {
console.log("saved category: ", savedCategory);
})

View File

@ -37,7 +37,7 @@ createConnection(options).then(connection => {
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.save(post)
.then(post => {
console.log("Post has been saved");
console.log("---------------------------");
@ -59,7 +59,7 @@ createConnection(options).then(connection => {
console.log("---------------------------");
loadedPost!.text = "post updated";
loadedPost!.author.name = "Bakha";
return postRepository.persist(loadedPost!);
return postRepository.save(loadedPost!);
})
.then(loadedPost => {
console.log("update finished. Now lets remove entity");

View File

@ -3,10 +3,9 @@ import {Repository} from "../repository/Repository";
import {EntitySubscriberInterface} from "../subscriber/EntitySubscriberInterface";
import {RepositoryNotFoundError} from "./error/RepositoryNotFoundError";
import {ObjectType} from "../common/ObjectType";
import {EntityListenerMetadata} from "../metadata/EntityListenerMetadata";
import {EntityManager} from "../entity-manager/EntityManager";
import {importClassesFromDirectories, importJsonsFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {getMetadataArgsStorage, getFromContainer} from "../index";
import {getFromContainer, getMetadataArgsStorage} from "../index";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy";
import {CannotImportAlreadyConnectedError} from "./error/CannotImportAlreadyConnectedError";
@ -39,6 +38,8 @@ import {CustomRepositoryCannotInheritRepositoryError} from "../repository/error/
import {MongoRepository} from "../repository/MongoRepository";
import {MongoDriver} from "../driver/mongodb/MongoDriver";
import {MongoEntityManager} from "../entity-manager/MongoEntityManager";
import {EntitySchemaTransformer} from "../entity-schema/EntitySchemaTransformer";
import {EntityMetadataValidator} from "../metadata-builder/EntityMetadataValidator";
/**
* Connection is a single database connection to a specific database of a database management system.
@ -82,7 +83,7 @@ export class Connection {
/**
* Gets EntityManager of this connection.
*/
private readonly _entityManager: EntityManager;
readonly manager: EntityManager;
/**
* Stores all registered repositories.
@ -94,11 +95,6 @@ export class Connection {
*/
private readonly entityRepositories: Object[] = [];
/**
* Entity listeners that are registered for this connection.
*/
private readonly entityListeners: EntityListenerMetadata[] = [];
/**
* Entity subscribers that are registered for this connection.
*/
@ -147,7 +143,7 @@ export class Connection {
this.name = name;
this.driver = driver;
this.logger = logger;
this._entityManager = this.createEntityManager();
this.manager = this.createEntityManager();
this.broadcaster = this.createBroadcaster();
}
@ -164,12 +160,11 @@ export class Connection {
/**
* Gets entity manager that allows to perform repository operations with any entity in this connection.
*
* @deprecated use manager instead.
*/
get entityManager(): EntityManager {
// if (!this.isConnected)
// throw new CannotGetEntityManagerNotConnectedError(this.name);
return this._entityManager;
return this.manager;
}
/**
@ -177,10 +172,10 @@ export class Connection {
* with any entity in this connection.
*/
get mongoEntityManager(): MongoEntityManager {
if (!(this._entityManager instanceof MongoEntityManager))
if (!(this.manager instanceof MongoEntityManager))
throw new Error(`MongoEntityManager is only available for MongoDB databases.`);
return this._entityManager as MongoEntityManager;
return this.manager as MongoEntityManager;
}
// -------------------------------------------------------------------------
@ -572,67 +567,7 @@ export class Connection {
* Gets custom entity repository marked with @EntityRepository decorator.
*/
getCustomRepository<T>(customRepository: ObjectType<T>): T {
const entityRepositoryMetadataArgs = getMetadataArgsStorage().entityRepositories.toArray().find(repository => {
return repository.target === (customRepository instanceof Function ? customRepository : (customRepository as any).constructor);
});
if (!entityRepositoryMetadataArgs)
throw new CustomRepositoryNotFoundError(customRepository);
let entityRepositoryInstance: any = this.entityRepositories.find(entityRepository => entityRepository.constructor === customRepository);
if (!entityRepositoryInstance) {
if (entityRepositoryMetadataArgs.useContainer) {
entityRepositoryInstance = getFromContainer(entityRepositoryMetadataArgs.target);
// if we get custom entity repository from container then there is a risk that it already was used
// in some different connection. If it was used there then we check it and throw an exception
// because we cant override its connection there again
if (entityRepositoryInstance instanceof AbstractRepository || entityRepositoryInstance instanceof Repository) {
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
if ((entityRepositoryInstance as any)["connection"] && (entityRepositoryInstance as any)["connection"] !== this)
throw new CustomRepositoryReusedError(customRepository);
}
} else {
entityRepositoryInstance = new (entityRepositoryMetadataArgs.target as any)();
}
if (entityRepositoryInstance instanceof AbstractRepository) {
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
if (!(entityRepositoryInstance as any)["connection"])
(entityRepositoryInstance as any)["connection"] = this;
}
if (entityRepositoryInstance instanceof Repository) {
if (!entityRepositoryMetadataArgs.entity)
throw new CustomRepositoryCannotInheritRepositoryError(customRepository);
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
(entityRepositoryInstance as any)["connection"] = this;
(entityRepositoryInstance as any)["metadata"] = this.getMetadata(entityRepositoryMetadataArgs.entity);
}
// register entity repository
this.entityRepositories.push(entityRepositoryInstance);
}
return entityRepositoryInstance;
}
/**
* Gets custom repository's managed entity.
* If given custom repository does not manage any entity then undefined will be returned.
*/
getCustomRepositoryTarget<T>(customRepository: any): Function|string|undefined {
const entityRepositoryMetadataArgs = getMetadataArgsStorage().entityRepositories.toArray().find(repository => {
return repository.target === (customRepository instanceof Function ? customRepository : (customRepository as any).constructor);
});
if (!entityRepositoryMetadataArgs)
throw new CustomRepositoryNotFoundError(customRepository);
return entityRepositoryMetadataArgs.entity;
return this.manager.getCustomRepository(customRepository);
}
// -------------------------------------------------------------------------
@ -660,40 +595,30 @@ export class Connection {
/**
* Builds all registered metadatas.
*/
protected buildMetadatas() {
public buildMetadatas() {
this.entitySubscribers.length = 0;
this.entityListeners.length = 0;
this.repositoryAggregators.length = 0;
this.entityMetadatas.length = 0;
const namingStrategy = this.createNamingStrategy();
this.driver.namingStrategy = namingStrategy;
const lazyRelationsWrapper = this.createLazyRelationsWrapper();
this.driver.namingStrategy = this.createNamingStrategy(); // todo: why they are in the driver
this.driver.lazyRelationsWrapper = this.createLazyRelationsWrapper(); // todo: why they are in the driver
const entityMetadataValidator = new EntityMetadataValidator();
// take imported event subscribers
if (this.subscriberClasses && this.subscriberClasses.length && !PlatformTools.getEnvVariable("SKIP_SUBSCRIBERS_LOADING")) {
getMetadataArgsStorage()
.entitySubscribers
.filterByTargets(this.subscriberClasses)
.toArray()
.filterSubscribers(this.subscriberClasses)
.map(metadata => getFromContainer(metadata.target))
.forEach(subscriber => this.entitySubscribers.push(subscriber));
}
// take imported entity listeners
if (this.entityClasses && this.entityClasses.length) {
getMetadataArgsStorage()
.entityListeners
.filterByTargets(this.entityClasses)
.toArray()
.forEach(metadata => this.entityListeners.push(new EntityListenerMetadata(metadata)));
}
// build entity metadatas from metadata args storage (collected from decorators)
if (this.entityClasses && this.entityClasses.length) {
getFromContainer(EntityMetadataBuilder)
.buildFromMetadataArgsStorage(this.driver, lazyRelationsWrapper, namingStrategy, this.entityClasses)
// build entity metadatas from metadata args storage (collected from decorators)
new EntityMetadataBuilder(this, getMetadataArgsStorage())
.build(this.entityClasses)
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.repositoryAggregators.push(new RepositoryAggregator(this, metadata));
@ -702,13 +627,16 @@ export class Connection {
// build entity metadatas from given entity schemas
if (this.entitySchemas && this.entitySchemas.length) {
getFromContainer(EntityMetadataBuilder)
.buildFromSchemas(this.driver, lazyRelationsWrapper, namingStrategy, this.entitySchemas)
const metadataArgsStorage = getFromContainer(EntitySchemaTransformer).transform(this.entitySchemas);
new EntityMetadataBuilder(this, metadataArgsStorage)
.build()
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.repositoryAggregators.push(new RepositoryAggregator(this, metadata));
});
}
entityMetadataValidator.validateMany(this.entityMetadatas);
}
/**
@ -722,9 +650,7 @@ export class Connection {
// try to find used naming strategy in the list of loaded naming strategies
const namingMetadata = getMetadataArgsStorage()
.namingStrategies
.filterByTargets(this.namingStrategyClasses)
.toArray()
.filterNamingStrategies(this.namingStrategyClasses)
.find(strategy => {
if (typeof this.usedNamingStrategy === "string") {
return strategy.name === this.usedNamingStrategy;
@ -755,7 +681,7 @@ export class Connection {
* Creates a new entity broadcaster using in this connection.
*/
protected createBroadcaster() {
return new Broadcaster(this, this.entitySubscribers, this.entityListeners);
return new Broadcaster(this, this.entitySubscribers);
}
/**

View File

@ -359,7 +359,8 @@ export class ConnectionManager {
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
*/
protected async createFromConfigAndConnectToAll(path?: string): Promise<Connection[]> {
const optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
let optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
if (!(optionsArray instanceof Array)) optionsArray = [optionsArray]; // cast options to array if ormconfig contains a single connection options object
if (!optionsArray)
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);
@ -377,7 +378,8 @@ export class ConnectionManager {
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
*/
protected async createFromConfigAndConnect(connectionName: string, path?: string): Promise<Connection> {
const optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
let optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
if (!(optionsArray instanceof Array)) optionsArray = [optionsArray]; // cast options to array if ormconfig contains a single connection options object
if (!optionsArray)
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);

View File

@ -11,6 +11,6 @@ export function DiscriminatorValue(value: any): Function {
target: target,
value: value
};
getMetadataArgsStorage().discriminatorValues.add(args);
getMetadataArgsStorage().discriminatorValues.push(args);
};
}

View File

@ -6,8 +6,10 @@ import {EmbeddedMetadataArgs} from "../metadata-args/EmbeddedMetadataArgs";
* Property in entity can be marked as Embedded, and on persist all columns from the embedded are mapped to the
* single table of the entity where Embedded is used. And on hydration all columns which supposed to be in the
* embedded will be mapped to it from the single table.
*
* Array option works only in monogodb.
*/
export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options?: { prefix?: string, array?: boolean }) {
export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options?: { prefix?: string|boolean, array?: boolean }) {
return function (object: Object, propertyName: string) {
const reflectMetadataType = Reflect && (Reflect as any).getMetadata ? (Reflect as any).getMetadata("design:type", object, propertyName) : undefined;
@ -20,6 +22,6 @@ export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options
prefix: options && options.prefix !== undefined ? options.prefix : undefined,
type: typeFunction
};
getMetadataArgsStorage().embeddeds.add(args);
getMetadataArgsStorage().embeddeds.push(args);
};
}

View File

@ -6,29 +6,12 @@ import {EntityRepositoryMetadataArgs} from "../metadata-args/EntityRepositoryMet
* Custom repository can either manage some specific entity, either just be generic.
* Custom repository can extend AbstractRepository or regular Repository or TreeRepository.
*/
export function EntityRepository(entity?: Function, options?: { useContainer?: boolean }): Function;
/**
* Used to declare a class as a custom repository.
* Custom repository can either manage some specific entity, either just be generic.
* Custom repository can extend AbstractRepository or regular Repository or TreeRepository.
*/
export function EntityRepository(options?: { useContainer?: boolean }): Function;
/**
* Used to declare a class as a custom repository.
* Custom repository can either manage some specific entity, either just be generic.
* Custom repository can extend AbstractRepository or regular Repository or TreeRepository.
*/
export function EntityRepository(entityOrOptions?: Function|{ useContainer?: boolean }, maybeOptions?: { useContainer?: boolean }): Function {
const entity = entityOrOptions instanceof Function ? entityOrOptions as Function : undefined;
const options = entityOrOptions instanceof Function ? maybeOptions : entityOrOptions as { useContainer?: boolean };
export function EntityRepository(entity?: Function): Function {
return function (target: Function) {
const args: EntityRepositoryMetadataArgs = {
target: target,
entity: entity,
useContainer: !!(options && options.useContainer)
};
getMetadataArgsStorage().entityRepositories.add(args);
getMetadataArgsStorage().entityRepositories.push(args);
};
}

View File

@ -42,7 +42,7 @@ export function Index(nameOrFieldsOrOptions: string|string[]|((object: any) => a
const fields = typeof nameOrFieldsOrOptions === "string" ? <((object?: any) => (any[]|{ [key: string]: number }))|string[]> maybeFieldsOrOptions : nameOrFieldsOrOptions as string[];
let options = (typeof nameOrFieldsOrOptions === "object" && !Array.isArray(nameOrFieldsOrOptions)) ? nameOrFieldsOrOptions as IndexOptions : maybeOptions;
if (!options)
options = (typeof maybeFieldsOrOptions === "object" && !Array.isArray(maybeFieldsOrOptions)) ? nameOrFieldsOrOptions as IndexOptions : maybeOptions;
options = (typeof maybeFieldsOrOptions === "object" && !Array.isArray(maybeFieldsOrOptions)) ? maybeFieldsOrOptions as IndexOptions : maybeOptions;
return function (clsOrObject: Function|Object, propertyName?: string) {
const args: IndexMetadataArgs = {
@ -51,6 +51,6 @@ export function Index(nameOrFieldsOrOptions: string|string[]|((object: any) => a
columns: propertyName ? [propertyName] : fields,
unique: options && options.unique ? true : false
};
getMetadataArgsStorage().indices.add(args);
getMetadataArgsStorage().indices.push(args);
};
}

View File

@ -14,6 +14,6 @@ export function NamingStrategy(name?: string): Function {
target: target,
name: strategyName
};
getMetadataArgsStorage().namingStrategies.add(args);
getMetadataArgsStorage().namingStrategies.push(args);
};
}

View File

@ -76,6 +76,6 @@ export function Column(typeOrOptions?: ColumnType|ColumnOptions, options?: Colum
mode: "regular",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -27,6 +27,6 @@ export function CreateDateColumn(options?: ColumnOptions): Function {
mode: "createDate",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -24,7 +24,7 @@ export function DiscriminatorColumn(discriminatorOptions: { name: string, type:
propertyName: discriminatorOptions.name,
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -23,6 +23,6 @@ export function ObjectIdColumn<T>(options?: ColumnOptions): Function {
mode: "objectId",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -68,7 +68,7 @@ export function PrimaryColumn(typeOrOptions?: ColumnType|ColumnOptions, options?
mode: "regular",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -19,7 +19,6 @@ export function PrimaryGeneratedColumn(options?: ColumnOptions): Function {
if (!options) options = {} as ColumnOptions;
// check if there is no type in column options then set the int type - by default for auto generated column
if (!options.type)
options = Object.assign({type: "int"} as ColumnOptions, options);
// check if column is not nullable, because we cannot allow a primary key to be nullable
@ -37,7 +36,7 @@ export function PrimaryGeneratedColumn(options?: ColumnOptions): Function {
mode: "regular",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -26,7 +26,7 @@ export function UpdateDateColumn(options?: ColumnOptions): Function {
mode: "updateDate",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -29,7 +29,7 @@ export function VersionColumn(options?: ColumnOptions): Function {
mode: "version",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -4,6 +4,8 @@ import {TableMetadataArgs} from "../../metadata-args/TableMetadataArgs";
/**
* Abstract entity is a class that contains columns and relations for all entities that will inherit this entity.
* Database table for the abstract entity is not created.
*
* @deprecated don't use it anymore. Now entity can extend any class with columns, no need to mark it with this decorator
*/
export function AbstractEntity() {
return function (target: Function) {
@ -12,6 +14,6 @@ export function AbstractEntity() {
name: undefined,
type: "abstract"
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -14,6 +14,6 @@ export function ClassEntityChild(tableName?: string, options?: EntityOptions) {
orderBy: options && options.orderBy ? options.orderBy : undefined,
skipSchemaSync: !!(options && options.skipSchemaSync === true)
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -14,6 +14,6 @@ export function ClosureEntity(name?: string, options?: EntityOptions) {
orderBy: options && options.orderBy ? options.orderBy : undefined,
skipSchemaSync: !!(options && options.skipSchemaSync === true)
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -3,6 +3,8 @@ import {TableMetadataArgs} from "../../metadata-args/TableMetadataArgs";
/**
* This decorator is used on the entities that must be embedded into another entities.
*
* @deprecated don't use it anymore. Now entity can embed any class with columns, no need to mark it with this decorator
*/
export function EmbeddableEntity(): Function {
return function (target: Function) {
@ -11,6 +13,6 @@ export function EmbeddableEntity(): Function {
type: "embeddable",
orderBy: undefined
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -16,6 +16,6 @@ export function Entity(name?: string, options?: EntityOptions) {
engine: options && options.engine ? options.engine : undefined,
skipSchemaSync: !!(options && options.skipSchemaSync === true)
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function SingleEntityChild() {
type: "single-table-child",
orderBy: undefined
};
getMetadataArgsStorage().tables.add(args);
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -10,6 +10,6 @@ export function TableInheritance(type: "single-table"|"class-table") {
target: target,
type: type
};
getMetadataArgsStorage().inheritances.add(args);
getMetadataArgsStorage().inheritances.push(args);
};
}

View File

@ -13,6 +13,6 @@ export function AfterInsert() {
propertyName: propertyName,
type: EventListenerTypes.AFTER_INSERT
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function AfterLoad() {
propertyName: propertyName,
type: EventListenerTypes.AFTER_LOAD
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function AfterRemove() {
propertyName: propertyName,
type: EventListenerTypes.AFTER_REMOVE
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function AfterUpdate() {
propertyName: propertyName,
type: EventListenerTypes.AFTER_UPDATE
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function BeforeInsert() {
propertyName: propertyName,
type: EventListenerTypes.BEFORE_INSERT
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function BeforeRemove() {
propertyName: propertyName,
type: EventListenerTypes.BEFORE_REMOVE
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -12,6 +12,6 @@ export function BeforeUpdate() {
propertyName: propertyName,
type: EventListenerTypes.BEFORE_UPDATE
};
getMetadataArgsStorage().entityListeners.add(args);
getMetadataArgsStorage().entityListeners.push(args);
};
}

View File

@ -10,6 +10,6 @@ export function EventSubscriber() {
const args: EntitySubscriberMetadataArgs = {
target: target
};
getMetadataArgsStorage().entitySubscribers.add(args);
getMetadataArgsStorage().entitySubscribers.push(args);
};
}

View File

@ -8,36 +8,36 @@ export interface ColumnOptions {
/**
* Column type. Must be one of the value from the ColumnTypes class.
*/
readonly type?: ColumnType;
type?: ColumnType;
/**
* Column name in the database.
*/
readonly name?: string;
name?: string;
/**
* Column type's length. Used only on some column types.
* For example type = "string" and length = "100" means that ORM will create a column with type varchar(100).
*/
readonly length?: string|number;
length?: string|number;
/**
* Indicates if this column is PRIMARY.
* Same can be achieved if @PrimaryColumn decorator will be used.
*/
readonly primary?: boolean;
primary?: boolean;
/**
* Specifies if this column will use auto increment (sequence, generated identity).
* Note that only one column in entity can be marked as generated, and it must be a primary column.
* (todo: create validation logic for this condition)
*/
readonly generated?: boolean;
generated?: boolean; // |"uuid"|"sequence";
/**
* Specifies if column's value must be unique or not.
*/
readonly unique?: boolean;
unique?: boolean;
/**
* Indicates if column's value can be set to NULL.
@ -47,43 +47,43 @@ export interface ColumnOptions {
/**
* Column comment.
*/
readonly comment?: string;
comment?: string;
/**
* Default database value.
*/
readonly default?: any;
default?: any;
/**
* The precision for a decimal (exact numeric) column (applies only for decimal column), which is the maximum
* number of digits that are stored for the values.
*/
readonly precision?: number;
precision?: number;
/**
* The scale for a decimal (exact numeric) column (applies only for decimal column), which represents the number
* of digits to the right of the decimal point and must not be greater than precision.
*/
readonly scale?: number;
scale?: number;
/**
* Indicates if this date column will contain a timezone.
* Used only for date-typed column types.
* Note that timezone option is not supported by all databases (only postgres for now).
*/
readonly timezone?: boolean;
timezone?: boolean;
/**
* Indicates if date object must be stored in given date's timezone.
* By default date is saved in UTC timezone.
* Works only with "datetime" columns.
*/
readonly localTimezone?: boolean;
localTimezone?: boolean;
/**
* Indicates if column's type will be set as a fixed-length data type.
* Works only with "string" columns.
*/
readonly fixedLength?: boolean;
fixedLength?: boolean;
}

View File

@ -8,7 +8,7 @@ export interface EntityOptions {
/**
* Specifies a default order by used for queries from this table when no explicit order by is specified.
*/
readonly orderBy?: OrderByCondition|((object: any) => OrderByCondition|any);
orderBy?: OrderByCondition|((object: any) => OrderByCondition|any);
/**
* Table's database engine type (like "InnoDB", "MyISAM", etc).
@ -16,11 +16,11 @@ export interface EntityOptions {
* If you update this value and table is already created, it will not change table's engine type.
* Note that not all databases support this option.
*/
readonly engine?: string;
engine?: string;
/**
* Specifies if this table will be skipped during schema synchronization.
*/
readonly skipSchemaSync?: boolean;
skipSchemaSync?: boolean;
}

View File

@ -6,13 +6,13 @@ export interface IndexOptions {
/**
* Indicates if this composite index must be unique or not.
*/
readonly unique?: boolean;
unique?: boolean;
/**
* If true, the index only references documents with the specified field.
* These indexes use less space but behave differently in some situations (particularly sorts).
* This option is only supported for mongodb database.
*/
readonly sparse?: boolean;
sparse?: boolean;
}

View File

@ -6,11 +6,11 @@ export interface JoinColumnOptions {
/**
* Name of the column.
*/
readonly name?: string;
name?: string;
/**
* Name of the column in the entity to which this column is referenced.
*/
readonly referencedColumnName?: string;
referencedColumnName?: string; // TODO rename to referencedColumn
}

View File

@ -0,0 +1,24 @@
import {JoinColumnOptions} from "./JoinColumnOptions";
/**
* Describes all relation's options.
*/
export interface JoinTableMultipleColumnsOptions {
/**
* Name of the table that will be created to store values of the both tables (join table).
* By default is auto generated.
*/
name?: string;
/**
* First column of the join table.
*/
joinColumns?: JoinColumnOptions[];
/**
* Second (inverse) column of the join table.
*/
inverseJoinColumns?: JoinColumnOptions[];
}

View File

@ -9,16 +9,16 @@ export interface JoinTableOptions {
* Name of the table that will be created to store values of the both tables (join table).
* By default is auto generated.
*/
readonly name?: string;
name?: string;
/**
* First column of the join table.
*/
readonly joinColumn?: JoinColumnOptions;
joinColumn?: JoinColumnOptions;
/**
* Second (inverse) column of the join table.
*/
readonly inverseJoinColumn?: JoinColumnOptions;
inverseJoinColumn?: JoinColumnOptions;
}

View File

@ -1,4 +1,4 @@
import {OnDeleteType} from "../../metadata/ForeignKeyMetadata";
import {OnDeleteType} from "../../metadata/types/OnDeleteType";
// todo: add ON_UPDATE
@ -11,43 +11,43 @@ export interface RelationOptions {
* If set to true then it means that related object can be allowed to be inserted / updated / removed to the db.
* This is option a shortcut if you would like to set cascadeInsert, cascadeUpdate and cascadeRemove to true.
*/
readonly cascadeAll?: boolean;
cascadeAll?: boolean;
/**
* If set to true then it means that related object can be allowed to be inserted to the db.
*/
readonly cascadeInsert?: boolean;
cascadeInsert?: boolean;
/**
* If set to true then it means that related object can be allowed to be updated in the db.
*/
readonly cascadeUpdate?: boolean;
cascadeUpdate?: boolean;
/**
* If set to true then it means that related object can be allowed to be remove from the db.
*/
readonly cascadeRemove?: boolean;
cascadeRemove?: boolean;
/**
* Indicates if relation column value can be nullable or not.
*/
readonly nullable?: boolean;
nullable?: boolean;
/**
* Database cascade action on delete.
*/
readonly onDelete?: OnDeleteType;
onDelete?: OnDeleteType;
/**
* Indicates if this relation will be a primary key.
* Can be used only for many-to-one and owner one-to-one relations.
*/
readonly primary?: boolean;
primary?: boolean;
/**
* Set this relation to be lazy. Note: lazy relations are promises. When you call them they return promise
* which resolve relation result then. If your property's type is Promise then this relation is set to lazy automatically.
*/
readonly lazy?: boolean;
lazy?: boolean;
}

View File

@ -7,16 +7,39 @@ import {JoinColumnMetadataArgs} from "../../metadata-args/JoinColumnMetadataArgs
* It also can be used on both one-to-one and many-to-one relations to specify custom column name
* or custom referenced column.
*/
export function JoinColumn(options?: JoinColumnOptions): Function {
export function JoinColumn(): Function;
/**
* JoinColumn decorator used on one-to-one relations to specify owner side of relationship.
* It also can be used on both one-to-one and many-to-one relations to specify custom column name
* or custom referenced column.
*/
export function JoinColumn(options: JoinColumnOptions): Function;
/**
* JoinColumn decorator used on one-to-one relations to specify owner side of relationship.
* It also can be used on both one-to-one and many-to-one relations to specify custom column name
* or custom referenced column.
*/
export function JoinColumn(options: JoinColumnOptions[]): Function;
/**
* JoinColumn decorator used on one-to-one relations to specify owner side of relationship.
* It also can be used on both one-to-one and many-to-one relations to specify custom column name
* or custom referenced column.
*/
export function JoinColumn(optionsOrOptionsArray?: JoinColumnOptions|JoinColumnOptions[]): Function {
return function (object: Object, propertyName: string) {
options = options || {} as JoinColumnOptions;
const args: JoinColumnMetadataArgs = {
target: object.constructor,
propertyName: propertyName,
name: options.name,
referencedColumnName: options.referencedColumnName
};
getMetadataArgsStorage().joinColumns.add(args);
const options = optionsOrOptionsArray instanceof Array ? optionsOrOptionsArray : [optionsOrOptionsArray || {}];
options.forEach(options => {
const args: JoinColumnMetadataArgs = {
target: object.constructor,
propertyName: propertyName,
name: options.name,
referencedColumnName: options.referencedColumnName
};
getMetadataArgsStorage().joinColumns.push(args);
});
};
}

View File

@ -1,22 +1,41 @@
import {getMetadataArgsStorage} from "../../index";
import {JoinTableOptions} from "../options/JoinTableOptions";
import {JoinTableMetadataArgs} from "../../metadata-args/JoinTableMetadataArgs";
import {JoinTableMultipleColumnsOptions} from "../options/JoinTableMuplipleColumnsOptions";
/**
* JoinTable decorator is used in many-to-many relationship to specify owner side of relationship.
* Its also used to set a custom junction table's name, column names and referenced columns.
*/
export function JoinTable(options?: JoinTableOptions): Function {
export function JoinTable(): Function;
/**
* JoinTable decorator is used in many-to-many relationship to specify owner side of relationship.
* Its also used to set a custom junction table's name, column names and referenced columns.
*/
export function JoinTable(options: JoinTableOptions): Function;
/**
* JoinTable decorator is used in many-to-many relationship to specify owner side of relationship.
* Its also used to set a custom junction table's name, column names and referenced columns.
*/
export function JoinTable(options: JoinTableMultipleColumnsOptions): Function;
/**
* JoinTable decorator is used in many-to-many relationship to specify owner side of relationship.
* Its also used to set a custom junction table's name, column names and referenced columns.
*/
export function JoinTable(options?: JoinTableOptions|JoinTableMultipleColumnsOptions): Function {
return function (object: Object, propertyName: string) {
options = options || {} as JoinTableOptions;
options = options || {} as JoinTableOptions|JoinTableMultipleColumnsOptions;
const args: JoinTableMetadataArgs = {
target: object.constructor,
propertyName: propertyName,
name: options.name,
joinColumn: options.joinColumn,
inverseJoinColumn: options.inverseJoinColumn
joinColumns: (options && (options as JoinTableOptions).joinColumn ? [(options as JoinTableOptions).joinColumn!] : (options as JoinTableMultipleColumnsOptions).joinColumns) as any,
inverseJoinColumns: (options && (options as JoinTableOptions).inverseJoinColumn ? [(options as JoinTableOptions).inverseJoinColumn!] : (options as JoinTableMultipleColumnsOptions).inverseJoinColumns) as any,
};
getMetadataArgsStorage().joinTables.add(args);
getMetadataArgsStorage().joinTables.push(args);
};
}

View File

@ -1,5 +1,4 @@
import {RelationOptions} from "../options/RelationOptions";
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {getMetadataArgsStorage} from "../../index";
import {ObjectType} from "../../common/ObjectType";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
@ -50,13 +49,13 @@ export function ManyToMany<T>(typeFunction: (type?: any) => ObjectType<T>,
target: object.constructor,
propertyName: propertyName,
// propertyType: reflectedType,
relationType: RelationTypes.MANY_TO_MANY,
relationType: "many-to-many",
isLazy: isLazy,
type: typeFunction,
inverseSideProperty: inverseSideProperty,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -1,5 +1,4 @@
import {RelationOptions} from "../options/RelationOptions";
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {getMetadataArgsStorage} from "../../index";
import {ObjectType} from "../../common/ObjectType";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
@ -50,12 +49,12 @@ export function ManyToOne<T>(typeFunction: (type?: any) => ObjectType<T>,
target: object.constructor,
propertyName: propertyName,
// propertyType: reflectedType,
relationType: RelationTypes.MANY_TO_ONE,
relationType: "many-to-one",
isLazy: isLazy,
type: typeFunction,
inverseSideProperty: inverseSideProperty,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -1,4 +1,3 @@
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {getMetadataArgsStorage} from "../../index";
import {ObjectType} from "../../common/ObjectType";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
@ -27,12 +26,12 @@ export function OneToMany<T>(typeFunction: (type?: any) => ObjectType<T>, invers
propertyName: propertyName,
// propertyType: reflectedType,
isLazy: isLazy,
relationType: RelationTypes.ONE_TO_MANY,
relationType: "one-to-many",
type: typeFunction,
inverseSideProperty: inverseSide,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -1,5 +1,4 @@
import {RelationOptions} from "../options/RelationOptions";
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {getMetadataArgsStorage} from "../../index";
import {ObjectType} from "../../common/ObjectType";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
@ -48,11 +47,11 @@ export function OneToOne<T>(typeFunction: (type?: any) => ObjectType<T>,
propertyName: propertyName,
// propertyType: reflectedType,
isLazy: isLazy,
relationType: RelationTypes.ONE_TO_ONE,
relationType: "one-to-one",
type: typeFunction,
inverseSideProperty: inverseSideProperty,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -1,22 +1,20 @@
import {getMetadataArgsStorage} from "../../index";
import {RelationCountMetadataArgs} from "../../metadata-args/RelationCountMetadataArgs";
import {QueryBuilder} from "../../query-builder/QueryBuilder";
/**
* Holds a number of children in the closure table of the column.
*/
export function RelationCount<T>(relation: string|((object: T) => any)): Function {
export function RelationCount<T>(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: QueryBuilder<any>) => QueryBuilder<any>): Function {
return function (object: Object, propertyName: string) {
// todo: need to check if property type is number?
// const reflectedType = ColumnTypes.typeToString((Reflect as any).getMetadata("design:type", object, propertyName));
// create and register a new column metadata
const args: RelationCountMetadataArgs = {
target: object.constructor,
propertyName: propertyName,
relation: relation
relation: relation,
alias: alias,
queryBuilderFactory: queryBuilderFactory
};
getMetadataArgsStorage().relationCounts.add(args);
getMetadataArgsStorage().relationCounts.push(args);
};
}

View File

@ -1,17 +1,20 @@
import {getMetadataArgsStorage} from "../../index";
import {RelationIdMetadataArgs} from "../../metadata-args/RelationIdMetadataArgs";
import {QueryBuilder} from "../../query-builder/QueryBuilder";
/**
* Special decorator used to extract relation id into separate entity property.
*/
export function RelationId<T>(relation: string|((object: T) => any)): Function {
export function RelationId<T>(relation: string|((object: T) => any), alias?: string, queryBuilderFactory?: (qb: QueryBuilder<any>) => QueryBuilder<any>): Function {
return function (object: Object, propertyName: string) {
const args: RelationIdMetadataArgs = {
target: object.constructor,
propertyName: propertyName,
relation: relation
relation: relation,
alias: alias,
queryBuilderFactory: queryBuilderFactory
};
getMetadataArgsStorage().relationIds.add(args);
getMetadataArgsStorage().relationIds.push(args);
};
}

View File

@ -1,4 +1,4 @@
import {getMetadataArgsStorage, getConnection} from "../../index";
import {getConnection, getMetadataArgsStorage} from "../../index";
/**
* Wraps some method into the transaction.
@ -17,14 +17,12 @@ export function Transaction(connectionName: string = "default"): Function {
// override method descriptor with proxy method
descriptor.value = function(...args: any[]) {
return getConnection(connectionName)
.entityManager
.manager
.transaction(entityManager => {
// gets all @TransactionEntityManager() decorator usages for this method
const indices = getMetadataArgsStorage()
.transactionEntityManagers
.filterByTarget(target.constructor)
.toArray()
.filterTransactionEntityManagers(target.constructor)
.filter(transactionEntityManager => transactionEntityManager.methodName === methodName)
.map(transactionEntityManager => transactionEntityManager.index);

View File

@ -11,6 +11,6 @@ export function TransactionEntityManager(): Function {
methodName: methodName,
index: index,
};
getMetadataArgsStorage().transactionEntityManagers.add(args);
getMetadataArgsStorage().transactionEntityManagers.push(args);
};
}

View File

@ -1,6 +1,5 @@
import {getMetadataArgsStorage} from "../../index";
import {RelationOptions} from "../options/RelationOptions";
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
/**
@ -25,11 +24,11 @@ export function TreeChildren(options?: { cascadeInsert?: boolean, cascadeUpdate?
propertyName: propertyName,
// propertyType: reflectedType,
isLazy: isLazy,
relationType: RelationTypes.ONE_TO_MANY,
relationType: "one-to-many",
type: () => object.constructor,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -22,7 +22,7 @@ export function TreeLevelColumn(): Function {
mode: "treeLevel",
options: options
};
getMetadataArgsStorage().columns.add(args);
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -1,6 +1,5 @@
import {getMetadataArgsStorage} from "../../index";
import {RelationOptions} from "../options/RelationOptions";
import {RelationTypes} from "../../metadata/types/RelationTypes";
import {RelationMetadataArgs} from "../../metadata-args/RelationMetadataArgs";
/**
@ -24,11 +23,11 @@ export function TreeParent(options?: { cascadeInsert?: boolean, cascadeUpdate?:
propertyName: propertyName,
// propertyType: reflectedType,
isLazy: isLazy,
relationType: RelationTypes.MANY_TO_ONE,
relationType: "many-to-one",
type: () => object.constructor,
options: options
};
getMetadataArgsStorage().relations.add(args);
getMetadataArgsStorage().relations.push(args);
};
}

View File

@ -3,6 +3,7 @@ import {QueryRunner} from "../query-runner/QueryRunner";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {LazyRelationsWrapper} from "../lazy-loading/LazyRelationsWrapper";
/**
* Driver organizes TypeORM communication with specific database management system.
@ -14,6 +15,11 @@ export interface Driver {
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver options contains connectivity options used to connection to the database.
*/

View File

@ -47,7 +47,7 @@ export interface DriverOptions {
* Schema name. By default is "public" (used only in Postgres databases).
*/
readonly schemaName?: string;
/**
* Connection SID (used for Oracle databases).
*/

Some files were not shown because too many files have changed in this diff Show More