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' ;
1314import { 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' ;
2119import { TypeUtils } from '../utils/typeUtils' ;
20+ import { SearchDaoFull } from './search.full.dao' ;
21+ import { SearchRequestModel } from './search.models' ;
2222
2323const __ = process . statics ;
2424
2525@injectable ( )
2626export 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' ) ;
0 commit comments