Skip to content

Commit 16aabfe

Browse files
fix(assetlibrary): make search dao extendable using protected functions/variables
1 parent b46963e commit 16aabfe

File tree

2 files changed

+92
-79
lines changed

2 files changed

+92
-79
lines changed

source/packages/services/assetlibrary/src/search/search.enhanced.dao.ts

Lines changed: 87 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,171 +10,185 @@
1010
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
1111
* and limitations under the License. *
1212
*********************************************************************************************************************/
13+
import { logger } from '@awssolutions/simple-cdf-logger';
1314
import { process, structure } from 'gremlin';
14-
import { injectable, inject } from 'inversify';
15-
import {logger} from '../utils/logger';
16-
import {TYPES} from '../di/types';
17-
import { SearchRequestModel } from './search.models';
18-
import {NodeAssembler} from '../data/assembler';
19-
import {NeptuneConnection} from '../data/base.full.dao';
20-
import { SearchDaoFull } from './search.full.dao';
15+
import { inject, injectable } from 'inversify';
16+
import { NodeAssembler } from '../data/assembler';
17+
import { NeptuneConnection } from '../data/base.full.dao';
18+
import { TYPES } from '../di/types';
2119
import { TypeUtils } from '../utils/typeUtils';
20+
import { SearchDaoFull } from './search.full.dao';
21+
import { SearchRequestModel } from './search.models';
2222

2323
const __ = process.statics;
2424

