Skip to content

Commit 68ef0bf

Browse files
committed
Implemented several minor bug fixes and enhanced code comments
1 parent 316e1af commit 68ef0bf

15 files changed

+5670
-298
lines changed

Neo4jExport/Neo4jExport.fsproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<Authors>Your Organization</Authors>
1010
<Description>Mission-critical, production-grade tool for exporting Neo4j databases to JSONL format</Description>
1111
<GenerateDocumentationFile>true</GenerateDocumentationFile>
12-
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
12+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1313
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
1414
</PropertyGroup>
1515

@@ -20,7 +20,6 @@
2020
<ItemGroup>
2121
<PackageReference Include="Neo4j.Driver" Version="5.28.1" />
2222
<PackageReference Include="System.Text.Json" Version="9.0.6" />
23-
<PackageReference Include="Fantomas.Core" Version="7.0.2" />
2423
<PackageReference Include="FSharp.Control.AsyncSeq" Version="3.2.1" />
2524
</ItemGroup>
2625

Neo4jExport/src/Configuration.fs

Lines changed: 162 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)