mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
trying to fix monogdb issues persisting single package
This commit is contained in:
parent
7f192b6b5d
commit
c9dd663019
@ -2,7 +2,7 @@
|
||||
"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.",
|
||||
"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": {
|
||||
@ -73,7 +73,6 @@
|
||||
"typescript": "^2.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/mongodb": "^2.2.2",
|
||||
"app-root-path": "^2.0.1",
|
||||
"glob": "^7.1.1",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
|
||||
@ -229,9 +229,8 @@ export class MongoDriver implements Driver {
|
||||
const promises: Promise<any>[] = [];
|
||||
await Promise.all(entityMetadatas.map(metadata => {
|
||||
metadata.indices.forEach(index => {
|
||||
// const columns = index.buildColumnsAsMap(1);
|
||||
// const options = { name: index.name };
|
||||
// promises.push(queryRunner.createCollectionIndex(metadata.tableName, columns, options));
|
||||
const options = { name: index.name };
|
||||
promises.push(queryRunner.createCollectionIndex(metadata.tableName, index.columnNamesWithOrderingMap, options));
|
||||
});
|
||||
}));
|
||||
await Promise.all(promises);
|
||||
|
||||
@ -6,27 +6,27 @@ export interface EmbeddedMetadataArgs {
|
||||
/**
|
||||
* Class to which this column is applied.
|
||||
*/
|
||||
readonly target: Function;
|
||||
target: Function;
|
||||
|
||||
/**
|
||||
* Class's property name to which this column is applied.
|
||||
*/
|
||||
readonly propertyName: string;
|
||||
propertyName: string;
|
||||
|
||||
/**
|
||||
* Indicates if this embedded is array or not.
|
||||
*/
|
||||
readonly isArray: boolean;
|
||||
isArray: boolean;
|
||||
|
||||
/**
|
||||
* Prefix of the embedded, used instead of propertyName.
|
||||
* If set to empty string, then prefix is not set at all.
|
||||
*/
|
||||
readonly prefix?: string|boolean;
|
||||
prefix?: string|boolean;
|
||||
|
||||
/**
|
||||
* Type of the class to be embedded.
|
||||
*/
|
||||
readonly type: ((type?: any) => Function);
|
||||
type: ((type?: any) => Function);
|
||||
|
||||
}
|
||||
|
||||
@ -123,6 +123,7 @@ export class EmbeddedMetadata {
|
||||
this.type = options.args.type();
|
||||
this.propertyName = options.args.propertyName;
|
||||
this.customPrefix = options.args.prefix;
|
||||
this.isArray = options.args.isArray;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@ -481,7 +481,12 @@ export class EntityMetadata {
|
||||
return undefined;
|
||||
|
||||
const primaryColumns = this.parentEntityMetadata ? this.primaryColumns : this.primaryColumns;
|
||||
const map = primaryColumns.reduce((map, column) => OrmUtils.mergeDeep(map, column.getEntityValueMap(entity)), {});
|
||||
const map = primaryColumns.reduce((map, column) => {
|
||||
if (column.isObjectId)
|
||||
return Object.assign(map, column.getEntityValueMap(entity));
|
||||
|
||||
return OrmUtils.mergeDeep(map, column.getEntityValueMap(entity));
|
||||
}, {});
|
||||
return Object.keys(map).length > 0 ? map : undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -54,6 +54,12 @@ export class IndexMetadata {
|
||||
*/
|
||||
tableName: string;
|
||||
|
||||
/**
|
||||
* Map of column names with order set.
|
||||
* Used only by MongoDB driver.
|
||||
*/
|
||||
columnNamesWithOrderingMap: { [key: string]: number } = {};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
@ -84,6 +90,8 @@ export class IndexMetadata {
|
||||
* Must be called after all entity metadata's properties map, columns and relations are built.
|
||||
*/
|
||||
build(namingStrategy: NamingStrategyInterface): this {
|
||||
|
||||
const map: { [key: string]: number } = {};
|
||||
this.tableName = this.entityMetadata.tableName;
|
||||
|
||||
// if columns already an array of string then simply return it
|
||||
@ -91,11 +99,17 @@ export class IndexMetadata {
|
||||
let columnPropertyNames: string[] = [];
|
||||
if (this.givenColumnNames instanceof Array) {
|
||||
columnPropertyNames = this.givenColumnNames;
|
||||
columnPropertyNames.forEach(name => map[name] = 1);
|
||||
} else {
|
||||
// if columns is a function that returns array of field names then execute it and get columns names from it
|
||||
const columnsFnResult = this.givenColumnNames(this.entityMetadata.propertiesMap);
|
||||
const columnsNamesFromFnResult = columnsFnResult instanceof Array ? columnsFnResult : Object.keys(columnsFnResult);
|
||||
columnPropertyNames = columnsNamesFromFnResult.map((i: any) => String(i));
|
||||
if (columnsFnResult instanceof Array) {
|
||||
columnPropertyNames = columnsFnResult.map((i: any) => String(i));
|
||||
columnPropertyNames.forEach(name => map[name] = 1);
|
||||
} else {
|
||||
columnPropertyNames = Object.keys(columnsFnResult).map((i: any) => String(i));
|
||||
Object.keys(columnsFnResult).forEach(columnName => map[columnName] = columnsFnResult[columnName]);
|
||||
}
|
||||
}
|
||||
|
||||
const columns = this.entityMetadata.columns.filter(column => columnPropertyNames.indexOf(column.propertyPath) !== -1);
|
||||
@ -115,9 +129,13 @@ export class IndexMetadata {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
this.columnNamesWithOrderingMap = Object.keys(map).reduce((updatedMap, key) => {
|
||||
const column = this.entityMetadata.columns.find(column => column.propertyName === key)!;
|
||||
updatedMap[column.databaseName] = map[key];
|
||||
return updatedMap;
|
||||
}, {} as { [key: string]: number });
|
||||
this.name = namingStrategy.indexName(this.givenName ? this.givenName : undefined, this.entityMetadata.tableName, this.columns.map(column => column.databaseName));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -250,6 +250,8 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
|
||||
|
||||
// if there no ids found (which means all entities are new and have generated ids) - then nothing to load there
|
||||
// console.log("allIds: ", allIds);
|
||||
// console.log("subject.entity: ", subjectGroup.subjects);
|
||||
// console.log("allIds: ", allIds);
|
||||
if (!allIds.length)
|
||||
return;
|
||||
// console.log("Y");
|
||||
@ -260,6 +262,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
|
||||
// todo: also custom queryRunnerProvider is an issue
|
||||
let entities: any[];
|
||||
if (this.connection.driver instanceof MongoDriver) {
|
||||
|
||||
entities = await this.connection
|
||||
.getMongoRepository<ObjectLiteral>(subjectGroup.target)
|
||||
.findByIds(allIds);
|
||||
|
||||
@ -9,6 +9,7 @@ import {EntityManager} from "../entity-manager/EntityManager";
|
||||
import {PromiseUtils} from "../util/PromiseUtils";
|
||||
import {MongoDriver} from "../driver/mongodb/MongoDriver";
|
||||
import {ColumnMetadata} from "../metadata/ColumnMetadata";
|
||||
import {EmbeddedMetadata} from "../metadata/EmbeddedMetadata";
|
||||
|
||||
/**
|
||||
* Executes all database operations (inserts, updated, deletes) that must be executed
|
||||
@ -458,6 +459,43 @@ export class SubjectOperationExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private collectColumns(columns: ColumnMetadata[], entity: ObjectLiteral, object: ObjectLiteral) {
|
||||
columns.forEach(column => {
|
||||
if (column.isVirtual || column.isParentId || column.isDiscriminator)
|
||||
return;
|
||||
|
||||
const value = entity[column.propertyName];
|
||||
if (value === undefined)
|
||||
return;
|
||||
|
||||
object[column.databaseNameWithoutPrefixes] = this.connection.driver.preparePersistentValue(value, column); // todo: maybe preparePersistentValue is not responsibility of this class
|
||||
});
|
||||
}
|
||||
|
||||
private collectEmbeds(embed: EmbeddedMetadata, entity: ObjectLiteral, object: ObjectLiteral) {
|
||||
|
||||
if (embed.isArray) {
|
||||
if (entity[embed.propertyName] instanceof Array) {
|
||||
if (!object[embed.prefix])
|
||||
object[embed.prefix] = [];
|
||||
|
||||
entity[embed.propertyName].forEach((subEntity: any, index: number) => {
|
||||
if (!object[embed.prefix][index])
|
||||
object[embed.prefix][index] = {};
|
||||
this.collectColumns(embed.columns, subEntity, object[embed.prefix][index]);
|
||||
embed.embeddeds.forEach(childEmbed => this.collectEmbeds(childEmbed, subEntity, object[embed.prefix][index]));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (entity[embed.propertyName] !== undefined) {
|
||||
if (!object[embed.prefix])
|
||||
object[embed.prefix] = {};
|
||||
this.collectColumns(embed.columns, entity[embed.propertyName], object[embed.prefix]);
|
||||
embed.embeddeds.forEach(childEmbed => this.collectEmbeds(childEmbed, entity[embed.propertyName], object[embed.prefix]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects columns and values for the insert operation.
|
||||
*/
|
||||
@ -465,16 +503,22 @@ export class SubjectOperationExecutor {
|
||||
|
||||
const values: ObjectLiteral = {};
|
||||
|
||||
metadata.columns.forEach(column => {
|
||||
if (column.isVirtual || column.isParentId || column.isDiscriminator)
|
||||
return;
|
||||
if (this.connection.driver instanceof MongoDriver) {
|
||||
this.collectColumns(metadata.ownColumns, entity, values);
|
||||
metadata.embeddeds.forEach(embed => this.collectEmbeds(embed, entity, values));
|
||||
|
||||
const value = column.getEntityValue(entity);
|
||||
if (value === null || value === undefined)
|
||||
return;
|
||||
} else {
|
||||
metadata.columns.forEach(column => {
|
||||
if (column.isVirtual || column.isParentId || column.isDiscriminator)
|
||||
return;
|
||||
|
||||
values[column.databaseName] = this.connection.driver.preparePersistentValue(value, column); // todo: maybe preparePersistentValue is not responsibility of this class
|
||||
});
|
||||
const value = column.getEntityValue(entity);
|
||||
if (value === null || value === undefined) // todo: probably check for null should not be there
|
||||
return;
|
||||
|
||||
values[column.databaseName] = this.connection.driver.preparePersistentValue(value, column); // todo: maybe preparePersistentValue is not responsibility of this class
|
||||
});
|
||||
}
|
||||
|
||||
metadata.relationsWithJoinColumns.forEach(relation => {
|
||||
relation.joinColumns.forEach(joinColumn => {
|
||||
@ -675,14 +719,18 @@ export class SubjectOperationExecutor {
|
||||
if (!idMap)
|
||||
throw new Error(`Internal error. Cannot get id of the updating entity.`);
|
||||
|
||||
const value: ObjectLiteral = {};
|
||||
/*const value: ObjectLiteral = {};
|
||||
subject.metadata.columns.forEach(column => {
|
||||
const columnValue = column.getEntityValue(entity);
|
||||
if (columnValue !== undefined)
|
||||
value[column.databaseName] = columnValue;
|
||||
});
|
||||
});*/
|
||||
// addEmbeddedValuesRecursively(entity, value, subject.metadata.embeddeds);
|
||||
|
||||
const value: ObjectLiteral = {};
|
||||
this.collectColumns(subject.metadata.ownColumns, entity, value);
|
||||
subject.metadata.embeddeds.forEach(embed => this.collectEmbeds(embed, entity, value));
|
||||
|
||||
// if number of updated columns = 0 no need to update updated date and version columns
|
||||
if (Object.keys(value).length === 0)
|
||||
return;
|
||||
@ -693,8 +741,6 @@ export class SubjectOperationExecutor {
|
||||
if (subject.metadata.versionColumn)
|
||||
value[subject.metadata.versionColumn.databaseName] = this.connection.driver.preparePersistentValue(subject.metadata.versionColumn.getEntityValue(entity) + 1, subject.metadata.versionColumn);
|
||||
|
||||
// console.log(value);
|
||||
// console.log("idMap:", idMap);
|
||||
return this.queryRunner.update(subject.metadata.tableName, value, idMap);
|
||||
}
|
||||
|
||||
|
||||
@ -32,18 +32,18 @@ export class DocumentToEntityTransformer {
|
||||
let hasData = false;
|
||||
|
||||
// handle _id property the special way
|
||||
if (metadata.objectIdColumn && document[metadata.objectIdColumn.databaseName]) {
|
||||
if (metadata.objectIdColumn && document[metadata.objectIdColumn.databaseNameWithoutPrefixes]) {
|
||||
// todo: we can't use driver in this class
|
||||
// do we really need prepare hydrated value here? If no then no problem. If yes then think maybe prepareHydratedValue process should be extracted out of driver class?
|
||||
// entity[metadata.objectIdColumn.propertyName] = this.driver.prepareHydratedValue(document[metadata.objectIdColumn.name"], metadata.objectIdColumn);
|
||||
entity[metadata.objectIdColumn.propertyName] = document[metadata.objectIdColumn.databaseName];
|
||||
entity[metadata.objectIdColumn.propertyName] = document[metadata.objectIdColumn.databaseNameWithoutPrefixes];
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
// add special columns that contains relation ids
|
||||
if (this.enableRelationIdValues) {
|
||||
metadata.columns.filter(column => !!column.relationMetadata).forEach(column => {
|
||||
const valueInObject = document[column.databaseName];
|
||||
const valueInObject = document[column.databaseNameWithoutPrefixes];
|
||||
if (valueInObject !== undefined && valueInObject !== null && column.propertyName) {
|
||||
// todo: we can't use driver in this class
|
||||
// const value = this.driver.prepareHydratedValue(valueInObject, column);
|
||||
@ -67,8 +67,8 @@ export class DocumentToEntityTransformer {
|
||||
});*/
|
||||
|
||||
// get value from columns selections and put them into object
|
||||
metadata.columns.forEach(column => {
|
||||
const valueInObject = document[column.databaseName];
|
||||
metadata.ownColumns.forEach(column => {
|
||||
const valueInObject = document[column.databaseNameWithoutPrefixes];
|
||||
if (valueInObject !== undefined &&
|
||||
valueInObject !== null &&
|
||||
column.propertyName &&
|
||||
@ -91,14 +91,14 @@ export class DocumentToEntityTransformer {
|
||||
entity[embedded.propertyName] = (document[embedded.prefix] as any[]).map(subValue => {
|
||||
const newItem = embedded.create();
|
||||
embedded.columns.forEach(column => {
|
||||
newItem[column.propertyName] = subValue[column.databaseName];
|
||||
newItem[column.propertyName] = subValue[column.databaseNameWithoutPrefixes];
|
||||
});
|
||||
return newItem;
|
||||
});
|
||||
|
||||
} else {
|
||||
embedded.columns.forEach(column => {
|
||||
const value = document[embedded.prefix][column.databaseName];
|
||||
const value = document[embedded.prefix][column.databaseNameWithoutPrefixes];
|
||||
if (!value) return;
|
||||
|
||||
if (!entity[embedded.propertyName])
|
||||
|
||||
@ -122,7 +122,7 @@ export class MongoRepository<Entity extends ObjectLiteral> extends Repository<En
|
||||
*/
|
||||
async findByIds(ids: any[], optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
|
||||
const query = this.convertFindManyOptionsOrConditionsToMongodbQuery(optionsOrConditions) || {};
|
||||
query["_id"] = { $in: ids };
|
||||
query["_id"] = { $in: ids.map(id => id[this.metadata.objectIdColumn!.propertyName]) };
|
||||
|
||||
const cursor = await this.createEntityCursor(query);
|
||||
if (FindOptionsUtils.isFindManyOptions(optionsOrConditions)) {
|
||||
|
||||
@ -55,16 +55,17 @@ export class OrmUtils {
|
||||
|
||||
// remember that NaN === NaN returns false
|
||||
// and isNaN(undefined) returns true
|
||||
if (isNaN(x) && isNaN(y) && typeof x === "number" && typeof y === "number") {
|
||||
if (isNaN(x) && isNaN(y) && typeof x === "number" && typeof y === "number")
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare primitives and functions.
|
||||
// Check if both arguments link to the same object.
|
||||
// Especially useful on the step where we compare prototypes
|
||||
if (x === y) {
|
||||
if (x === y)
|
||||
return true;
|
||||
|
||||
if (x.equals instanceof Function && x.equals(y))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Works in case when functions are created in constructor.
|
||||
// Comparing dates is a common scenario. Another built-ins?
|
||||
@ -73,31 +74,25 @@ export class OrmUtils {
|
||||
(x instanceof Date && y instanceof Date) ||
|
||||
(x instanceof RegExp && y instanceof RegExp) ||
|
||||
(x instanceof String && y instanceof String) ||
|
||||
(x instanceof Number && y instanceof Number)) {
|
||||
(x instanceof Number && y instanceof Number))
|
||||
return x.toString() === y.toString();
|
||||
}
|
||||
|
||||
// At last checking prototypes as good as we can
|
||||
if (!(x instanceof Object && y instanceof Object)) {
|
||||
if (!(x instanceof Object && y instanceof Object))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
|
||||
if (x.isPrototypeOf(y) || y.isPrototypeOf(x))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.constructor !== y.constructor) {
|
||||
if (x.constructor !== y.constructor)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.prototype !== y.prototype) {
|
||||
if (x.prototype !== y.prototype)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for infinitive linking loops
|
||||
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
|
||||
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Quick checking of one object being a subset of another.
|
||||
// todo: cache the structure of arguments[0] for performance
|
||||
|
||||
@ -5,7 +5,7 @@ import {Post} from "./entity/Post";
|
||||
import {Counters} from "./entity/Counters";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe.skip("mongodb > array columns", () => {
|
||||
describe("mongodb > array columns", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
|
||||
@ -6,7 +6,7 @@ import {Counters} from "./entity/Counters";
|
||||
import {Information} from "./entity/Information";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe.skip("mongodb > embedded columns", () => {
|
||||
describe("mongodb > embedded columns", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
|
||||
@ -4,7 +4,7 @@ import {createTestingConnections, closeTestingConnections, reloadTestingDatabase
|
||||
import {Post} from "./entity/Post";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe.only("mongodb > indices", () => {
|
||||
describe("mongodb > indices", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user