1 | import {config,isJSON} from '../core/utils';
|
2 | import * as Sequelize from "sequelize";
|
3 | import Q = require('q');
|
4 | import {IEntityService} from '../core/interfaces/entity-service';
|
5 | import {MetaUtils} from "../core/metadata/utils";
|
6 | import {pathRepoMap, getEntity} from '../core/dynamic/model-entity';
|
7 | import {QueryOptions} from '../core/interfaces/queryOptions';
|
8 | import {Decorators as CoreDecorators, Decorators} from '../core/constants';
|
9 | import * as Enumerable from 'linq';
|
10 | import { IAssociationParams } from '../core/decorators/interfaces';
|
11 | import { PrincipalContext } from '../security/auth/principalContext';
|
12 | import {ConstantKeys} from '../core/constants/constantKeys';
|
13 | var queryString = require('qs');
|
14 |
|
15 | class SequelizeService implements IEntityService {
|
16 | private sequelize: any;
|
17 | private _schemaCollection = {};
|
18 | private _relationCollection = [];
|
19 | constructor() {
|
20 |
|
21 | }
|
22 |
|
23 | init(force?: boolean): Promise<any> {
|
24 | force = force || false;
|
25 | return this.sequelize.sync({ force: force, logging: true });
|
26 | }
|
27 |
|
28 | connect() {
|
29 | if (config().SqlConfig.isSqlEnabled == false)
|
30 | return;
|
31 | this.sequelize = new Sequelize(config().SqlConfig.database,
|
32 | config().SqlConfig.username,
|
33 | config().SqlConfig.password,
|
34 | config().SqlConfig.sequlizeSetting);
|
35 | }
|
36 |
|
37 | getSqlContext(): any {
|
38 | return this.sequelize;
|
39 | }
|
40 |
|
41 | startTransaction(param?:any):Q.Promise<any>{
|
42 | return this.sequelize.transaction();
|
43 | }
|
44 |
|
45 | commitTransaction(param?:any):Q.Promise<any>{
|
46 | return param.commit();
|
47 | }
|
48 |
|
49 | rollbackTransaction(param?:any):Q.Promise<any>{
|
50 | return param.rollback();
|
51 | }
|
52 |
|
53 | getCustomResult(databaseName: string, query) {
|
54 | if (config().SqlConfig.isSqlEnabled == false)
|
55 | return;
|
56 | var dynamicSequelize = new Sequelize(databaseName,
|
57 | config().SqlConfig.username,
|
58 | config().SqlConfig.password,
|
59 | config().SqlConfig.sequlizeSetting);
|
60 | return dynamicSequelize.query(query);
|
61 | }
|
62 |
|
63 | addScheam(name: string, schema: any, detail: any) {
|
64 | var newSchema = this.sequelize.define(name, schema, detail);
|
65 | this._schemaCollection[name] = newSchema;
|
66 | return newSchema;
|
67 | }
|
68 |
|
69 | addRelationInSchema(fromSchema: any, toSchema: any, relationType:string, metaData:IAssociationParams) {
|
70 | let path = metaData.propertyKey;
|
71 | if (relationType == CoreDecorators.ONETOMANY)
|
72 | fromSchema.hasMany(toSchema, { as: path, foreignKey:metaData.foreignKey});
|
73 | if (relationType == CoreDecorators.MANYTOONE)
|
74 | fromSchema.belongsTo(toSchema, { as: path, foreignKey:metaData.foreignKey});
|
75 | if (relationType == CoreDecorators.ONETOONE)
|
76 | fromSchema.hasOne(toSchema, { as: path, foreignKey:metaData.foreignKey});
|
77 |
|
78 | let relationToDictionary: any = {};
|
79 | relationToDictionary.metaData = metaData;
|
80 | relationToDictionary.type = relationType;
|
81 | relationToDictionary["relation"] = metaData.rel;
|
82 | relationToDictionary.fromSchema = fromSchema;
|
83 | relationToDictionary.toSchema = toSchema;
|
84 | relationToDictionary.path = path;
|
85 |
|
86 | this._relationCollection.push(relationToDictionary);
|
87 | }
|
88 |
|
89 | parseProperties(props,schemaModel){
|
90 | let config = {}
|
91 | props.forEach(prop=>{
|
92 | if(prop.indexOf('.')<0){
|
93 | config['attributes']=config['attributes']?config['attributes']:[];
|
94 | config['attributes'].push(prop);
|
95 | }
|
96 | else{
|
97 | let foreignKeys = prop.split('.');
|
98 | this.insertForeignKey(config, foreignKeys,schemaModel);
|
99 | }
|
100 | })
|
101 | return config;
|
102 | }
|
103 |
|
104 | insertForeignKey(config, foreignKeys,schemaModel){
|
105 | let modelConfig = config;
|
106 | foreignKeys.forEach((x, i)=>{
|
107 | if(foreignKeys.length-1 == i){
|
108 | modelConfig['attributes']=modelConfig['attributes']?modelConfig['attributes']:[];
|
109 | let relSchemas = this._relationCollection.filter(schema => (schema.relation == schemaModel.name));
|
110 | if(relSchemas.length >0 && relSchemas[0].toSchema.primaryKeyAttribute!=x){
|
111 | modelConfig['attributes'].push(x);
|
112 | }
|
113 | }
|
114 | else{
|
115 | modelConfig['include']=modelConfig['include']?modelConfig['include']:[];
|
116 | let filterConfig = modelConfig.include.filter(p=>p.as==x);
|
117 | if(!filterConfig.length){
|
118 | let relSchemas = this._relationCollection.filter(schema => (schema.fromSchema.name == schemaModel.name) && (schema.type == Decorators.MANYTOONE) && (schema.path == x));
|
119 | if(relSchemas.length>0){
|
120 | schemaModel = relSchemas[0].toSchema;
|
121 | let tempConfig = { model: relSchemas[0].toSchema, as :relSchemas[0].path,attributes:[relSchemas[0].toSchema.primaryKeyAttribute]}
|
122 | modelConfig.include.push(tempConfig);
|
123 | modelConfig = tempConfig;
|
124 | }
|
125 | }
|
126 | else{
|
127 | let relSchemas = this._relationCollection.filter(schema => (schema.fromSchema.name == schemaModel.name) && (schema.type == Decorators.MANYTOONE) && (schema.path == x));
|
128 | if(relSchemas.length>0){
|
129 | schemaModel = relSchemas[0].toSchema;
|
130 | }
|
131 | modelConfig = filterConfig[0];
|
132 | }
|
133 | }
|
134 | })
|
135 | }
|
136 |
|
137 | getAllForeignKeyAssocationsForFindWhere(inputArr, schemaModel) {
|
138 | let parseProperties = this.parseProperties(inputArr,schemaModel);
|
139 | return parseProperties;
|
140 | }
|
141 |
|
142 | getAllForeignKeyAssocations(schemaModel, properties:Array<string>){
|
143 | let includes = [];
|
144 | let relSchemas = this._relationCollection.filter(x=>(x.fromSchema.name == schemaModel.name) && (x.type == Decorators.MANYTOONE ));
|
145 | if(relSchemas.length){
|
146 | relSchemas.forEach(x=>{
|
147 | if(!properties || !properties.length || properties.indexOf(x.path)>=0){
|
148 | if(x.metaData.eagerLoading){
|
149 | let model = { model: x.toSchema, as: x.path};
|
150 | if (x.metaData.properties) {
|
151 | model['attributes'] = x.metaData.properties;
|
152 | }
|
153 | let childModel = this.getAllForeignKeyAssocations(x.toSchema, x.metaData.properties);
|
154 | if(childModel.length){
|
155 | model['include']= childModel;
|
156 | }
|
157 | includes.push(model);
|
158 | }
|
159 | }
|
160 | });
|
161 | }
|
162 | return includes;
|
163 | }
|
164 |
|
165 | getAllForeignKeyAssocationsForManyToOne(schemaModel, properties:Array<string>){
|
166 | let includes = [];
|
167 | let relSchemas = this._relationCollection.filter(x=>(x.fromSchema.name == schemaModel.name) && (x.type == Decorators.MANYTOONE));
|
168 | if(relSchemas.length){
|
169 | relSchemas.forEach(x=>{
|
170 | if(!properties || !properties.length || properties.indexOf(x.path)>=0){
|
171 | if(x.metaData.eagerLoading){
|
172 | let model = { model: x.toSchema, as: x.path};
|
173 | if (x.metaData.properties) {
|
174 | model['attributes'] = x.metaData.properties;
|
175 | }
|
176 | let childModel = this.getAllForeignKeyAssocationsForManyToOne(x.toSchema, x.metaData.properties);
|
177 | if(childModel.length){
|
178 | model['include']= childModel;
|
179 | }
|
180 | includes.push(model);
|
181 | }
|
182 | }
|
183 | });
|
184 | }
|
185 | return includes;
|
186 | }
|
187 |
|
188 | getAllForeignKeyAssocationsOneToMany(type, schemaModel, properties:Array<string>){
|
189 | let includes = [];
|
190 | let relSchemas = this._relationCollection.filter(x=>(x.fromSchema.name == schemaModel.name) && ( x.type == type));
|
191 | if(relSchemas.length){
|
192 | relSchemas.forEach(x=>{
|
193 | if(!properties || !properties.length || properties.indexOf(x.path)>=0){
|
194 | if(x.metaData.eagerLoading){
|
195 | let model = { model: x.toSchema, as: x.path};
|
196 | if (x.metaData.properties) {
|
197 | model['attributes'] = x.metaData.properties;
|
198 | }
|
199 | let childModel = this.getAllForeignKeyAssocationsOneToMany(type, x.toSchema, x.metaData.properties);
|
200 | if(childModel.length){
|
201 | model['include']= childModel;
|
202 | }
|
203 | includes.push(model);
|
204 | }
|
205 | }
|
206 | });
|
207 | }
|
208 | return includes;
|
209 | }
|
210 |
|
211 | getModel(repoPath: string, dynamicName?: string) {
|
212 | try {
|
213 | var schemaNamefromPathRepomap = pathRepoMap[repoPath].schemaName;
|
214 | return this._schemaCollection[schemaNamefromPathRepomap];
|
215 | } catch (e) {
|
216 | throw e;
|
217 | }
|
218 | }
|
219 |
|
220 | appendTransaction(options){
|
221 | let trans = PrincipalContext.get(ConstantKeys.transaction);
|
222 | if(trans){
|
223 | options['transaction'] = trans;
|
224 | }
|
225 | return options;
|
226 | }
|
227 |
|
228 | bulkPost(repoPath: string, objArr: Array<any>, batchSize?: number): Q.Promise<any> {
|
229 | let options = {individualHooks: true}
|
230 | options = this.appendTransaction(options);
|
231 | return this.getModel(repoPath).bulkCreate(objArr, options).then(result=>{
|
232 | return result.map(x=>x.dataValues);
|
233 | });
|
234 | }
|
235 |
|
236 | bulkPutMany(repoPath: string, objIds: Array<any>, obj: any): Q.Promise<any> {
|
237 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
238 | let cond = {}
|
239 | cond[primaryKey] = objIds
|
240 | let options = { where: cond };
|
241 | options = this.appendTransaction(options);
|
242 | return this.getModel(repoPath).update(obj, options).then(result=>{
|
243 | return this.findMany(repoPath, objIds, false);
|
244 | });
|
245 | }
|
246 |
|
247 | bulkDel(repoPath: string, objArr: Array<any>): Q.Promise<any> {
|
248 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
249 | let cond = {}
|
250 | if(isJSON(objArr[0])){
|
251 | cond[primaryKey] = objArr.map(x => x[primaryKey]);
|
252 | }
|
253 | else{
|
254 | cond[primaryKey] = objArr;
|
255 | }
|
256 | let options = { where: cond }
|
257 | options = this.appendTransaction(options);
|
258 | return this.getModel(repoPath).destroy(options).then(result=>{
|
259 | return {success:result};
|
260 | })
|
261 | }
|
262 |
|
263 | bulkPut(repoPath: string, objArr: Array<any>,batchSize?: number): Q.Promise<any> {
|
264 | let asyncalls=[];
|
265 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
266 | objArr.forEach(obj=>{
|
267 | let cond = {}
|
268 | cond[primaryKey] = obj[primaryKey];
|
269 | let options = { where: cond }
|
270 | options = this.appendTransaction(options);
|
271 | asyncalls.push(this.getModel(repoPath).update(obj, options));
|
272 | });
|
273 | return Q.allSettled(asyncalls).then(result=>{
|
274 | return this.findMany(repoPath, objArr.map(x=>x[primaryKey]), false);
|
275 | });
|
276 | }
|
277 |
|
278 | bulkPatch(repoPath: string, objArr: Array<any>): Q.Promise<any> {
|
279 | return this.bulkPut(repoPath, objArr);
|
280 | }
|
281 |
|
282 | findAll(repoPath: string): Q.Promise<any> {
|
283 | return this.getModel(repoPath).findAll({raw: true}).then(result => {
|
284 | if (!result) return null;
|
285 |
|
286 | return result;
|
287 | });
|
288 | }
|
289 |
|
290 | findWhere(repoPath: string, query, selectedFields?: Array<string>, queryOptions?: QueryOptions, toLoadChilds?: boolean): Q.Promise<any> {
|
291 | let schemaModel = this.getModel(repoPath);
|
292 | let cond = {};
|
293 | if (selectedFields && selectedFields.length > 0) {
|
294 | cond = this.getAllForeignKeyAssocationsForFindWhere(selectedFields, schemaModel);
|
295 | }
|
296 | else {
|
297 | cond['include'] = this.getAllForeignKeyAssocations(schemaModel, []);
|
298 | }
|
299 | cond["where"] = query
|
300 | if(queryOptions){
|
301 | if(queryOptions.skip){
|
302 | cond['offset'] = parseInt(queryOptions.skip.toString());
|
303 | }
|
304 | if(queryOptions.limit){
|
305 | cond['limit'] = parseInt(queryOptions.limit.toString());
|
306 | }
|
307 | if(queryOptions.sort){
|
308 | cond['order'] = queryOptions.sort
|
309 | }
|
310 | }
|
311 | return schemaModel.findAll(cond).then(result => {
|
312 | if (!result) return null;
|
313 | return result.map(x => x.dataValues);
|
314 | });
|
315 | }
|
316 |
|
317 |
|
318 |
|
319 | countWhere(repoPath: string, query): Q.Promise<any> {
|
320 | return this.getModel(repoPath).findAndCountAll({ where: query }).then(result => {
|
321 | return result;
|
322 | });
|
323 | }
|
324 |
|
325 |
|
326 |
|
327 |
|
328 | distinctWhere(repoPath: string, query): Q.Promise<any> {
|
329 | if (!query) {
|
330 | query = {};
|
331 | }
|
332 | query.distinct = true;
|
333 | return this.getModel(repoPath).findAndCountAll(query).then(result => {
|
334 | return result;
|
335 | });
|
336 | }
|
337 |
|
338 | findOne(repoPath: string, id, donotLoadChilds?: boolean): Q.Promise<any> {
|
339 | let schemaModel = this.getModel(repoPath);
|
340 | let primaryKey = schemaModel.primaryKeyAttribute;
|
341 | var cond = {};
|
342 | cond[primaryKey] = id;
|
343 | let include1 = donotLoadChilds? [] : this.getAllForeignKeyAssocationsForManyToOne(schemaModel, null);
|
344 | let include2 = donotLoadChilds? [] : this.getAllForeignKeyAssocationsOneToMany(Decorators.ONETOMANY, schemaModel, null);
|
345 | let include3 = donotLoadChilds? [] : this.getAllForeignKeyAssocationsOneToMany(Decorators.ONETOONE, schemaModel, null);
|
346 | let include = include1.concat(include2).concat(include3);
|
347 | console.log('%%%%%%%%%%%%%%%%%%%%'+include);
|
348 | return schemaModel.find({ include: include, where: cond }).then(result => {
|
349 | return result.dataValues;
|
350 | })
|
351 | .catch(err=>{
|
352 | console.log('####'+err)
|
353 | })
|
354 | }
|
355 |
|
356 | findByField(repoPath: string, fieldName, value): Q.Promise<any> {
|
357 | return this.getModel(repoPath).find({ where: { fieldName: value } });
|
358 | }
|
359 |
|
360 | findMany(repoPath: string, ids: Array<any>, toLoadEmbeddedChilds?: boolean) {
|
361 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
362 | let cond = {};
|
363 | cond[primaryKey] = ids;
|
364 | return this.findWhere(repoPath,cond, [], null, toLoadEmbeddedChilds);
|
365 | }
|
366 |
|
367 | findChild(repoPath: string, id, prop): Q.Promise<any> {
|
368 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
369 | let cond = {};
|
370 | cond[primaryKey] = id;
|
371 | return this.getModel(repoPath).find({
|
372 | where: cond,
|
373 | include: [
|
374 | { model: this.getModel(prop), as: prop }
|
375 | ]
|
376 | }).then(
|
377 | function (entity) {
|
378 | return entity[prop];
|
379 | });
|
380 | }
|
381 |
|
382 | |
383 |
|
384 |
|
385 |
|
386 |
|
387 | post(repoPath: string, obj: any): Q.Promise<any> {
|
388 | let options = {};
|
389 | options = this.appendTransaction(options);
|
390 | return this.getModel(repoPath).create(obj, options);
|
391 | }
|
392 |
|
393 | put(repoPath: string, id: any, obj: any): Q.Promise<any> {
|
394 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
395 | let cond = {};
|
396 | cond[primaryKey] = id;
|
397 | let options = { where: cond }
|
398 | options = this.appendTransaction(options);
|
399 | return this.getModel(repoPath).update(obj, options).then(result=>{
|
400 | return this.findOne(repoPath, id);
|
401 | })
|
402 | }
|
403 |
|
404 | del(repoPath: string, id: any): Q.Promise<any> {
|
405 | let primaryKey = this.getModel(repoPath).primaryKeyAttribute;
|
406 | let cond = {};
|
407 | cond[primaryKey] = id;
|
408 | let options = { where: cond };
|
409 | options = this.appendTransaction(options);
|
410 | return this.getModel(repoPath).destroy(options).then(result=>{
|
411 | return {success:result};
|
412 | })
|
413 | }
|
414 |
|
415 | patch(repoPath: string, id: any, obj): Q.Promise<any> {
|
416 | return this.put(repoPath, id, obj)
|
417 | }
|
418 |
|
419 | getSortCondition(val){
|
420 | return JSON.parse(val);
|
421 | }
|
422 |
|
423 | getLikeCondition(val){
|
424 | val = queryString.parse('key='+val)['key'];
|
425 | return {
|
426 | [this.sequelize.Op.like]: '%'+val+'%'
|
427 | }
|
428 | }
|
429 |
|
430 | getStartsWithCondition(val){
|
431 | val = queryString.parse('key='+val)['key'];
|
432 | return {
|
433 | [this.sequelize.Op.like]: val+'%'
|
434 | }
|
435 | }
|
436 |
|
437 | getPrimaryKey(repoPath){
|
438 | return this.getModel(repoPath).primaryKeyAttribute;
|
439 | }
|
440 |
|
441 | private getAssociationForSchema(model: any, schema: any) {
|
442 | Enumerable.from(this._relationCollection)
|
443 | .where(relationSchema => relationSchema.fromSchema == schema).forEach(relation1 => {
|
444 | model.dataValues[relation1.path] = model[relation1.toSchema.name + "s"];
|
445 | });
|
446 | }
|
447 |
|
448 | }
|
449 | export var sequelizeService = new SequelizeService();
|
450 |
|