Created
October 14, 2019 18:47
-
-
Save akvsh-r/0f86841338f90fd8034faf00a6da9f6d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2018 - Present, Co. | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or | |
* without modification, are not permitted. | |
*/ | |
import { Types } from 'mongoose'; | |
import { Service } from 'typedi'; | |
import { | |
Contract, | |
ContractModel, | |
IContract, | |
IEntity, | |
EntityModel, | |
ContractListInput, | |
IPaginatedResponse, | |
} from 'fox-node-datalib'; | |
import { elasticSearchClient, getIndexNameByLocale } from '@common/utils/elastic-search'; | |
import { log } from '@config/logger'; | |
import { ModelService } from '../common/graphql/model/model.service'; | |
import { prettyPrint } from '@common/utils/print'; | |
@Service() | |
export class ContractService extends ModelService<Contract> { | |
constructor() { | |
super(); | |
this.modelClass = ContractModel; | |
} | |
// ref: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#_search | |
async getAll(listInput: ContractListInput) { | |
// const start: number = skip; | |
// const end: number = skip + take; | |
const { skip, take: size, sort, order, searchQuery, locale } = listInput; | |
const { appliedFilters } = this.getFilters(listInput); | |
let result: IPaginatedResponse<any> = { items: [], total: 0, hasMore: false }; | |
// const sortFilter = sort ? { [sort]: order } : {}; | |
const total = await this.modelClass.countDocuments(appliedFilters); | |
const index = getIndexNameByLocale(this.modelClass, locale); | |
try { | |
const { | |
body: { | |
hits: { hits }, | |
}, | |
} = await elasticSearchClient.search({ | |
index, | |
size, | |
from: skip * size, | |
sort: `${sort}:${order}`, | |
body: { | |
query: { | |
match_all: { | |
query: searchQuery | |
}, | |
}, | |
}, | |
}); | |
const hasMore = hits.length > 0; | |
result = { items: hits, total, hasMore }; | |
log.debug(`Result from the find query: ${prettyPrint(hits)}`); | |
} catch (error) { | |
log.debug(`Error from the find query: ${prettyPrint(error)}`); | |
} finally { | |
return result; | |
} | |
} | |
async create(contractDoc: Partial<IContract>) { | |
const contract = await ContractModel.create(contractDoc); | |
const entityPopulatedContract = await ContractModel.findOne({ _id: contract._id }).populate('entity'); | |
if (entityPopulatedContract) { | |
this.indexContract(entityPopulatedContract); | |
} | |
return contract; | |
} | |
async createMany(contractDocs: Partial<IContract>[]) { | |
const contracts = await ContractModel.insertMany(contractDocs); | |
const contractIds = contracts.map(({ _id }) => _id); | |
const entityPopulatedContracts = await ContractModel.find({ | |
_id: { $in: contractIds }, | |
}).populate('entity'); | |
await this.bulkIndexContracts(entityPopulatedContracts); | |
return contracts; | |
} | |
async createMock(contractDoc: Partial<IContract>) { | |
const { _id, ...restAttrs } = contractDoc.entity as IEntity; | |
await EntityModel.create(restAttrs); | |
const contract = (await ContractModel.create(contractDoc)).populate('entity'); | |
this.indexContract(contract); | |
return contract; | |
} | |
async createManyMock(contractDocs: Partial<IContract>[]) { | |
const entityCreatePromises: Promise<IEntity>[] = []; | |
contractDocs.map(async doc => { | |
const { _id, ...restAttrs } = doc.entity as IEntity; | |
entityCreatePromises.push(EntityModel.create(restAttrs)); | |
}); | |
const entities = await Promise.all(entityCreatePromises); | |
contractDocs.forEach((contractDoc, index) => { | |
// TODO: fix type for this: | |
// @ts-ignore | |
contractDoc.entity = new Types.ObjectId(entities[index]._id); | |
}); | |
const contracts = await ContractModel.insertMany(contractDocs); | |
const contractIds = contracts.map(({ _id }) => _id); | |
const entityPopulatedContracts = await ContractModel.find({ | |
_id: { $in: contractIds }, | |
}).populate('entity'); | |
await this.bulkIndexContracts(entityPopulatedContracts); | |
return contracts; | |
} | |
async indexContract(contract: Contract) { | |
const contractLocale = (contract.entity as IEntity).locale; | |
return elasticSearchClient.index({ | |
index: `${ContractModel.modelName}_${contractLocale}`, | |
id: contract._id.toHexString(), | |
body: contract, | |
}); | |
} | |
async bulkIndexContracts(contracts: Contract[]) { | |
const bulkBody: any[] = []; | |
contracts.forEach(({ _id, entity, ...item }) => { | |
bulkBody.push({ | |
index: { | |
_index: getIndexNameByLocale(this.modelClass, [(entity as IEntity).locale]), | |
_type: `${ContractModel.modelName}`, | |
_id, | |
}, | |
}); | |
bulkBody.push(item); | |
}); | |
log.debug(`indexing ${bulkBody.length}`); | |
return elasticSearchClient.bulk({ | |
index: 'contracts_index', | |
body: bulkBody, | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment