@@ -47,10 +47,6 @@ module Configuration =
4747 | " 0" -> Ok false
4848 | _ -> Error( sprintf " %s must be a valid boolean (true/false, yes/no, 1/0) (got: '%s ')" name value)
4949
50- let private getOkValue =
51- function
52- | Ok value -> value
53- | Error _ -> failwith " Internal error: attempted to extract Ok value from Error result"
5450
5551 let private appErrorToString =
5652 function
@@ -87,6 +83,9 @@ module Configuration =
8783 Result.Error( sprintf " Invalid URI: %s " ex.Message)
8884
8985 let private validateOutputDirectory path =
86+ // IMPORTANT: This function intentionally creates the directory during configuration validation.
87+ // This is a fail-fast design decision to ensure we catch invalid paths or permission issues
88+ // BEFORE establishing expensive database connections.
9089 match Security.validatePathSyntax path with
9190 | Result.Error e -> Result.Error e
9291 | Result.Ok validPath ->
@@ -263,119 +262,167 @@ module Configuration =
263262 Env.MAX_ LABELS_ IN_ PATH_ COMPACT
264263 ( Utils.getEnvVar Env.MAX_ LABELS_ IN_ PATH_ COMPACT ( string Defaults.MaxLabelsInPathCompact))
265264
266- let allValidationResults =
267- [ uriResult
268- |> Result.map ( fun _ -> ())
269- |> Result.mapError id
270- outputResult
271- |> Result.map ( fun _ -> ())
272- |> Result.mapError appErrorToString
273- minDiskGb
274- |> Result.map ( fun _ -> ())
275- |> Result.mapError id
276- maxMemoryMb
277- |> Result.map ( fun _ -> ())
278- |> Result.mapError id
279- skipSchema
280- |> Result.map ( fun _ -> ())
281- |> Result.mapError id
282- maxRetries
283- |> Result.map ( fun _ -> ())
284- |> Result.mapError id
285- retryDelayMs
286- |> Result.map ( fun _ -> ())
287- |> Result.mapError id
288- maxRetryDelayMs
289- |> Result.map ( fun _ -> ())
290- |> Result.mapError id
291- queryTimeout
292- |> Result.map ( fun _ -> ())
293- |> Result.mapError id
294- enableDebug
295- |> Result.map ( fun _ -> ())
296- |> Result.mapError id
297- validateJson
298- |> Result.map ( fun _ -> ())
299- |> Result.mapError id
300- allowInsecure
301- |> Result.map ( fun _ -> ())
302- |> Result.mapError id
303- batchSize
304- |> Result.map ( fun _ -> ())
305- |> Result.mapError id
306- jsonBufferSizeKb
307- |> Result.map ( fun _ -> ())
308- |> Result.mapError id
309- maxPathLength
310- |> Result.map ( fun _ -> ())
311- |> Result.mapError id
312- pathFullModeLimit
313- |> Result.map ( fun _ -> ())
314- |> Result.mapError id
315- pathCompactModeLimit
316- |> Result.map ( fun _ -> ())
317- |> Result.mapError id
318- pathPropertyDepth
319- |> Result.map ( fun _ -> ())
320- |> Result.mapError id
321- maxNestedDepth
322- |> Result.map ( fun _ -> ())
323- |> Result.mapError id
324- nestedShallowModeDepth
325- |> Result.map ( fun _ -> ())
326- |> Result.mapError id
327- nestedReferenceModeDepth
328- |> Result.map ( fun _ -> ())
329- |> Result.mapError id
330- maxCollectionItems
331- |> Result.map ( fun _ -> ())
332- |> Result.mapError id
333- maxLabelsPerNode
334- |> Result.map ( fun _ -> ())
335- |> Result.mapError id
336- maxLabelsInReferenceMode
337- |> Result.map ( fun _ -> ())
338- |> Result.mapError id
339- maxLabelsInPathCompact
340- |> Result.map ( fun _ -> ())
341- |> Result.mapError id ]
342-
343- let errors =
344- allValidationResults
345- |> List.choose ( function
346- | Error e -> Some e
347- | Ok _ -> None)
348-
349- match errors with
350- | [] ->
265+ // Pattern match on all validation results to extract values safely
266+ match
267+ uriResult,
268+ outputResult,
269+ minDiskGb,
270+ maxMemoryMb,
271+ skipSchema,
272+ maxRetries,
273+ retryDelayMs,
274+ maxRetryDelayMs,
275+ queryTimeout,
276+ enableDebug,
277+ validateJson,
278+ allowInsecure,
279+ batchSize,
280+ jsonBufferSizeKb,
281+ maxPathLength,
282+ pathFullModeLimit,
283+ pathCompactModeLimit,
284+ pathPropertyDepth,
285+ maxNestedDepth,
286+ nestedShallowModeDepth,
287+ nestedReferenceModeDepth,
288+ maxCollectionItems,
289+ maxLabelsPerNode,
290+ maxLabelsInReferenceMode,
291+ maxLabelsInPathCompact
292+ with
293+ | Ok uri,
294+ Ok output,
295+ Ok diskGb,
296+ Ok memMb,
297+ Ok skipSch,
298+ Ok maxRet,
299+ Ok retDelay,
300+ Ok maxRetDelay,
301+ Ok queryTo,
302+ Ok debug,
303+ Ok valJson,
304+ Ok insecure,
305+ Ok batch,
306+ Ok jsonBuf,
307+ Ok pathLen,
308+ Ok pathFull,
309+ Ok pathCompact,
310+ Ok pathDepth,
311+ Ok nestDepth,
312+ Ok nestShallow,
313+ Ok nestRef,
314+ Ok collItems,
315+ Ok labelsNode,
316+ Ok labelsRef,
317+ Ok labelsCompact ->
351318 Result.Ok
352- { Uri = getOkValue uriResult
319+ { Uri = uri
353320 User = Utils.getEnvVar Env.User Defaults.User
354321 Password = Utils.getEnvVar Env.Password Defaults.Password
355- OutputDirectory = getOkValue outputResult
356- MinDiskGb = getOkValue minDiskGb
357- MaxMemoryMb = getOkValue maxMemoryMb
358- SkipSchemaCollection = getOkValue skipSchema
359- MaxRetries = getOkValue maxRetries
360- RetryDelayMs = getOkValue retryDelayMs
361- MaxRetryDelayMs = getOkValue maxRetryDelayMs
362- QueryTimeoutSeconds = getOkValue queryTimeout
363- EnableDebugLogging = getOkValue enableDebug
364- ValidateJsonOutput = getOkValue validateJson
365- AllowInsecure = getOkValue allowInsecure
366- BatchSize = getOkValue batchSize
367- JsonBufferSizeKb = getOkValue jsonBufferSizeKb
368- MaxPathLength = getOkValue maxPathLength
369- PathFullModeLimit = getOkValue pathFullModeLimit
370- PathCompactModeLimit = getOkValue pathCompactModeLimit
371- PathPropertyDepth = getOkValue pathPropertyDepth
372- MaxNestedDepth = getOkValue maxNestedDepth
373- NestedShallowModeDepth = getOkValue nestedShallowModeDepth
374- NestedReferenceModeDepth = getOkValue nestedReferenceModeDepth
375- MaxCollectionItems = getOkValue maxCollectionItems
376- MaxLabelsPerNode = getOkValue maxLabelsPerNode
377- MaxLabelsInReferenceMode = getOkValue maxLabelsInReferenceMode
378- MaxLabelsInPathCompact = getOkValue maxLabelsInPathCompact }
379- | errors -> Result.Error( ConfigError( String.concat " ; " errors))
322+ OutputDirectory = output
323+ MinDiskGb = diskGb
324+ MaxMemoryMb = memMb
325+ SkipSchemaCollection = skipSch
326+ MaxRetries = maxRet
327+ RetryDelayMs = retDelay
328+ MaxRetryDelayMs = maxRetDelay
329+ QueryTimeoutSeconds = queryTo
330+ EnableDebugLogging = debug
331+ ValidateJsonOutput = valJson
332+ AllowInsecure = insecure
333+ BatchSize = batch
334+ JsonBufferSizeKb = jsonBuf
335+ MaxPathLength = pathLen
336+ PathFullModeLimit = pathFull
337+ PathCompactModeLimit = pathCompact
338+ PathPropertyDepth = pathDepth
339+ MaxNestedDepth = nestDepth
340+ NestedShallowModeDepth = nestShallow
341+ NestedReferenceModeDepth = nestRef
342+ MaxCollectionItems = collItems
343+ MaxLabelsPerNode = labelsNode
344+ MaxLabelsInReferenceMode = labelsRef
345+ MaxLabelsInPathCompact = labelsCompact }
346+ | _ ->
347+ // Collect all errors from the Results
348+ let errors =
349+ [ match uriResult with
350+ | Error e -> Some e
351+ | _ -> None
352+ match outputResult with
353+ | Error e -> Some( appErrorToString e)
354+ | _ -> None
355+ match minDiskGb with
356+ | Error e -> Some e
357+ | _ -> None
358+ match maxMemoryMb with
359+ | Error e -> Some e
360+ | _ -> None
361+ match skipSchema with
362+ | Error e -> Some e
363+ | _ -> None
364+ match maxRetries with
365+ | Error e -> Some e
366+ | _ -> None
367+ match retryDelayMs with
368+ | Error e -> Some e
369+ | _ -> None
370+ match maxRetryDelayMs with
371+ | Error e -> Some e
372+ | _ -> None
373+ match queryTimeout with
374+ | Error e -> Some e
375+ | _ -> None
376+ match enableDebug with
377+ | Error e -> Some e
378+ | _ -> None
379+ match validateJson with
380+ | Error e -> Some e
381+ | _ -> None
382+ match allowInsecure with
383+ | Error e -> Some e
384+ | _ -> None
385+ match batchSize with
386+ | Error e -> Some e
387+ | _ -> None
388+ match jsonBufferSizeKb with
389+ | Error e -> Some e
390+ | _ -> None
391+ match maxPathLength with
392+ | Error e -> Some e
393+ | _ -> None
394+ match pathFullModeLimit with
395+ | Error e -> Some e
396+ | _ -> None
397+ match pathCompactModeLimit with
398+ | Error e -> Some e
399+ | _ -> None
400+ match pathPropertyDepth with
401+ | Error e -> Some e
402+ | _ -> None
403+ match maxNestedDepth with
404+ | Error e -> Some e
405+ | _ -> None
406+ match nestedShallowModeDepth with
407+ | Error e -> Some e
408+ | _ -> None
409+ match nestedReferenceModeDepth with
410+ | Error e -> Some e
411+ | _ -> None
412+ match maxCollectionItems with
413+ | Error e -> Some e
414+ | _ -> None
415+ match maxLabelsPerNode with
416+ | Error e -> Some e
417+ | _ -> None
418+ match maxLabelsInReferenceMode with
419+ | Error e -> Some e
420+ | _ -> None
421+ match maxLabelsInPathCompact with
422+ | Error e -> Some e
423+ | _ -> None ]
424+ |> List.choose id
425+
426+ Result.Error( ConfigError( String.concat " ; " errors))
380427 with ex ->
381428 Result.Error( ConfigError( sprintf " Invalid configuration: %s " ex.Message))
0 commit comments