@@ -23,11 +23,12 @@ const { Context } = require('../../../util/context');
2323const { v4 : uuidv4 } = require ( 'uuid' ) ;
2424const config = require ( '../../../config' ) ;
2525const {
26- try_infer_attributes,
2726 NodeChildSelector,
2827 NodePathSelector,
2928 NodeUIDSelector,
30- NodeSelector,
29+ NodeRawEntrySelector,
30+ RootNodeSelector,
31+ try_infer_attributes,
3132} = require ( '../../../filesystem/node/selectors' ) ;
3233const fsCapabilities = require ( '../../../filesystem/definitions/capabilities' ) ;
3334const APIError = require ( '../../../api/APIError' ) ;
@@ -198,46 +199,22 @@ class MemoryFSProvider {
198199 * Check if a given node exists.
199200 *
200201 * @param {Object } param
201- * @param {NodeSelector } param.selector - The selector used for checking.
202+ * @param {NodePathSelector | NodeUIDSelector | NodeChildSelector | RootNodeSelector | NodeRawEntrySelector } param.selector - The selector used for checking.
202203 * @returns {Promise<boolean> } - True if the node exists, false otherwise.
203204 */
204205 async quick_check ( { selector } ) {
205- // memoryfs relies on attributes path/uid
206- try_infer_attributes ( selector ) ;
207-
208- // shortcut: has full path
209- if ( selector ?. path ) {
210- const inner_path = this . _inner_path ( selector . path ) ;
206+ if ( selector instanceof NodePathSelector ) {
207+ const inner_path = this . _inner_path ( selector . value ) ;
211208 return this . entriesByPath . has ( inner_path ) ;
212209 }
213210
214- // shortcut: has uid
215- if ( selector ?. uid ) {
216- return this . entriesByUUID . has ( selector . uid ) ;
211+ if ( selector instanceof NodeUIDSelector ) {
212+ return this . entriesByUUID . has ( selector . value ) ;
217213 }
218214
219- if ( selector instanceof NodeChildSelector ) {
220- let parent_entry = null ;
221- if ( selector . parent instanceof NodeUIDSelector ) {
222- // shortcut: uid parent + name child
223- parent_entry = this . entriesByUUID . get ( selector . parent . uid ) ;
224- } else {
225- // composite parent, has to stat it first
226- parent_entry = await this . stat ( {
227- selector : selector . parent ,
228- } ) ;
229- }
230-
231- if ( parent_entry ) {
232- const full_path = _path . join ( parent_entry . path , selector . name ) ;
233- const path_selector = new NodePathSelector ( full_path ) ;
234- return this . quick_check ( {
235- selector : path_selector ,
236- } ) ;
237- }
238- }
239-
240- return false ;
215+ // fallback to stat
216+ const entry = await this . stat ( { selector } ) ;
217+ return ! ! entry ;
241218 }
242219
243220 /**
@@ -247,42 +224,47 @@ class MemoryFSProvider {
247224 * `path` of the absolute path from the root.
248225 *
249226 * @param {Object } param
250- * @param {NodeSelector } param.selector - The selector to stat.
227+ * @param {NodePathSelector | NodeUIDSelector | NodeChildSelector | RootNodeSelector | NodeRawEntrySelector } param.selector - The selector to stat.
251228 * @returns {Promise<MemoryFile|null> } - The result of the stat operation, or `null` if the node doesn't exist.
252229 */
253230 async stat ( { selector } ) {
254- // memoryfs relies on attributes path/uid
255231 try_infer_attributes ( selector ) ;
256232
257233 let entry_uuid = null ;
258234
259- if ( selector ?. path ) {
235+ if ( selector instanceof NodePathSelector ) {
260236 // stat by path
261- const inner_path = this . _inner_path ( selector . path ) ;
237+ const inner_path = this . _inner_path ( selector . value ) ;
262238 entry_uuid = this . entriesByPath . get ( inner_path ) ;
263- } else if ( selector ?. uid ) {
239+ } else if ( selector instanceof NodeUIDSelector ) {
264240 // stat by uid
265- entry_uuid = selector . uid ;
266- } else {
267- // the tricky case: selector has a composite (i.e. non path/uid) parent
268- if ( selector instanceof NodeChildSelector ) {
241+ entry_uuid = selector . value ;
242+ } else if ( selector instanceof NodeChildSelector ) {
243+ if ( selector . path ) {
244+ // Shouldn't care about about parent when the "path" is present
245+ // since it might have different provider.
246+ return await this . stat ( {
247+ selector : new NodePathSelector ( selector . path ) ,
248+ } ) ;
249+ } else {
250+ // recursively stat the parent and then stat the child
269251 const parent_entry = await this . stat ( {
270252 selector : selector . parent ,
271253 } ) ;
272254 if ( parent_entry ) {
273255 const full_path = _path . join ( parent_entry . path , selector . name ) ;
274- const path_selector = new NodePathSelector ( full_path ) ;
275256 return await this . stat ( {
276- selector : path_selector ,
257+ selector : new NodePathSelector ( full_path ) ,
277258 } ) ;
278259 }
279260 }
280-
261+ } else {
262+ // other selectors shouldn't reach here, i.e., it's an internal logic error
281263 throw APIError . create ( 'invalid_node' ) ;
282264 }
283265
284266 const entry = this . entriesByUUID . get ( entry_uuid ) ;
285- if ( ! entry ) {
267+ if ( ! entry ) {
286268 return null ;
287269 }
288270
@@ -304,7 +286,7 @@ class MemoryFSProvider {
304286 async readdir ( { context, node } ) {
305287 // prerequistes: get required path via stat
306288 const entry = await this . stat ( { selector : node . selector } ) ;
307- if ( ! entry ) {
289+ if ( ! entry ) {
308290 throw APIError . create ( 'invalid_node' ) ;
309291 }
310292
@@ -338,21 +320,28 @@ class MemoryFSProvider {
338320 async mkdir ( { context, parent, name } ) {
339321 // prerequistes: get required path via stat
340322 const parent_entry = await this . stat ( { selector : parent . selector } ) ;
341- if ( ! parent_entry ) {
323+ if ( ! parent_entry ) {
342324 throw APIError . create ( 'invalid_node' ) ;
343325 }
344326
345327 const full_path = _path . join ( parent_entry . path , name ) ;
346328 const inner_path = this . _inner_path ( full_path ) ;
347329
348- const entry = new MemoryFile ( {
349- path : inner_path ,
350- is_dir : true ,
351- content : null ,
352- parent_uid : parent_entry . uuid ,
353- } ) ;
354- this . entriesByPath . set ( inner_path , entry . uuid ) ;
355- this . entriesByUUID . set ( entry . uuid , entry ) ;
330+ let entry = null ;
331+ if ( this . entriesByPath . has ( inner_path ) ) {
332+ throw APIError . create ( 'item_with_same_name_exists' , null , {
333+ entry_name : full_path ,
334+ } ) ;
335+ } else {
336+ entry = new MemoryFile ( {
337+ path : inner_path ,
338+ is_dir : true ,
339+ content : null ,
340+ parent_uid : parent_entry . uuid ,
341+ } ) ;
342+ this . entriesByPath . set ( inner_path , entry . uuid ) ;
343+ this . entriesByUUID . set ( entry . uuid , entry ) ;
344+ }
356345
357346 // create the node
358347 const fs = context . get ( 'services' ) . get ( 'filesystem' ) ;
@@ -374,9 +363,11 @@ class MemoryFSProvider {
374363 * @returns {Promise<void> }
375364 */
376365 async rmdir ( { context, node, options = { } } ) {
366+ this . _integrity_check ( ) ;
367+
377368 // prerequistes: get required path via stat
378369 const entry = await this . stat ( { selector : node . selector } ) ;
379- if ( ! entry ) {
370+ if ( ! entry ) {
380371 throw APIError . create ( 'invalid_node' ) ;
381372 }
382373
@@ -424,7 +415,7 @@ class MemoryFSProvider {
424415 async unlink ( { context, node } ) {
425416 // prerequistes: get required path via stat
426417 const entry = await this . stat ( { selector : node . selector } ) ;
427- if ( ! entry ) {
418+ if ( ! entry ) {
428419 throw APIError . create ( 'invalid_node' ) ;
429420 }
430421
@@ -447,7 +438,7 @@ class MemoryFSProvider {
447438 async move ( { context, node, new_parent, new_name, metadata } ) {
448439 // prerequistes: get required path via stat
449440 const new_parent_entry = await this . stat ( { selector : new_parent . selector } ) ;
450- if ( ! new_parent_entry ) {
441+ if ( ! new_parent_entry ) {
451442 throw APIError . create ( 'invalid_node' ) ;
452443 }
453444
@@ -534,20 +525,27 @@ class MemoryFSProvider {
534525 async write_new ( { context, parent, name, file } ) {
535526 // prerequistes: get required path via stat
536527 const parent_entry = await this . stat ( { selector : parent . selector } ) ;
537- if ( ! parent_entry ) {
528+ if ( ! parent_entry ) {
538529 throw APIError . create ( 'invalid_node' ) ;
539530 }
540531 const full_path = _path . join ( parent_entry . path , name ) ;
541532 const inner_path = this . _inner_path ( full_path ) ;
542533
543- const entry = new MemoryFile ( {
544- path : inner_path ,
545- is_dir : false ,
546- content : file . stream . read ( ) ,
547- parent_uid : parent_entry . uuid ,
548- } ) ;
549- this . entriesByPath . set ( inner_path , entry . uuid ) ;
550- this . entriesByUUID . set ( entry . uuid , entry ) ;
534+ let entry = null ;
535+ if ( this . entriesByPath . has ( inner_path ) ) {
536+ throw APIError . create ( 'item_with_same_name_exists' , null , {
537+ entry_name : full_path ,
538+ } ) ;
539+ } else {
540+ entry = new MemoryFile ( {
541+ path : inner_path ,
542+ is_dir : false ,
543+ content : file . stream . read ( ) ,
544+ parent_uid : parent_entry . uuid ,
545+ } ) ;
546+ this . entriesByPath . set ( inner_path , entry . uuid ) ;
547+ this . entriesByUUID . set ( entry . uuid , entry ) ;
548+ }
551549
552550 const fs = context . get ( 'services' ) . get ( 'filesystem' ) ;
553551 const node = await fs . node ( entry . uuid ) ;
@@ -570,7 +568,7 @@ class MemoryFSProvider {
570568 */
571569 async write_overwrite ( { context, node, file } ) {
572570 const entry = await this . stat ( { selector : node . selector } ) ;
573- if ( ! entry ) {
571+ if ( ! entry ) {
574572 throw APIError . create ( 'invalid_node' ) ;
575573 }
576574 const inner_path = this . _inner_path ( entry . path ) ;
0 commit comments