-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(search-service): add sequelize support in search service
add sequelize support in search service GH-1350
- Loading branch information
1 parent
229179c
commit c344faf
Showing
11 changed files
with
306 additions
and
35 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './recent-search.repository'; | ||
export * from './search-query.repository'; |
106 changes: 106 additions & 0 deletions
106
services/search-service/src/repositories/sequelize/recent-search.repository.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Copyright (c) 2023 Sourcefuse Technologies | ||
// | ||
// This software is released under the MIT License. | ||
// https://opensource.org/licenses/MIT | ||
import {Getter, inject} from '@loopback/core'; | ||
import {HasManyRepositoryFactory, repository} from '@loopback/repository'; | ||
import {HttpErrors} from '@loopback/rest'; | ||
import {SequelizeDataSource} from '@loopback/sequelize'; | ||
import {IAuthUserWithPermissions} from '@sourceloop/core'; | ||
import {SequelizeUserModifyCrudRepository} from '@sourceloop/core/sequelize'; | ||
import {AuthenticationBindings} from 'loopback4-authentication'; | ||
import {SearchServiceConfig} from '../..'; | ||
import {DEFAULT_RECENTS, Errors} from '../../const'; | ||
import {SearchServiceBindings} from '../../keys'; | ||
import {RecentSearch, SearchQuery} from '../../models'; | ||
import {SearchQueryRepository} from './search-query.repository'; | ||
export class RecentSearchRepository extends SequelizeUserModifyCrudRepository< | ||
RecentSearch, | ||
typeof RecentSearch.prototype.id | ||
> { | ||
public readonly params: HasManyRepositoryFactory< | ||
SearchQuery, | ||
typeof SearchQuery.prototype.id | ||
>; | ||
|
||
constructor( | ||
@inject(`datasources.${SearchServiceBindings.DATASOURCE_NAME}`) | ||
dataSource: SequelizeDataSource, | ||
@repository.getter('SearchQueryRepository') | ||
queryRepositoryGetter: Getter<SearchQueryRepository>, | ||
@inject(SearchServiceBindings.Config) | ||
private readonly config: SearchServiceConfig, | ||
@inject.getter(AuthenticationBindings.CURRENT_USER) | ||
protected readonly getCurrentUser: Getter< | ||
IAuthUserWithPermissions | undefined | ||
>, | ||
) { | ||
super(RecentSearch, dataSource, getCurrentUser); | ||
this.params = this.createHasManyRepositoryFactoryFor( | ||
'params', | ||
queryRepositoryGetter, | ||
); | ||
this.registerInclusionResolver('params', this.params.inclusionResolver); | ||
} | ||
|
||
async create(query: SearchQuery, user?: IAuthUserWithPermissions) { | ||
if (!user) { | ||
throw new HttpErrors.BadRequest(Errors.USER_MISSING); | ||
} | ||
|
||
let saved = await super.findOne({ | ||
where: { | ||
userId: user.userTenantId, | ||
}, | ||
}); | ||
|
||
if (saved?.id) { | ||
const prev = await this.params(saved.id).find({ | ||
order: ['created_on DESC'], | ||
fields: { | ||
where: false, | ||
}, | ||
}); | ||
|
||
const recentCount = | ||
this.config.controller?.recentCount ?? DEFAULT_RECENTS; | ||
|
||
//to delete from recent search if already present | ||
const prevMatched = prev | ||
.filter( | ||
item => | ||
item.match.toLocaleLowerCase() === query.match.toLocaleLowerCase(), | ||
) | ||
.map(item => item.id); | ||
await this.params(saved.id).delete({ | ||
id: { | ||
inq: prevMatched, | ||
}, | ||
}); | ||
|
||
if (prev.length >= recentCount) { | ||
const latestOnes = prev.slice(0, recentCount).map(item => item.id); | ||
await this.params(saved.id).delete({ | ||
id: { | ||
nin: latestOnes, | ||
}, | ||
}); | ||
} | ||
} else { | ||
saved = await super.create({ | ||
userId: user.userTenantId, | ||
}); | ||
} | ||
|
||
if (saved?.id) { | ||
await this.params(saved.id).create({ | ||
...query, | ||
recentSearchId: saved.id, | ||
}); | ||
} else { | ||
throw new HttpErrors.InternalServerError(Errors.FAILED); | ||
} | ||
|
||
return saved; | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
services/search-service/src/repositories/sequelize/search-query.repository.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright (c) 2023 Sourcefuse Technologies | ||
// | ||
// This software is released under the MIT License. | ||
// https://opensource.org/licenses/MIT | ||
import {Getter, inject} from '@loopback/core'; | ||
import {AnyObject, Count, Where} from '@loopback/repository'; | ||
import {SequelizeDataSource} from '@loopback/sequelize'; | ||
import {IAuthUserWithPermissions} from '@sourceloop/core'; | ||
import {SequelizeUserModifyCrudRepository} from '@sourceloop/core/sequelize'; | ||
import {AuthenticationBindings} from 'loopback4-authentication'; | ||
import {SearchServiceConfig} from '../..'; | ||
import {SearchServiceBindings} from '../../keys'; | ||
import {SearchQuery} from '../../models'; | ||
|
||
export class SearchQueryRepository extends SequelizeUserModifyCrudRepository< | ||
SearchQuery, | ||
typeof SearchQuery.prototype.id | ||
> { | ||
constructor( | ||
@inject(`datasources.${SearchServiceBindings.DATASOURCE_NAME}`) | ||
dataSource: SequelizeDataSource, | ||
@inject(SearchServiceBindings.Config) | ||
private readonly config: SearchServiceConfig, | ||
@inject.getter(AuthenticationBindings.CURRENT_USER) | ||
protected readonly getCurrentUser: Getter< | ||
IAuthUserWithPermissions | undefined | ||
>, | ||
) { | ||
super(SearchQuery, dataSource, getCurrentUser); | ||
} | ||
|
||
deleteAll(where?: Where<SearchQuery>, options?: AnyObject): Promise<Count> { | ||
return super.deleteAllHard(where, options); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import {BindingScope, Provider, inject, injectable} from '@loopback/context'; | ||
import {SearchServiceBindings} from '../keys'; | ||
import {SearchQuery, SearchResult} from '../models'; | ||
import {SearchServiceConfig, isSearchableModel} from '../types'; | ||
export type ModelProviderFn = ( | ||
search: SearchQuery, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
queryBuilder: any, // NOSONAR | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
) => Promise<{query: string; params: any[]}>; // NOSONAR | ||
@injectable({scope: BindingScope.SINGLETON}) | ||
export class SearchModelProvider implements Provider<ModelProviderFn> { | ||
constructor( | ||
@inject(SearchServiceBindings.Config) | ||
private readonly config: SearchServiceConfig, | ||
) {} | ||
value(): ModelProviderFn { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
// sonarignore:start | ||
return async (search: SearchQuery, queryBuilder: any) => { | ||
// sonarignore:end | ||
let models; | ||
if (search.sources && search.sources.length > 0) { | ||
const sources = search.sources; | ||
models = this.config.models.filter(model => { | ||
if (isSearchableModel(model)) { | ||
return sources.includes(model.identifier ?? model.model.modelName); | ||
} else { | ||
return sources.includes(model.modelName); | ||
} | ||
}); | ||
} else { | ||
models = this.config.models; | ||
} | ||
const type = this.config.type ?? SearchResult; | ||
|
||
const {query, params} = await queryBuilder.build( | ||
models, | ||
this.config.ignoreColumns, | ||
type, | ||
); | ||
return {query, params}; | ||
}; | ||
} | ||
} |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from '../model.provider'; | ||
export * from './search.provider'; |
Oops, something went wrong.