2525
@injectable()
2626
export class SearchDaoEnhanced extends SearchDaoFull {
27-
2827
public constructor(
2928
@inject('neptuneUrl') neptuneUrl: string,
3029
@inject('enableDfeOptimization') enableDfeOptimization: boolean,
3130
@inject('openSearchEndpoint') private openSearchEndpoint: boolean,
3231
@inject(TYPES.TypeUtils) typeUtils: TypeUtils,
3332
@inject(TYPES.NodeAssembler) assembler: NodeAssembler,
34-
@inject(TYPES.GraphSourceFactory) graphSourceFactory: () => structure.Graph
33+
@inject(TYPES.GraphSourceFactory) graphSourceFactory: () => structure.Graph
3534
) {
3635
super(neptuneUrl, enableDfeOptimization, typeUtils, assembler, graphSourceFactory);
3736
}
3837

39-
protected buildSearchTraverser(conn: NeptuneConnection, request: SearchRequestModel, authorizedPaths:string[]) : process.GraphTraversal {
40-
41-
logger.debug(`search.enhanced.dao buildSearchTraverser: in: request: ${JSON.stringify(request)}, authorizedPaths:${authorizedPaths}`);
38+
protected buildSearchTraverser(
39+
conn: NeptuneConnection,
40+
request: SearchRequestModel,
41+
authorizedPaths: string[]
42+
): process.GraphTraversal {
43+
logger.debug(
44+
`search.enhanced.dao buildSearchTraverser: in: request: ${JSON.stringify(
45+
request
46+
)}, authorizedPaths:${authorizedPaths}`
47+
);
4248

4349
let source: process.GraphTraversalSource = conn.traversal;
4450
if (this.enableDfeOptimization) {
4551
source = source.withSideEffect('Neptune#useDFE', true);
4652
}
47-
source = source.withSideEffect("Neptune#fts.endpoint", this.openSearchEndpoint);
48-
source = source.withSideEffect("Neptune#fts.queryType", "query_string");
49-
53+
source = source.withSideEffect('Neptune#fts.endpoint', this.openSearchEndpoint);
54+
source = source.withSideEffect('Neptune#fts.queryType', 'query_string');
55+
5056
// if a path is provided, that becomes the starting point
5157
let traverser: process.GraphTraversal;
52-
if (request.ancestorPath!==undefined) {
58+
if (request.ancestorPath !== undefined) {
5359
const ancestorId = `group___${request.ancestorPath}`;
54-
traverser = source.V(ancestorId).
55-
repeat(__.in_().simplePath().dedup()).emit().as('a');
60+
traverser = source.V(ancestorId).repeat(__.in_().simplePath().dedup()).emit().as('a');
5661
} else {
5762
traverser = source.V().as('a');
5863
}
5964

6065
// construct Gremlin traverser from request parameters
6166

62-
if (request.types!==undefined) {
63-
request.types.forEach(t=> traverser.select('a').hasLabel(t));
67+
if (request.types !== undefined) {
68+
request.types.forEach((t) => traverser.select('a').hasLabel(t));
6469
}
6570

66-
if (request.eq!==undefined) {
67-
request.eq.forEach(f=> {
71+
if (request.eq !== undefined) {
72+
request.eq.forEach((f) => {
6873
traverser.select('a');
6974
this.buildSearchFilterVBase(f, traverser);
7075
traverser.has(f.field, f.value);
7176
});
7277
}
73-
if (request.neq!==undefined) {
74-
request.neq.forEach(f=> {
78+
if (request.neq !== undefined) {
79+
request.neq.forEach((f) => {
7580
traverser.select('a');
7681
this.buildSearchFilterVBase(f, traverser);
7782
traverser.not(__.has(f.field, f.value));
7883
});
7984
}
80-
if (request.lt!==undefined) {
81-
request.lt.forEach(f=> {
85+
if (request.lt !== undefined) {
86+
request.lt.forEach((f) => {
8287
traverser.select('a');
8388
this.buildSearchFilterVBase(f, traverser);
8489
traverser.has(f.field, process.P.lt(Number(f.value)));
8590
});
8691
}
87-
if (request.lte!==undefined) {
88-
request.lte.forEach(f=> {
92+
if (request.lte !== undefined) {
93+
request.lte.forEach((f) => {
8994
traverser.select('a');
9095
this.buildSearchFilterVBase(f, traverser);
9196
traverser.has(f.field, process.P.lte(Number(f.value)));
9297
});
9398
}
94-
if (request.gt!==undefined) {
95-
request.gt.forEach(f=> {
99+
if (request.gt !== undefined) {
100+
request.gt.forEach((f) => {
96101
traverser.select('a');
97102
this.buildSearchFilterVBase(f, traverser);
98103
traverser.has(f.field, process.P.gt(Number(f.value)));
99104
});
100105
}
101-
if (request.gte!==undefined) {
102-
request.gte.forEach(f=> {
106+
if (request.gte !== undefined) {
107+
request.gte.forEach((f) => {
103108
traverser.select('a');
104109
this.buildSearchFilterVBase(f, traverser);
105110
traverser.has(f.field, process.P.gte(Number(f.value)));
106111
});
107112
}
108-
if (request.startsWith!==undefined) {
109-
request.startsWith.forEach(f=> {
113+
if (request.startsWith !== undefined) {
114+
request.startsWith.forEach((f) => {
110115
const luceneQueryKey = this.buildLuceneQueryKey(f.field, true);
111116
let luceneQueryVal = f.value.toString();
112-
[':', '/', ' '].forEach( char => {
117+
[':', '/', ' '].forEach((char) => {
113118
luceneQueryVal = luceneQueryVal.replace(new RegExp(char, 'g'), `\\${char}`);
114119
});
115-
['[', ']'].forEach( char => {
116-
luceneQueryVal = luceneQueryVal.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
120+
['[', ']'].forEach((char) => {
121+
luceneQueryVal = luceneQueryVal.replace(
122+
new RegExp(`\\${char}`, 'g'),
123+
`\\${char}`
124+
);
117125
});
118126
traverser.select('a');
119127
this.buildSearchFilterVBase(f, traverser);
120128
traverser.has('*', `Neptune#fts ${luceneQueryKey}:${luceneQueryVal}*`);
121129
});
122130
}
123131

124-
if (request.endsWith!==undefined) {
125-
request.endsWith.forEach(f=> {
132+
if (request.endsWith !== undefined) {
133+
request.endsWith.forEach((f) => {
126134
const luceneQueryKey = this.buildLuceneQueryKey(f.field, true);
127135
let luceneQueryVal = f.value.toString();
128-
[':', '/', ' '].forEach( char => {
136+
[':', '/', ' '].forEach((char) => {
129137
luceneQueryVal = luceneQueryVal.replace(new RegExp(char, 'g'), `\\${char}`);
130138
});
131-
['[', ']'].forEach( char => {
132-
luceneQueryVal = luceneQueryVal.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
139+
['[', ']'].forEach((char) => {
140+
luceneQueryVal = luceneQueryVal.replace(
141+
new RegExp(`\\${char}`, 'g'),
142+
`\\${char}`
143+
);
133144
});
134145
traverser.select('a');
135146
this.buildSearchFilterVBase(f, traverser);
136147
traverser.has('*', `Neptune#fts ${luceneQueryKey}:*${luceneQueryVal}`);
137148
});
138149
}
139150

140-
if (request.contains!==undefined) {
141-
request.contains.forEach(f=> {
151+
if (request.contains !== undefined) {
152+
request.contains.forEach((f) => {
142153
const luceneQueryKey = this.buildLuceneQueryKey(f.field, true);
143154
let luceneQueryVal = f.value.toString();
144-
[':', '/', ' '].forEach( char => {
155+
[':', '/', ' '].forEach((char) => {
145156
luceneQueryVal = luceneQueryVal.replace(new RegExp(char, 'g'), `\\${char}`);
146157
});
147-
['[', ']'].forEach( char => {
148-
luceneQueryVal = luceneQueryVal.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
158+
['[', ']'].forEach((char) => {
159+
luceneQueryVal = luceneQueryVal.replace(
160+
new RegExp(`\\${char}`, 'g'),
161+
`\\${char}`
162+
);
149163
});
150164
traverser.select('a');
151165
this.buildSearchFilterVBase(f, traverser);
152166
traverser.has('*', `Neptune#fts ${luceneQueryKey}:*${luceneQueryVal}*`);
153167
});
154168
}
155169

156-
if (request.exists!==undefined) {
157-
request.exists.forEach(f=> {
170+
if (request.exists !== undefined) {
171+
request.exists.forEach((f) => {
158172
traverser.select('a');
159173
this.buildSearchFilterEBase(f, traverser);
160174
traverser.has(f.field, f.value);
161175
});
162176
}
163177

164-
if (request.nexists!==undefined) {
165-
request.nexists.forEach(f=> {
178+
if (request.nexists !== undefined) {
179+
request.nexists.forEach((f) => {
166180
traverser.select('a');
167181
this.buildSearchFilterEBaseNegated(f, traverser, f.field, f.value);
168182
});
169183
}
170184

171-
if (request.fulltext!==undefined) {
172-
request.fulltext.forEach(f=> {
185+
if (request.fulltext !== undefined) {
186+
request.fulltext.forEach((f) => {
173187
// Remove any characters that would be recognized by Lucene as control characters.
174-
// Alternatively, could escape them but the standard query string analyzer will
188+
// Alternatively, could escape them but the standard query string analyzer will
175189
// replace them with spaces anyway.
176190
let luceneQueryVal = f.value.toString();
177-
[':', '/', '\\[', '\\]'].forEach( char => {
191+
[':', '/', '\\[', '\\]'].forEach((char) => {
178192
luceneQueryVal = luceneQueryVal.replace(new RegExp(char, 'g'), ' ');
179193
});
180194
// RegExp('\\\\') = regex for single backslash, '\\\\' = string with two backslashes
@@ -185,16 +199,16 @@ export class SearchDaoEnhanced extends SearchDaoFull {
185199
});
186200
}
187201

188-
if (request.regex!==undefined) {
189-
request.regex.forEach(f=> {
202+
if (request.regex !== undefined) {
203+
request.regex.forEach((f) => {
190204
const luceneQueryKey = this.buildLuceneQueryKey(f.field, true);
191205
// Escape characters that can appear, escaped or unescaped, in regex but are also
192206
// control characters for Lucene. For example, "abc/def" is a valid regex but the contained
193207
// slash is interpreted by Lucene as the end of the regex. Square brackets [] must not
194208
// be escaped even though they denote range queries in Lucene because Lucene ignores
195209
// them inside of regexes.
196210
let luceneQueryVal = f.value.toString();
197-
[':', '/', ' '].forEach( char => {
211+
[':', '/', ' '].forEach((char) => {
198212
luceneQueryVal = luceneQueryVal.replace(new RegExp(char, 'g'), `\\${char}`);
199213
});
200214
traverser.select('a');
@@ -203,11 +217,11 @@ export class SearchDaoEnhanced extends SearchDaoFull {
203217
});
204218
}
205219

206-
if (request.lucene!==undefined) {
207-
request.lucene.forEach(f=> {
220+
if (request.lucene !== undefined) {
221+
request.lucene.forEach((f) => {
208222
traverser.select('a');
209223
this.buildSearchFilterVBase(f, traverser);
210-
// no escaping for Opensearch, user can send control characters and is responsible for
224+
// no escaping for Opensearch, user can send control characters and is responsible for
211225
// escaping them in the search request when necessary
212226
traverser.has(f.field, `Neptune#fts ${f.value}`);
213227
});
@@ -217,29 +231,28 @@ export class SearchDaoEnhanced extends SearchDaoFull {
217231
traverser.select('a').dedup().fold().unfold().as('matched');
218232

219233
// if authz is enabled, only return results that the user is authorized to view
220-
if (authorizedPaths!==undefined && authorizedPaths.length>0) {
221-
222-
const authorizedPathIds = authorizedPaths.map(path=>`group___${path}`);
223-
traverser.
224-
local(
225-
__.until(
226-
__.hasId(process.P.within(authorizedPathIds))
227-
).repeat(
234+
if (authorizedPaths !== undefined && authorizedPaths.length > 0) {
235+
const authorizedPathIds = authorizedPaths.map((path) => `group___${path}`);
236+
traverser
237+
.local(
238+
__.until(__.hasId(process.P.within(authorizedPathIds))).repeat(
228239
__.out().simplePath().dedup()
229240
)
230-
).as('authorization');
241+
)
242+
.as('authorization');
231243
}
232244

233-
logger.debug(`search.enhanced.dao buildSearchTraverser: traverser: ${traverser.toString()}`);
245+
logger.debug(
246+
`search.enhanced.dao buildSearchTraverser: traverser: ${traverser.toString()}`
247+
);
234248

235249
return traverser.select('matched').dedup();
236-
237250
}
238251

239-
private buildLuceneQueryKey(field: string, keyword?: boolean) : string {
252+
private buildLuceneQueryKey(field: string, keyword?: boolean): string {
240253
if (field === 'id') return 'entity_id';
241254
if (field === 'label') return 'entity_type';
242-
255+
243256
let components: string[] = [];
244257
components = ['predicates', field, 'value'];
245258
if (keyword) components.push('keyword');

source/packages/services/assetlibrary/src/search/search.full.dao.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ const __ = process.statics;
3232
export class SearchDaoFull extends BaseDaoFull {
3333
public constructor(
3434
@inject('neptuneUrl') neptuneUrl: string,
35-
@inject('enableDfeOptimization') private enableDfeOptimization: boolean,
35+
@inject('enableDfeOptimization') protected enableDfeOptimization: boolean,
3636
@inject(TYPES.TypeUtils) private typeUtils: TypeUtils,
3737
@inject(TYPES.NodeAssembler) private assembler: NodeAssembler,
3838
@inject(TYPES.GraphSourceFactory) graphSourceFactory: () => structure.Graph
3939
) {
4040
super(neptuneUrl, graphSourceFactory);
4141
}
4242

43-
private buildSearchTraverser(
43+
protected buildSearchTraverser(
4444
conn: NeptuneConnection,
4545
request: SearchRequestModel,
4646
authorizedPaths: string[]
@@ -184,7 +184,7 @@ export class SearchDaoFull extends BaseDaoFull {
184184
return traverser.select('a').dedup();
185185
}
186186

187-
private buildSearchFilterVBase(
187+
protected buildSearchFilterVBase(
188188
filter: SearchRequestFilter | SearchRequestFacet,
189189
traverser: process.GraphTraversal
190190
): void {
@@ -199,7 +199,7 @@ export class SearchDaoFull extends BaseDaoFull {
199199
}
200200
}
201201

202-
private buildSearchFilterEBase(
202+
protected buildSearchFilterEBase(
203203
filter: SearchRequestFilter | SearchRequestFacet,
204204
traverser: process.GraphTraversal
205205
): void {
@@ -215,7 +215,7 @@ export class SearchDaoFull extends BaseDaoFull {
215215
}
216216
}
217217

218-
private buildSearchFilterEBaseNegated(
218+
protected buildSearchFilterEBaseNegated(
219219
filter: SearchRequestFilter | SearchRequestFacet,
220220
traverser: process.GraphTraversal,
221221
field: unknown,

0 commit comments

Comments
 (0)