From 4b692a9d1cdddfc6a4badb1dc5b45b67f845ab4c Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 08:10:17 +0100 Subject: [PATCH 01/33] Update model properties to enable json import --- src/api/BdmsContextExtensions.cs | 12 ++++++++++++ src/api/Models/Borehole.cs | 8 ++++---- src/api/Models/Completion.cs | 6 +++--- src/api/Models/Layer.cs | 6 ------ src/api/Models/LayerColorCode.cs | 3 +++ src/api/Models/Stratigraphy.cs | 10 +++++----- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/api/BdmsContextExtensions.cs b/src/api/BdmsContextExtensions.cs index 783ac425c..95f7012cd 100644 --- a/src/api/BdmsContextExtensions.cs +++ b/src/api/BdmsContextExtensions.cs @@ -128,6 +128,10 @@ public static void SeedData(this BdmsContext context) var fakeBoreholes = new Faker() .StrictMode(true) .RuleFor(o => o.Id, f => borehole_ids++) + .RuleFor(o => o.Stratigraphies, _ => new Collection()) + .RuleFor(o => o.Completions, _ => new Collection()) + .RuleFor(o => o.Sections, _ => new Collection
()) + .RuleFor(o => o.Observations, _ => new Collection()) .RuleFor(o => o.CreatedById, f => f.PickRandom(userRange)) .RuleFor(o => o.CreatedBy, _ => default!) .RuleFor(o => o.UpdatedById, f => f.PickRandom(userRange)) @@ -258,6 +262,11 @@ public static void SeedData(this BdmsContext context) var fakeStratigraphies = new Faker() .StrictMode(true) .RuleFor(o => o.Id, f => stratigraphy_ids++) + .RuleFor(o => o.Layers, _ => new Collection()) + .RuleFor(o => o.LithologicalDescriptions, _ => new Collection()) + .RuleFor(o => o.LithostratigraphyLayers, _ => new Collection()) + .RuleFor(o => o.ChronostratigraphyLayers, _ => new Collection()) + .RuleFor(o => o.FaciesDescriptions, _ => new Collection()) .RuleFor(o => o.CreatedById, f => f.PickRandom(userRange).OrNull(f, .05f)) .RuleFor(o => o.CreatedBy, _ => default!) .RuleFor(o => o.BoreholeId, f => f.PickRandom(boreholeRange).OrNull(f, .05f)) @@ -569,6 +578,9 @@ void SeedCodelists(Faker faker) var completionRange = Enumerable.Range(completion_ids, 500); var fakeCompletions = new Faker() .StrictMode(true) + .RuleFor(c => c.Instrumentations, _ => new Collection()) + .RuleFor(c => c.Casings, _ => new Collection()) + .RuleFor(c => c.Backfills, _ => new Collection()) .RuleFor(c => c.BoreholeId, f => f.PickRandom(richBoreholeRange)) .RuleFor(c => c.Borehole, _ => default!) .RuleFor(c => c.Created, f => f.Date.Past().ToUniversalTime()) diff --git a/src/api/Models/Borehole.cs b/src/api/Models/Borehole.cs index 6e82d4b38..d46953d7b 100644 --- a/src/api/Models/Borehole.cs +++ b/src/api/Models/Borehole.cs @@ -358,17 +358,17 @@ public class Borehole : IChangeTracking, IIdentifyable /// /// Gets the 's stratigraphies. /// - public ICollection? Stratigraphies { get; } + public ICollection? Stratigraphies { get; set; } /// /// Gets the 's completions. /// - public ICollection? Completions { get; } + public ICollection? Completions { get; set; } /// /// Gets the 's s. /// - public ICollection
? Sections { get; } + public ICollection
? Sections { get; set; } /// /// Gets the 's . @@ -379,7 +379,7 @@ public class Borehole : IChangeTracking, IIdentifyable /// /// Gets the 's observations. /// - public ICollection? Observations { get; } + public ICollection? Observations { get; set; } /// /// Gets the 's workflows. diff --git a/src/api/Models/Completion.cs b/src/api/Models/Completion.cs index ca54a245b..109182005 100644 --- a/src/api/Models/Completion.cs +++ b/src/api/Models/Completion.cs @@ -84,15 +84,15 @@ public class Completion : IChangeTracking, IIdentifyable /// /// Gets the s associated with the . /// - public ICollection? Instrumentations { get; } + public ICollection? Instrumentations { get; set; } /// /// Gets the s associated with the . /// - public ICollection? Backfills { get; } + public ICollection? Backfills { get; set; } /// /// Gets the s associated with the . /// - public ICollection? Casings { get; } + public ICollection? Casings { get; set; } } diff --git a/src/api/Models/Layer.cs b/src/api/Models/Layer.cs index fbab28c50..a2140b2ec 100644 --- a/src/api/Models/Layer.cs +++ b/src/api/Models/Layer.cs @@ -266,37 +266,31 @@ public class Layer : ILayerDescription, IChangeTracking, IIdentifyable /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerColorCodes { get; set; } /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerDebrisCodes { get; set; } /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerGrainShapeCodes { get; set; } /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerGrainAngularityCodes { get; set; } /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerOrganicComponentCodes { get; set; } /// /// Gets or sets the join table entities. /// - [JsonIgnore] public IList? LayerUscs3Codes { get; set; } /// diff --git a/src/api/Models/LayerColorCode.cs b/src/api/Models/LayerColorCode.cs index a2fc85fa6..513461fc5 100644 --- a/src/api/Models/LayerColorCode.cs +++ b/src/api/Models/LayerColorCode.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace BDMS.Models; @@ -12,6 +13,7 @@ public class LayerColorCode : ILayerCode [Column("layer_id")] public int LayerId { get; set; } + [JsonIgnore] /// public Layer Layer { get; set; } @@ -19,6 +21,7 @@ public class LayerColorCode : ILayerCode [Column("color_id")] public int CodelistId { get; set; } + [JsonIgnore] /// public Codelist Codelist { get; set; } } diff --git a/src/api/Models/Stratigraphy.cs b/src/api/Models/Stratigraphy.cs index 074a60fb6..f3d92590b 100644 --- a/src/api/Models/Stratigraphy.cs +++ b/src/api/Models/Stratigraphy.cs @@ -83,25 +83,25 @@ public class Stratigraphy : IChangeTracking, IIdentifyable /// /// Gets the s associated with the . /// - public ICollection? Layers { get; } + public ICollection? Layers { get; set; } /// /// Gets the s associated with the . /// - public ICollection? LithologicalDescriptions { get; } + public ICollection? LithologicalDescriptions { get; set; } /// /// Gets the s associated with the . /// - public ICollection? FaciesDescriptions { get; } + public ICollection? FaciesDescriptions { get; set; } /// /// Gets the s associated with the . /// - public ICollection? ChronostratigraphyLayers { get; } + public ICollection? ChronostratigraphyLayers { get; set; } /// /// Gets the s associated with the . /// - public ICollection? LithostratigraphyLayers { get; } + public ICollection? LithostratigraphyLayers { get; set; } } From ce22aa1a43d02814eada33ffa30a47d3d507e86c Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 08:13:35 +0100 Subject: [PATCH 02/33] Add json import to upload controller --- src/api/Controllers/FileTypeChecker.cs | 7 + src/api/Controllers/UploadController.cs | 240 ++++++++++++++++++++++-- 2 files changed, 227 insertions(+), 20 deletions(-) diff --git a/src/api/Controllers/FileTypeChecker.cs b/src/api/Controllers/FileTypeChecker.cs index d48f9dc69..b2f087989 100644 --- a/src/api/Controllers/FileTypeChecker.cs +++ b/src/api/Controllers/FileTypeChecker.cs @@ -12,6 +12,13 @@ public static class FileTypeChecker /// true if the is a csv file; false otherwise. public static bool IsCsv(IFormFile file) => HasCorrectFileExtension(file, ".csv"); + /// + /// Checks if the is a JSON file. + /// + /// The file to check the type for. + /// true if the is a JSON file; false otherwise. + public static bool IsJson(IFormFile file) => HasCorrectFileExtension(file, ".json"); + /// /// Checks if the is of the expected type. /// diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 40e9848bc..f2c3c1d95 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -6,9 +6,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using System.Collections; using System.Globalization; using System.Net; +using System.Text.Json; namespace BDMS.Controllers; @@ -32,6 +32,7 @@ public class UploadController : ControllerBase PrepareHeaderForMatch = args => args.Header.Humanize(LetterCasing.Title), MissingFieldFound = null, }; + private static readonly JsonSerializerOptions jsonImportOptions = new() { PropertyNameCaseInsensitive = true }; public UploadController(BdmsContext context, ILogger logger, LocationService locationService, CoordinateService coordinateService, BoreholeFileCloudService boreholeFileCloudService) { @@ -42,6 +43,200 @@ public UploadController(BdmsContext context, ILogger logger, L this.boreholeFileCloudService = boreholeFileCloudService; } + /// + /// Receives an uploaded JSON file to import one or several (s). + /// + /// The of the new (s). + /// The containing the borehole JSON records that were uploaded. + /// The number of the newly created s. + [HttpPost("json")] + [Authorize(Policy = PolicyNames.Viewer)] + [RequestSizeLimit(int.MaxValue)] + [RequestFormLimits(MultipartBodyLengthLimit = MaxFileSize)] + public async Task> UploadJsonFile(int workgroupId, IFormFile file) + { + // Increase max allowed errors to be able to return more validation errors at once. + ModelState.MaxAllowedErrors = 1000; + + if (file == null || file.Length == 0) + { + return BadRequest("No file uploaded."); + } + + if (!FileTypeChecker.IsJson(file)) return BadRequest("Invalid file type for borehole json."); + + try + { + using var stream = file.OpenReadStream(); + using var reader = new StreamReader(stream); + var jsonContent = await reader.ReadToEndAsync().ConfigureAwait(false); + + List? boreholes; + + try + { + boreholes = JsonSerializer.Deserialize>(jsonContent, jsonImportOptions); + } + catch (JsonException) + { + return BadRequest("The provided file is not a array of boreholes or is not a valid json format."); + } + + if (boreholes == null || boreholes.Count == 0) + { + return BadRequest("No boreholes found in file."); + } + + for (var i = 0; i < boreholes.Count; i++) + { + boreholes[i].ImportId = i + 1; + } + + ValidateBoreholeImports(workgroupId, boreholes, true); + + if (!ModelState.IsValid) + { + return ValidationProblem(statusCode: (int)HttpStatusCode.BadRequest); + } + + var subjectId = HttpContext.GetUserSubjectId(); + + var user = await context.Users + .AsNoTracking() + .SingleOrDefaultAsync(u => u.SubjectId == subjectId) + .ConfigureAwait(false); + + foreach (var borehole in boreholes) + { + borehole.WorkgroupId = workgroupId; + borehole.Id = 0; + borehole.LockedById = null; + + foreach (var strati in borehole.Stratigraphies) + { + strati.Id = 0; + strati.BoreholeId = 0; + strati.Borehole = borehole; + foreach (var lithology in strati.Layers) + { + lithology.Id = 0; + lithology.StratigraphyId = 0; + lithology.Stratigraphy = strati; + } + + foreach (var chronostratigraphyLayer in strati.ChronostratigraphyLayers) + { + chronostratigraphyLayer.Id = 0; + chronostratigraphyLayer.StratigraphyId = 0; + chronostratigraphyLayer.Stratigraphy = strati; + } + + foreach (var lithostratigraphyLayer in strati.LithostratigraphyLayers) + { + lithostratigraphyLayer.Id = 0; + lithostratigraphyLayer.StratigraphyId = 0; + lithostratigraphyLayer.Stratigraphy = strati; + } + + foreach (var lithologicalDescription in strati.LithologicalDescriptions) + { + lithologicalDescription.Id = 0; + lithologicalDescription.StratigraphyId = 0; + lithologicalDescription.Stratigraphy = strati; + } + + foreach (var faciesDescription in strati.FaciesDescriptions) + { + faciesDescription.Id = 0; + faciesDescription.StratigraphyId = 0; + faciesDescription.Stratigraphy = strati; + } + + foreach (var chronostratigraphyLayer in strati.ChronostratigraphyLayers) + { + chronostratigraphyLayer.Id = 0; + chronostratigraphyLayer.StratigraphyId = 0; + chronostratigraphyLayer.Stratigraphy = strati; + } + } + + foreach (var completion in borehole.Completions) + { + completion.Id = 0; + completion.BoreholeId = 0; + completion.Borehole = borehole; + foreach (var instrumentation in completion.Instrumentations) + { + instrumentation.Id = 0; + instrumentation.CompletionId = 0; + instrumentation.Completion = completion; + } + + foreach (var casing in completion.Casings) + { + casing.Id = 0; + casing.CompletionId = 0; + casing.Completion = completion; + + foreach (var casingElement in casing.CasingElements) + { + casingElement.Id = 0; + casingElement.CasingId = 0; + casingElement.Casing = casing; + } + } + + foreach (var backfill in completion.Backfills) + { + backfill.Id = 0; + backfill.CompletionId = 0; + backfill.Completion = completion; + } + + foreach (var instrumentation in completion.Instrumentations) + { + instrumentation.Id = 0; + instrumentation.CompletionId = 0; + instrumentation.Completion = completion; + } + } + + foreach (var section in borehole.Sections) + { + section.Id = 0; + section.BoreholeId = 0; + section.Borehole = borehole; + + foreach (var sectionElement in section.SectionElements) + { + sectionElement.Id = 0; + sectionElement.SectionId = 0; + sectionElement.Section = section; + } + } + + foreach (var observation in borehole.Observations) + { + observation.Id = 0; + observation.BoreholeId = 0; + observation.Borehole = borehole; + } + + borehole.Workflows.Clear(); + borehole.Workflows.Add(new Workflow { Borehole = borehole, Role = Role.Editor, UserId = user.Id }); + } + + await context.Boreholes.AddRangeAsync(boreholes).ConfigureAwait(false); + var result = await SaveChangesAsync(() => Ok(boreholes.Count)).ConfigureAwait(false); + + return result; + } + catch (Exception ex) + { + return StatusCode(500, $"Internal server error: {ex.Message}"); + } + } + /// /// Receives an uploaded csv file to import one or several (s). /// @@ -78,7 +273,7 @@ public async Task> UploadFileAsync(int workgroupId, IFormFile if (lithologyFile != null && !FileTypeChecker.IsCsv(lithologyFile)) return BadRequest("Invalid file type for lithology csv."); var boreholeImports = ReadBoreholesFromCsv(boreholesFile); - ValidateBoreholeImports(workgroupId, boreholeImports, attachments); + ValidateBoreholeImports(workgroupId, boreholeImports, false, attachments); var lithologyImports = new List(); if (lithologyFile != null) @@ -311,7 +506,7 @@ internal static int GetPrecision(IReaderRow row, string fieldName) return 0; } - private void ValidateBoreholeImports(int workgroupId, List boreholesFromFile, IList? attachments = null) + private void ValidateBoreholeImports(int workgroupId, List boreholesFromFile, bool zeroBasedIndex, IList? attachments = null) { // Get boreholes from db with same workgroupId as provided. var boreholesFromDb = context.Boreholes @@ -321,21 +516,23 @@ private void ValidateBoreholeImports(int workgroupId, List boreh .ToList(); // Iterate over provided boreholes, validate them, and create error messages when necessary. Use a non-zero based index for error message keys (e.g. 'Row1'). - foreach (var boreholeFromFile in boreholesFromFile.Select((value, index) => (value, index: index + 1))) + foreach (var boreholeFromFile in boreholesFromFile.Select((value, index) => (value, index))) { + var processingIndex = zeroBasedIndex ? boreholeFromFile.index : boreholeFromFile.index + 1; + var prefix = zeroBasedIndex ? "Borehole" : "Row"; if (string.IsNullOrEmpty(boreholeFromFile.value.OriginalName)) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name")); + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name")); } if (boreholeFromFile.value.LocationX == null && boreholeFromFile.value.LocationXLV03 == null) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x")); + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x")); } if (boreholeFromFile.value.LocationY == null && boreholeFromFile.value.LocationYLV03 == null) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y")); + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y")); } // Check if any borehole with same coordinates (in tolerance) and same total depth is duplicated in file @@ -345,7 +542,7 @@ private void ValidateBoreholeImports(int workgroupId, List boreh CompareValuesWithTolerance(b.LocationX, boreholeFromFile.value.LocationX, 2) && CompareValuesWithTolerance(b.LocationY, boreholeFromFile.value.LocationY, 2))) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); + ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); } // Check if borehole with same coordinates (in tolerance) and same total depth already exists in db. @@ -354,22 +551,25 @@ private void ValidateBoreholeImports(int workgroupId, List boreh (CompareValuesWithTolerance(b.LocationX, boreholeFromFile.value.LocationX, 2) || CompareValuesWithTolerance(b.LocationXLV03, boreholeFromFile.value.LocationX, 2)) && (CompareValuesWithTolerance(b.LocationY, boreholeFromFile.value.LocationY, 2) || CompareValuesWithTolerance(b.LocationYLV03, boreholeFromFile.value.LocationY, 2)))) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database."); + ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database."); } - // Checks if each file name in the comma separated string is present in the list of the attachments. - var attachmentFileNamesToLink = boreholeFromFile.value.Attachments? - .Split(",") - .Select(s => s.Replace(" ", "", StringComparison.OrdinalIgnoreCase)) - .Where(s => !string.IsNullOrEmpty(s)) - .ToList() - ?? new List(); - - foreach (var attachmentFileNameToLink in attachmentFileNamesToLink) + if (attachments != null && !string.IsNullOrEmpty(boreholeFromFile.value.Attachments)) { - if (attachments?.Any(a => a.FileName.Equals(attachmentFileNameToLink, StringComparison.OrdinalIgnoreCase)) == false) + // Checks if each file name in the comma separated string is present in the list of the attachments. + var attachmentFileNamesToLink = boreholeFromFile.value.Attachments? + .Split(",") + .Select(s => s.Replace(" ", "", StringComparison.OrdinalIgnoreCase)) + .Where(s => !string.IsNullOrEmpty(s)) + .ToList() + ?? new List(); + + foreach (var attachmentFileNameToLink in attachmentFileNamesToLink) { - ModelState.AddModelError($"Row{boreholeFromFile.index}", $"Attachment file '{attachmentFileNameToLink}' not found."); + if (attachments?.Any(a => a.FileName.Equals(attachmentFileNameToLink, StringComparison.OrdinalIgnoreCase)) == false) + { + ModelState.AddModelError($"{prefix}{processingIndex}", $"Attachment file '{attachmentFileNameToLink}' not found."); + } } } } From 1105e03766e6d9f7dabec718295f2b35da468cbd Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 08:17:08 +0100 Subject: [PATCH 03/33] Add json import tests --- tests/api/BDMS.Test.csproj | 15 + tests/api/Controllers/UploadControllerTest.cs | 400 +++ .../json_import_duplicated_by_location.json | 2319 ++++++++++++++++ .../json_import_duplicates_existing.json | 2319 ++++++++++++++++ tests/api/TestData/json_import_single.json | 1441 ++++++++++ tests/api/TestData/json_import_valid.json | 2332 +++++++++++++++++ tests/api/TestData/not_a_json_file.csv | 2 + 7 files changed, 8828 insertions(+) create mode 100644 tests/api/TestData/json_import_duplicated_by_location.json create mode 100644 tests/api/TestData/json_import_duplicates_existing.json create mode 100644 tests/api/TestData/json_import_single.json create mode 100644 tests/api/TestData/json_import_valid.json create mode 100644 tests/api/TestData/not_a_json_file.csv diff --git a/tests/api/BDMS.Test.csproj b/tests/api/BDMS.Test.csproj index 68c1d325a..dff7fa83b 100644 --- a/tests/api/BDMS.Test.csproj +++ b/tests/api/BDMS.Test.csproj @@ -104,6 +104,18 @@ Always + + Always + + + Always + + + Always + + + Always + Always @@ -119,6 +131,9 @@ Always + + Always + Always diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 406b02f88..6747600aa 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -77,6 +77,406 @@ public async Task TestCleanup() loggerMock.Verify(); } + [TestMethod] + public async Task UploadJsonWithSingleObjectInsteadOfArrayShouldReturnError() + { + var boreholeJsonFile = GetFormFileByExistingFile("json_import_single.json"); + + ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + + ActionResultAssert.IsBadRequest(response.Result); + BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; + Assert.AreEqual("The provided file is not a list of boreholes or is not a valid json format.", badRequestResult.Value); + } + + [TestMethod] + public async Task UploadJsonWithValidJsonShouldSaveData() + { + var boreholeJsonFile = GetFormFileByExistingFile("json_import_valid.json"); + + ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + + ActionResultAssert.IsOk(response.Result); + OkObjectResult okResult = (OkObjectResult)response.Result!; + Assert.AreEqual(2, okResult.Value); + + var borehole = GetBoreholesWithIncludes(context.Boreholes).ToList().Find(b => b.OriginalName == "PURPLETOLL"); + + // Assert borehole + Assert.IsNotNull(borehole.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(borehole.Created, "Created should not be null"); + Assert.IsNotNull(borehole.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(borehole.Updated, "Updated should not be null"); + Assert.IsNull(borehole.LockedById, "LockedById should be null"); + Assert.IsNull(borehole.Locked, "Locked should be null"); + Assert.AreEqual(1, borehole.WorkgroupId, "WorkgroupId"); + Assert.IsNotNull(borehole.Workgroup, "Workgroup should not be null"); + Assert.IsTrue(borehole.IsPublic, "IsPublic"); + Assert.IsNull(borehole.TypeId, "TypeId should be null"); + Assert.IsNull(borehole.Type, "Type should be null"); + Assert.AreEqual(2739000, borehole.LocationX, "LocationX"); + Assert.AreEqual(6, borehole.PrecisionLocationX, "PrecisionLocationX"); + Assert.AreEqual(1291100, borehole.LocationY, "LocationY"); + Assert.AreEqual(7, borehole.PrecisionLocationY, "PrecisionLocationY"); + Assert.AreEqual(610700, borehole.LocationXLV03, "LocationXLV03"); + Assert.AreEqual(4, borehole.PrecisionLocationXLV03, "PrecisionLocationXLV03"); + Assert.AreEqual(102500, borehole.LocationYLV03, "LocationYLV03"); + Assert.AreEqual(3, borehole.PrecisionLocationYLV03, "PrecisionLocationYLV03"); + Assert.AreEqual((ReferenceSystem)20104002, borehole.OriginalReferenceSystem, "OriginalReferenceSystem"); + Assert.AreEqual(3160.6575921925983, borehole.ElevationZ, "ElevationZ"); + Assert.AreEqual(20106001, borehole.HrsId, "HrsId"); + Assert.IsNull(borehole.Hrs, "Hrs should be null"); + Assert.AreEqual(567.0068294587577, borehole.TotalDepth, "TotalDepth"); + Assert.IsNull(borehole.RestrictionId, "RestrictionId should be null"); + Assert.IsNull(borehole.Restriction, "Restriction should be null"); + Assert.IsNull(borehole.RestrictionUntil, "RestrictionUntil should be null"); + Assert.IsFalse(borehole.NationalInterest, "NationalInterest"); + Assert.AreEqual("PURPLETOLL", borehole.OriginalName, "OriginalName"); + Assert.AreEqual("GREYGOAT", borehole.AlternateName, "AlternateName"); + Assert.IsNull(borehole.LocationPrecisionId, "LocationPrecisionId should be null"); + Assert.IsNull(borehole.LocationPrecision, "LocationPrecision should be null"); + Assert.AreEqual(20114002, borehole.ElevationPrecisionId, "ElevationPrecisionId"); + Assert.IsNull(borehole.ElevationPrecision, "ElevationPrecision should be null"); + Assert.AreEqual("Switchable explicit superstructure", borehole.ProjectName, "ProjectName"); + Assert.AreEqual("Montenegro", borehole.Country, "Country"); + Assert.AreEqual("Texas", borehole.Canton, "Canton"); + Assert.AreEqual("Lake Reecechester", borehole.Municipality, "Municipality"); + Assert.AreEqual(22103009, borehole.PurposeId, "PurposeId"); + Assert.IsNull(borehole.Purpose, "Purpose should be null"); + Assert.AreEqual(22104006, borehole.StatusId, "StatusId"); + Assert.IsNull(borehole.Status, "Status should be null"); + Assert.AreEqual(22108003, borehole.QtDepthId, "QtDepthId"); + Assert.IsNull(borehole.QtDepth, "QtDepth should be null"); + Assert.AreEqual(759.5479580385368, borehole.TopBedrockFreshMd, "TopBedrockFreshMd"); + Assert.AreEqual(1.338392690447342, borehole.TopBedrockWeatheredMd, "TopBedrockWeatheredMd"); + Assert.IsFalse(borehole.HasGroundwater, "HasGroundwater"); + Assert.AreEqual(borehole.Remarks, "This product works too well."); + Assert.AreEqual(15104543, borehole.LithologyTopBedrockId, "LithologyTopBedrockId"); + Assert.IsNull(borehole.LithologyTopBedrock, "LithologyTopBedrock should be null"); + Assert.AreEqual(15302037, borehole.LithostratigraphyId, "LithostratigraphyId"); + Assert.IsNull(borehole.Lithostratigraphy, "Lithostratigraphy should be null"); + Assert.AreEqual(15001060, borehole.ChronostratigraphyId, "ChronostratigraphyId"); + Assert.IsNull(borehole.Chronostratigraphy, "Chronostratigraphy should be null"); + Assert.AreEqual(899.1648284248844, borehole.ReferenceElevation, "ReferenceElevation"); + Assert.AreEqual(20114006, borehole.QtReferenceElevationId, "QtReferenceElevationId"); + Assert.IsNull(borehole.QtReferenceElevation, "QtReferenceElevation should be null"); + Assert.AreEqual(20117005, borehole.ReferenceElevationTypeId, "ReferenceElevationTypeId"); + Assert.IsNull(borehole.ReferenceElevationType, "ReferenceElevationType should be null"); + + // Assert stratigraphy + Assert.AreEqual(2, borehole.Stratigraphies.Count, "Stratigraphies.Count"); + var stratigraphy = borehole.Stratigraphies.First(); + Assert.IsNotNull(stratigraphy.Borehole, "stratigraphy.Borehole should not be null"); + Assert.IsTrue(stratigraphy.IsPrimary, "IsPrimary"); + Assert.IsNotNull(stratigraphy.Updated, "Updated should not be null"); + Assert.IsNotNull(stratigraphy.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(stratigraphy.Created, "Created should not be null"); + Assert.IsNotNull(stratigraphy.CreatedById, "CreatedById should not be null"); + Assert.AreEqual("Marjolaine Hegmann", stratigraphy.Name, "Name"); + Assert.AreEqual(9003, stratigraphy.QualityId, "QualityId"); + Assert.IsNull(stratigraphy.Quality, "Quality should be null"); + Assert.AreEqual("My co-worker Ali has one of these. He says it looks towering.", stratigraphy.Notes, "Notes"); + + // Assert stratigraphy's layers + Assert.AreEqual(2, stratigraphy.Layers.Count, "Stratigraphy.Layers.Count"); + var layer = stratigraphy.Layers.First(); + Assert.IsNotNull(layer.Created, "Created should not be null"); + Assert.IsNotNull(layer.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(layer.Updated, "Updated should not be null"); + Assert.IsNotNull(layer.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(layer.Stratigraphy, "layer.Stratigraphy should not be null"); + Assert.IsTrue(layer.IsUndefined, "IsUndefined should be true"); + Assert.AreEqual(0, layer.FromDepth, "FromDepth"); + Assert.AreEqual(10, layer.ToDepth, "ToDepth"); + Assert.IsFalse(layer.IsLast, "IsLast should be false"); + Assert.AreEqual(9002, layer.DescriptionQualityId, "DescriptionQualityId"); + Assert.IsNull(layer.DescriptionQuality, "DescriptionQuality should be null"); + Assert.AreEqual(15104888, layer.LithologyId, "LithologyId"); + Assert.IsNull(layer.Lithology, "Lithology should be null"); + Assert.AreEqual(21101003, layer.PlasticityId, "PlasticityId"); + Assert.IsNull(layer.Plasticity, "Plasticity should be null"); + Assert.AreEqual(21103003, layer.ConsistanceId, "ConsistanceId"); + Assert.IsNull(layer.Consistance, "Consistance should be null"); + Assert.IsNull(layer.AlterationId, "AlterationId should be null"); + Assert.IsNull(layer.Alteration, "Alteration should be null"); + Assert.AreEqual(21102003, layer.CompactnessId, "CompactnessId"); + Assert.IsNull(layer.Compactness, "Compactness should be null"); + Assert.AreEqual(21109002, layer.GrainSize1Id, "GrainSize1Id"); + Assert.IsNull(layer.GrainSize1, "GrainSize1 should be null"); + Assert.AreEqual(21109002, layer.GrainSize2Id, "GrainSize2Id"); + Assert.IsNull(layer.GrainSize2, "GrainSize2 should be null"); + Assert.AreEqual(21116003, layer.CohesionId, "CohesionId"); + Assert.IsNull(layer.Cohesion, "Cohesion should be null"); + Assert.AreEqual("synergistic", layer.OriginalUscs, "OriginalUscs"); + Assert.AreEqual(23107001, layer.UscsDeterminationId, "UscsDeterminationId"); + Assert.IsNull(layer.UscsDetermination, "UscsDetermination should be null"); + Assert.AreEqual("payment optical copy networks", layer.Notes, "Notes"); + Assert.AreEqual(15303008, layer.LithostratigraphyId, "LithostratigraphyId"); + Assert.IsNull(layer.Lithostratigraphy, "Lithostratigraphy should be null"); + Assert.AreEqual(21105004, layer.HumidityId, "HumidityId"); + Assert.IsNull(layer.Humidity, "Humidity should be null"); + Assert.IsTrue(layer.IsStriae, "IsStriae should be true"); + Assert.AreEqual(30000019, layer.GradationId, "GradationId"); + Assert.IsNull(layer.Gradation, "Gradation should be null"); + Assert.AreEqual(15104470, layer.LithologyTopBedrockId, "LithologyTopBedrockId"); + Assert.IsNull(layer.LithologyTopBedrock, "LithologyTopBedrock should be null"); + Assert.AreEqual("Handmade connect Data Progressive Danish Krone", layer.OriginalLithology, "OriginalLithology"); + Assert.IsNotNull(layer.LayerDebrisCodes, "LayerDebrisCodes should not be null"); + Assert.IsNotNull(layer.LayerGrainShapeCodes, "LayerGrainShapeCodes should not be null"); + Assert.IsNotNull(layer.LayerGrainAngularityCodes, "LayerGrainAngularityCodes should not be null"); + Assert.IsNotNull(layer.LayerOrganicComponentCodes, "LayerOrganicComponentCodes should not be null"); + Assert.IsNotNull(layer.LayerUscs3Codes, "LayerUscs3Codes should not be null"); + Assert.IsNotNull(layer.LayerColorCodes, "LayerColorCodes should not be null"); + + // Assert stratigraphy's lithological descriptions + Assert.AreEqual(2, stratigraphy.LithologicalDescriptions.Count, "Stratigraphy.LithologicalDescriptions.Count"); + var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0); + Assert.IsNotNull(lithologicalDescription.Created, "Created should not be null"); + Assert.IsNotNull(lithologicalDescription.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(lithologicalDescription.Updated, "Updated should not be null"); + Assert.IsNotNull(lithologicalDescription.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(lithologicalDescription.Stratigraphy, "lithologicalDescription.Stratigraphy should not be null"); + Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", lithologicalDescription.Description, "Description"); + Assert.AreEqual(9005, lithologicalDescription.DescriptionQualityId, "DescriptionQualityId"); + Assert.IsNull(lithologicalDescription.DescriptionQuality, "DescriptionQuality should be null"); + Assert.AreEqual(0, lithologicalDescription.FromDepth, "FromDepth"); + Assert.AreEqual(10, lithologicalDescription.ToDepth, "ToDepth"); + + // Assert stratigraphy's facies descriptions + Assert.AreEqual(2, stratigraphy.FaciesDescriptions.Count, "Stratigraphy.FaciesDescriptions.Count"); + var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0); + Assert.IsNotNull(faciesDescription.Created, "Created should not be null"); + Assert.IsNotNull(faciesDescription.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(faciesDescription.Updated, "Updated should not be null"); + Assert.IsNotNull(faciesDescription.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(faciesDescription.Stratigraphy, "faciesDescription.Stratigraphy should not be null"); + Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", faciesDescription.Description, "Description"); + Assert.AreEqual(9005, faciesDescription.DescriptionQualityId, "DescriptionQualityId"); + Assert.IsNull(faciesDescription.DescriptionQuality, "DescriptionQuality should be null"); + Assert.AreEqual(0, faciesDescription.FromDepth, "FromDepth"); + Assert.AreEqual(10, faciesDescription.ToDepth, "ToDepth"); + + // Assert stratigraphy's chronostratigraphy layers + Assert.AreEqual(2, stratigraphy.ChronostratigraphyLayers.Count, "Stratigraphy.ChronostratigraphyLayers.Count"); + var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0); + Assert.IsNotNull(chronostratigraphyLayer.Created, "Created should not be null"); + Assert.IsNotNull(chronostratigraphyLayer.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(chronostratigraphyLayer.Updated, "Updated should not be null"); + Assert.IsNotNull(chronostratigraphyLayer.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(chronostratigraphyLayer.Stratigraphy, "chronostratigraphyLayer.Stratigraphy should not be null"); + Assert.AreEqual(15001134, chronostratigraphyLayer.ChronostratigraphyId, "ChronostratigraphyId"); + Assert.IsNull(chronostratigraphyLayer.Chronostratigraphy, "Chronostratigraphy should be null"); + Assert.AreEqual(0, chronostratigraphyLayer.FromDepth, "FromDepth"); + Assert.AreEqual(10, chronostratigraphyLayer.ToDepth, "ToDepth"); + + // Assert stratigraphy's lithostratigraphy layers + Assert.AreEqual(2, stratigraphy.LithostratigraphyLayers.Count, "Stratigraphy.LithostratigraphyLayers.Count"); + var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0); + Assert.IsNotNull(lithostratigraphyLayer.Created, "Created should not be null"); + Assert.IsNotNull(lithostratigraphyLayer.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(lithostratigraphyLayer.Updated, "Updated should not be null"); + Assert.IsNotNull(lithostratigraphyLayer.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(lithostratigraphyLayer.Stratigraphy, "lithostratigraphyLayer.Stratigraphy should not be null"); + Assert.AreEqual(15303501, lithostratigraphyLayer.LithostratigraphyId, "LithostratigraphyId"); + Assert.IsNull(lithostratigraphyLayer.Lithostratigraphy, "lithostratigraphyLayer.Lithostratigraphy should not be null"); + Assert.AreEqual(0, lithostratigraphyLayer.FromDepth, "FromDepth"); + Assert.AreEqual(10, lithostratigraphyLayer.ToDepth, "ToDepth"); + + // Assert borehole's completions + Assert.AreEqual(2, borehole.Completions.Count, "Completions.Count"); + var completion = borehole.Completions.First(); + Assert.IsNotNull(completion.Created, "Created should not be null"); + Assert.IsNotNull(completion.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(completion.Updated, "Updated should not be null"); + Assert.IsNotNull(completion.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(completion.Borehole, "completion.Borehole should not be null"); + Assert.AreEqual("Handcrafted Rubber Chair", completion.Name, "Name"); + Assert.AreEqual(16000000, completion.KindId, "KindId"); + Assert.IsNull(completion.Kind, "Kind should be null"); + Assert.AreEqual("Ratione ut non in recusandae labore.", completion.Notes, "Notes"); + Assert.AreEqual(DateOnly.Parse("2021-01-24"), completion.AbandonDate, "AbandonDate"); + + // Assert completion's instrumentations + Assert.AreEqual(1, completion.Instrumentations.Count, "Instrumentations.Count"); + var instrumentation = completion.Instrumentations.First(); + Assert.IsNotNull(instrumentation.Created, "Created should not be null"); + Assert.IsNotNull(instrumentation.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(instrumentation.Updated, "Updated should not be null"); + Assert.IsNotNull(instrumentation.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(instrumentation.Completion, "instrumentation.Completion should be null"); + Assert.AreEqual(70, instrumentation.FromDepth, "FromDepth"); + Assert.AreEqual(80, instrumentation.ToDepth, "ToDepth"); + Assert.AreEqual("Explorer", instrumentation.Name, "Name"); + Assert.AreEqual(25000201, instrumentation.KindId, "KindId"); + Assert.IsNull(instrumentation.Kind, "Kind should be null"); + Assert.AreEqual(25000213, instrumentation.StatusId, "StatusId"); + Assert.IsNull(instrumentation.Status, "Status should be null"); + Assert.IsFalse(instrumentation.IsOpenBorehole, "IsOpenBorehole should be false"); + Assert.AreEqual(17000312, instrumentation.CasingId, "CasingId"); + Assert.IsNotNull(instrumentation.Casing, "instrumentation.Casing should not be null"); + Assert.AreEqual("copy Field bandwidth Burg", instrumentation.Notes, "Notes"); + + // Assert completion's backfills + Assert.AreEqual(1, completion.Backfills.Count, "Backfills.Count"); + var backfill = completion.Backfills.First(); + Assert.IsNotNull(backfill.Created, "Created should not be null"); + Assert.IsNotNull(backfill.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(backfill.Updated, "Updated should not be null"); + Assert.IsNotNull(backfill.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(backfill.Completion, "backfill.Completion should be null"); + Assert.AreEqual(70, backfill.FromDepth, "FromDepth"); + Assert.AreEqual(80, backfill.ToDepth, "ToDepth"); + Assert.AreEqual(25000300, backfill.KindId, "KindId"); + Assert.IsNull(backfill.Kind, "Kind should be null"); + Assert.AreEqual(25000306, backfill.MaterialId, "MaterialId"); + Assert.IsNull(backfill.Material, "Material should be null"); + Assert.IsFalse(backfill.IsOpenBorehole, "IsOpenBorehole should be false"); + Assert.AreEqual(17000011, backfill.CasingId, "CasingId"); + Assert.IsNotNull(backfill.Casing, "backfill.Casing should not be null"); + Assert.AreEqual("Licensed Plastic Soap Managed withdrawal Tools & Industrial", backfill.Notes, "Notes"); + + // Assert completion's casings + Assert.AreEqual(1, completion.Casings.Count, "Casings.Count"); + var casing = completion.Casings.First(); + Assert.IsNotNull(casing.Created, "Created should not be null"); + Assert.IsNotNull(casing.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(casing.Updated, "Updated should not be null"); + Assert.IsNotNull(casing.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(casing.Completion, "casing.Completion should not be null"); + Assert.AreEqual("Rustic", casing.Name, "Name"); + Assert.AreEqual(DateOnly.Parse("2021-03-24"), casing.DateStart, "DateStart"); + Assert.AreEqual(DateOnly.Parse("2021-12-12"), casing.DateFinish, "DateFinish"); + Assert.AreEqual("matrices Managed withdrawal Tools & Industrial", casing.Notes, "Notes"); + + // Assert casing's casingelements + Assert.AreEqual(2, casing.CasingElements.Count, "CasingElements.Count"); + var casingElement = casing.CasingElements.First(); + Assert.IsNotNull(casingElement.Created, "Created should not be null"); + Assert.IsNotNull(casingElement.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(casingElement.Updated, "Updated should not be null"); + Assert.IsNotNull(casingElement.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(casingElement.Casing, "casingElement.Casing should not be null"); + Assert.AreEqual(0, casingElement.FromDepth, "FromDepth"); + Assert.AreEqual(10, casingElement.ToDepth, "ToDepth"); + Assert.AreEqual(25000116, casingElement.KindId, "KindId"); + Assert.IsNull(casingElement.Kind, "Kind should be null"); + Assert.AreEqual(25000114, casingElement.MaterialId, "MaterialId"); + Assert.IsNull(casingElement.Material, "Material should be null"); + Assert.AreEqual(7.91766288360472, casingElement.InnerDiameter, "InnerDiameter"); + Assert.AreEqual(4.857009269696199, casingElement.OuterDiameter, "OuterDiameter"); + + // Assert borehole's sections + Assert.AreEqual(2, borehole.Sections.Count, "Sections.Count"); + var section = borehole.Sections.First(); + Assert.IsNotNull(section.Created, "Created should not be null"); + Assert.IsNotNull(section.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(section.Updated, "Updated should not be null"); + Assert.IsNotNull(section.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(section.Borehole, "section.Borehole should not be null"); + Assert.AreEqual("Gourde", section.Name, "Name"); + + // Assert section's sectionelements + Assert.AreEqual(2, section.SectionElements.Count, "SectionElements.Count"); + var sectionElement = section.SectionElements.First(); + Assert.IsNotNull(sectionElement.Created, "Created should not be null"); + Assert.IsNotNull(sectionElement.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(sectionElement.Updated, "Updated should not be null"); + Assert.IsNotNull(sectionElement.UpdatedById, "UpdatedById should not be null"); + Assert.IsNotNull(sectionElement.Section, "sectionElement.Section should not be null"); + Assert.AreEqual(60, sectionElement.FromDepth, "FromDepth"); + Assert.AreEqual(143, sectionElement.ToDepth, "ToDepth"); + Assert.AreEqual(0, sectionElement.Order, "Order"); + Assert.AreEqual(22107004, sectionElement.DrillingMethodId, "DrillingMethodId"); + Assert.AreEqual(DateOnly.Parse("2021-04-06"), sectionElement.DrillingStartDate, "DrillingStartDate"); + Assert.AreEqual(DateOnly.Parse("2021-05-31"), sectionElement.DrillingEndDate, "DrillingEndDate"); + Assert.AreEqual(22102002, sectionElement.CuttingsId, "CuttingsId"); + Assert.AreEqual(8.990221083625322, sectionElement.DrillingDiameter, "DrillingDiameter"); + Assert.AreEqual(18.406672318655378, sectionElement.DrillingCoreDiameter, "DrillingCoreDiameter"); + Assert.AreEqual(22109003, sectionElement.DrillingMudTypeId, "DrillingMudTypeId"); + Assert.AreEqual(22109020, sectionElement.DrillingMudSubtypeId, "DrillingMudSubtypeId"); + + // Assert borehole's observations + Assert.AreEqual(2, borehole.Observations.Count, "Observations.Count"); + var observation = borehole.Observations.First(x => x.FromDepthM == 1900); + Assert.IsNotNull(observation.Created, "Created should not be null"); + Assert.IsNotNull(observation.CreatedById, "CreatedById should not be null"); + Assert.IsNotNull(observation.Updated, "Updated should not be null"); + Assert.IsNotNull(observation.UpdatedById, "UpdatedById should not be null"); + Assert.AreEqual((ObservationType)2, observation.Type, "Type"); + Assert.AreEqual(DateTime.Parse("2021-10-05T17:41:48.389173Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.StartTime, "StartTime"); + Assert.AreEqual(DateTime.Parse("2021-09-21T20:42:21.785577Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.EndTime, "EndTime"); + Assert.AreEqual(1380.508568643829, observation.Duration, "Duration"); + Assert.AreEqual(1900.0, observation.FromDepthM, "FromDepthM"); + Assert.AreEqual(2227.610979433456, observation.ToDepthM, "ToDepthM"); + Assert.AreEqual(3136.3928836828063, observation.FromDepthMasl, "FromDepthMasl"); + Assert.AreEqual(4047.543691819787, observation.ToDepthMasl, "ToDepthMasl"); + Assert.IsTrue(observation.IsOpenBorehole, "IsOpenBorehole"); + Assert.IsNotNull(observation.Casing, "observation.Casing should be null"); + Assert.AreEqual("Quis repellendus nihil et ipsam ut ad eius.", observation.Comment, "Comment"); + Assert.AreEqual(15203156, observation.ReliabilityId, "ReliabilityId"); + Assert.IsNull(observation.Reliability, "Reliability should be null"); + Assert.IsNotNull(observation.Borehole, "observation.Borehole should not be null"); + + // Assert borehole's workflows + Assert.AreEqual(1, borehole.Workflows.Count, "Workflows.Count"); + var workflow = borehole.Workflows.First(); + Assert.IsNull(workflow.Started, "Started should be null"); + Assert.IsNull(workflow.Finished, "Finished should be null"); + Assert.IsNull(workflow.Notes, "Notes should be null"); + Assert.AreEqual(Role.Editor, workflow.Role, "Role"); + Assert.IsNotNull(workflow.User, "User should be null"); + Assert.IsNotNull(workflow.Borehole, "workflow.Borehole should not be null"); + Assert.AreEqual(borehole.CreatedById, workflow.UserId); + Assert.AreEqual(borehole.CreatedById, workflow.UserId); + } + + [TestMethod] + public async Task UploadJsonWithNoJsonFileShouldReturnError() + { + var boreholeJsonFile = GetFormFileByExistingFile("not_a_json_file.csv"); + + ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + + ActionResultAssert.IsBadRequest(response.Result); + BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; + Assert.AreEqual("Invalid file type for borehole json.", badRequestResult.Value); + } + + [TestMethod] + public async Task UploadJsonWithDuplicateBoreholesByLocationShouldReturnError() + { + var boreholeJsonFile = GetFormFileByExistingFile("json_import_duplicated_by_location.json"); + + ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + + Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); + ObjectResult result = (ObjectResult)response.Result!; + ActionResultAssert.IsBadRequest(result); + + ValidationProblemDetails problemDetails = (ValidationProblemDetails)result.Value!; + Assert.AreEqual(2, problemDetails.Errors.Count); + + CollectionAssert.AreEquivalent(new[] { $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times.", }, problemDetails.Errors["Borehole0"]); + CollectionAssert.AreEquivalent(new[] { $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times.", }, problemDetails.Errors["Borehole1"]); + } + + [TestMethod] + public async Task UploadJsonWithDuplicatesExistingBoreholeShouldReturnError() + { + var boreholeJsonFile = GetFormFileByExistingFile("json_import_duplicates_existing.json"); + + ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + + Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); + ObjectResult result = (ObjectResult)response.Result!; + ActionResultAssert.IsBadRequest(result); + + ValidationProblemDetails problemDetails = (ValidationProblemDetails)result.Value!; + Assert.AreEqual(1, problemDetails.Errors.Count); + + CollectionAssert.AreEquivalent(new[] { $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database.", }, problemDetails.Errors["Borehole0"]); + } + [TestMethod] public async Task UploadLithologyShouldSaveData() { diff --git a/tests/api/TestData/json_import_duplicated_by_location.json b/tests/api/TestData/json_import_duplicated_by_location.json new file mode 100644 index 000000000..d8a59b952 --- /dev/null +++ b/tests/api/TestData/json_import_duplicated_by_location.json @@ -0,0 +1,2319 @@ +[ + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2738000, + "precisionLocationX": 6, + "locationY": 1291000, + "precisionLocationY": 7, + "locationXLV03": 610000, + "precisionLocationXLV03": 4, + "locationYLV03": 102000, + "precisionLocationYLV03": 3, + "originalReferenceSystem": 20104002, + "elevationZ": 3160.6575921925983, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 567.0068294587577, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "PURPLETOLL", + "alternateName": "GREYGOAT", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": null, + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + }, + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2738000, + "precisionLocationX": 6, + "locationY": 1291000, + "precisionLocationY": 7, + "locationXLV03": 610000, + "precisionLocationXLV03": 4, + "locationYLV03": 102000, + "precisionLocationYLV03": 3, + "originalReferenceSystem": 20104002, + "elevationZ": 3160.6575921925983, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 567.0068294587577, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "JETMONSTER", + "alternateName": "SKYSHOP", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": null, + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + } +] + diff --git a/tests/api/TestData/json_import_duplicates_existing.json b/tests/api/TestData/json_import_duplicates_existing.json new file mode 100644 index 000000000..bdcc9d15e --- /dev/null +++ b/tests/api/TestData/json_import_duplicates_existing.json @@ -0,0 +1,2319 @@ +[ + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2478298, + "precisionLocationX": 8, + "locationY": 1283998, + "precisionLocationY": 7, + "locationXLV03": 543351, + "precisionLocationXLV03": 1, + "locationYLV03": 255303, + "precisionLocationYLV03": 8, + "originalReferenceSystem": 20104001, + "elevationZ": 3242.7205335082117, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 491.27111420560215, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "PURPLETOLL", + "alternateName": "GREYGOAT", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": null, + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + }, + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2738000, + "precisionLocationX": 6, + "locationY": 1291000, + "precisionLocationY": 7, + "locationXLV03": 610000, + "precisionLocationXLV03": 4, + "locationYLV03": 102000, + "precisionLocationYLV03": 3, + "originalReferenceSystem": 20104002, + "elevationZ": 3160.6575921925983, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 567.0068294587577, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "JETMONSTER", + "alternateName": "SKYSHOP", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": null, + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + } +] + diff --git a/tests/api/TestData/json_import_single.json b/tests/api/TestData/json_import_single.json new file mode 100644 index 000000000..41c8917c2 --- /dev/null +++ b/tests/api/TestData/json_import_single.json @@ -0,0 +1,1441 @@ +{ + "id": 1002670, + "createdById": 5, + "createdBy": null, + "created": "2021-08-03T08:32:22.966113Z", + "updated": "2021-04-30T11:02:59.17319Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 5, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2478298, + "precisionLocationX": 8, + "locationY": 1283998, + "precisionLocationY": 7, + "locationXLV03": 543351, + "precisionLocationXLV03": 1, + "locationYLV03": 255303, + "precisionLocationYLV03": 8, + "originalReferenceSystem": 20104001, + "elevationZ": 3242.7205335082117, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 491.27111420560215, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "PURPLETOLL", + "alternateName": "GREYGOAT", + "locationPrecisionId": 20113007, + "locationPrecision": null, + "elevationPrecisionId": 20114005, + "elevationPrecision": null, + "projectName": null, + "country": "Sierra Leone", + "canton": "Arkansas", + "municipality": "South Hellen", + "purposeId": 22103001, + "purpose": null, + "statusId": 22104002, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 543.0975381951301, + "topBedrockWeatheredMd": 0.701670643268931, + "hasGroundwater": true, + "remarks": "This product works excessively well. It speedily improves my baseball by a lot.", + "lithologyTopBedrockId": 15104790, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15304098, + "lithostratigraphy": null, + "chronostratigraphyId": 15001003, + "chronostratigraphy": null, + "referenceElevation": 1434.1510240613254, + "qtReferenceElevationId": 20114005, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117002, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001305, + "boreholeId": 1002670, + "borehole": null, + "isPrimary": true, + "date": "2021-03-12T23:23:56.346395Z", + "updated": "2021-05-12T11:35:06.047108Z", + "updatedById": 3, + "updatedBy": null, + "created": "2021-03-02T18:23:51.736541Z", + "createdById": 2, + "createdBy": null, + "name": "Sincere Witting", + "qualityId": 9003, + "quality": null, + "notes": "I tried to annihilate it but got bonbon all over it.", + "layers": [ + { + "layerColorCodes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 21112002, + "codelist": null + }, + { + "layerId": 7013050, + "layer": null, + "codelistId": 21112024, + "codelist": null + } + ], + "layerDebrisCodes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 9102, + "codelist": null + }, + { + "layerId": 7013050, + "layer": null, + "codelistId": 9100, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 21110005, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 21115003, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 21108005, + "codelist": null + } + ], + "layerUscs3Codes": [ + { + "layerId": 7013050, + "layer": null, + "codelistId": 23101002, + "codelist": null + }, + { + "layerId": 7013050, + "layer": null, + "codelistId": 23101035, + "codelist": null + } + ], + "id": 7013050, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-25T11:08:52.554898Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-09-04T01:43:24.071883Z", + "isUndefined": false, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9004, + "descriptionQuality": null, + "lithologyId": 15104986, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103004, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109003, + "grainSize1": null, + "grainSize2Id": 23101034, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101007, + "uscs2": null, + "originalUscs": "invoice", + "uscsDeterminationId": 23107002, + "uscsDetermination": null, + "notes": "cross-media Falls Refined Steel Towels Corporate", + "lithostratigraphyId": 15303105, + "lithostratigraphy": null, + "humidityId": 21105005, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104816, + "lithologyTopBedrock": null, + "originalLithology": "24/365 Awesome Frozen Table bypassing interface generate", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013051, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-04-10T07:23:22.69064Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-22T07:43:34.811646Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9003, + "descriptionQuality": null, + "lithologyId": 15104474, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103010, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": 21109001, + "grainSize1": null, + "grainSize2Id": 23101014, + "grainSize2": null, + "cohesionId": 21116005, + "cohesion": null, + "uscs1Id": 23101016, + "uscs1": null, + "uscs2Id": 23101008, + "uscs2": null, + "originalUscs": "Focused", + "uscsDeterminationId": 23107002, + "uscsDetermination": null, + "notes": "Central PNG functionalities Human", + "lithostratigraphyId": 15303489, + "lithostratigraphy": null, + "humidityId": 21105005, + "humidity": null, + "isStriae": false, + "gradationId": 30000016, + "gradation": null, + "lithologyTopBedrockId": 15104628, + "lithologyTopBedrock": null, + "originalLithology": "demand-driven Montenegro Ramp intermediate deposit", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013052, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-24T03:37:52.826382Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-12-08T13:43:45.551409Z", + "isUndefined": true, + "fromDepth": 20, + "toDepth": 30, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104553, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": 21106012, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109006, + "grainSize1": null, + "grainSize2Id": 23101029, + "grainSize2": null, + "cohesionId": 21116004, + "cohesion": null, + "uscs1Id": 23101025, + "uscs1": null, + "uscs2Id": 23101009, + "uscs2": null, + "originalUscs": "International", + "uscsDeterminationId": 23107002, + "uscsDetermination": null, + "notes": "Bedfordshire Incredible Cotton Sausages open-source Tactics", + "lithostratigraphyId": null, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15105031, + "lithologyTopBedrock": null, + "originalLithology": "transmitter transmitter Credit Card Account Corners Metrics", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013053, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-09T23:52:22.962124Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-26T19:43:56.291171Z", + "isUndefined": true, + "fromDepth": 30, + "toDepth": 40, + "isLast": false, + "descriptionQualityId": null, + "descriptionQuality": null, + "lithologyId": 15104631, + "lithology": null, + "plasticityId": 21101001, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": 21109004, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101034, + "uscs1": null, + "uscs2Id": 23101010, + "uscs2": null, + "originalUscs": "Clothing", + "uscsDeterminationId": 23107002, + "uscsDetermination": null, + "notes": "Small Cotton Sausages Jersey payment Division", + "lithostratigraphyId": 15300336, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": 15104842, + "lithologyTopBedrock": null, + "originalLithology": "Strategist Principal compress Soft lime", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013054, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-11-25T20:06:53.097866Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-03-14T01:44:07.030934Z", + "isUndefined": true, + "fromDepth": 40, + "toDepth": 50, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104710, + "lithology": null, + "plasticityId": 21101001, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109001, + "grainSize1": null, + "grainSize2Id": 23101023, + "grainSize2": null, + "cohesionId": 21116001, + "cohesion": null, + "uscs1Id": null, + "uscs1": null, + "uscs2Id": 23101010, + "uscs2": null, + "originalUscs": "Ohio", + "uscsDeterminationId": 23107003, + "uscsDetermination": null, + "notes": "Auto Loan Account Latvian Lats Personal Loan Account Washington", + "lithostratigraphyId": 15302040, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": false, + "gradationId": 30000016, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "Investment Account Concrete 5th generation success Rustic", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013055, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-10-11T16:21:23.233608Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-10-30T07:44:17.770697Z", + "isUndefined": false, + "fromDepth": 50, + "toDepth": 60, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104788, + "lithology": null, + "plasticityId": 21101002, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106007, + "alteration": null, + "compactnessId": 21102006, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101003, + "grainSize2": null, + "cohesionId": 21116004, + "cohesion": null, + "uscs1Id": 23101018, + "uscs1": null, + "uscs2Id": 23101011, + "uscs2": null, + "originalUscs": "Auto Loan Account", + "uscsDeterminationId": 23107003, + "uscsDetermination": null, + "notes": "sky blue Associate firewall Freeway", + "lithostratigraphyId": 15302359, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104466, + "lithologyTopBedrock": null, + "originalLithology": "Rustic Plastic Shirt Florida deposit GB Ports", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013056, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-08-27T12:35:53.369351Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-06-17T13:44:28.51046Z", + "isUndefined": false, + "fromDepth": 60, + "toDepth": 70, + "isLast": false, + "descriptionQualityId": 9005, + "descriptionQuality": null, + "lithologyId": 15104867, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103002, + "consistance": null, + "alterationId": 21106001, + "alteration": null, + "compactnessId": null, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": 23101018, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101027, + "uscs1": null, + "uscs2Id": 23101012, + "uscs2": null, + "originalUscs": "capacitor", + "uscsDeterminationId": 23107003, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15303129, + "lithostratigraphy": null, + "humidityId": null, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": 15104869, + "lithologyTopBedrock": null, + "originalLithology": "Togo New Jersey compressing Clothing Gorgeous Fresh Chicken", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013057, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-07-13T08:50:23.505093Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T19:44:39.250222Z", + "isUndefined": true, + "fromDepth": 70, + "toDepth": 80, + "isLast": false, + "descriptionQualityId": 9004, + "descriptionQuality": null, + "lithologyId": 15104945, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103008, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102006, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101032, + "grainSize2": null, + "cohesionId": 21116001, + "cohesion": null, + "uscs1Id": 23101001, + "uscs1": null, + "uscs2Id": 23101013, + "uscs2": null, + "originalUscs": "bypassing", + "uscsDeterminationId": 23107003, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15303528, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": true, + "gradationId": 30000016, + "gradation": null, + "lithologyTopBedrockId": 15104681, + "lithologyTopBedrock": null, + "originalLithology": "Orchestrator transmit Practical enhance Bedfordshire", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013058, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-29T05:04:53.640835Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-09-21T01:44:49.989985Z", + "isUndefined": true, + "fromDepth": 80, + "toDepth": 90, + "isLast": false, + "descriptionQualityId": 9003, + "descriptionQuality": null, + "lithologyId": 15105024, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103001, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109008, + "grainSize1": null, + "grainSize2Id": 23101012, + "grainSize2": null, + "cohesionId": 21116005, + "cohesion": null, + "uscs1Id": 23101010, + "uscs1": null, + "uscs2Id": 23101014, + "uscs2": null, + "originalUscs": "Integration", + "uscsDeterminationId": 23107003, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300045, + "lithostratigraphy": null, + "humidityId": 21105001, + "humidity": null, + "isStriae": false, + "gradationId": 30000015, + "gradation": null, + "lithologyTopBedrockId": 15104492, + "lithologyTopBedrock": null, + "originalLithology": "action-items Metrics deliver Rupiah collaboration", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7013059, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-14T01:19:23.776577Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-05-09T07:45:00.729748Z", + "isUndefined": true, + "fromDepth": 90, + "toDepth": 100, + "isLast": true, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104511, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103004, + "consistance": null, + "alterationId": 21106008, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": 23101027, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": null, + "uscs1": null, + "uscs2Id": 23101015, + "uscs2": null, + "originalUscs": "Clothing & Outdoors", + "uscsDeterminationId": 23107004, + "uscsDetermination": null, + "notes": "Borders Fantastic plum Web", + "lithostratigraphyId": 15300364, + "lithostratigraphy": null, + "humidityId": 21105002, + "humidity": null, + "isStriae": false, + "gradationId": null, + "gradation": null, + "lithologyTopBedrockId": 15104895, + "lithologyTopBedrock": null, + "originalLithology": "Intelligent Metal Chicken Practical Wooden Mouse generate Home Loan Account Park", + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9013050, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-26T20:06:32.652956Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-06-11T21:41:21.374869Z", + "description": "cohesive South Carolina Cambridgeshire", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9013051, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-10-15T05:50:58.037711Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-03T23:37:04.782876Z", + "description": "Group Technician Group", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + }, + { + "id": 9013052, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-02T15:35:23.422465Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-26T01:32:48.190882Z", + "description": "payment Orchard cultivate", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 20, + "toDepth": 30 + }, + { + "id": 9013053, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-01-19T01:19:48.80722Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-20T03:28:31.598889Z", + "description": "generate District navigating", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 30, + "toDepth": 40 + }, + { + "id": 9013054, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-04-22T13:05:11.319341Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-11-20T01:50:29.737489Z", + "description": "Small Plastic Gloves system engine Incredible", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 40, + "toDepth": 50 + }, + { + "id": 9013055, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": null, + "updatedById": 5, + "updatedBy": null, + "updated": "2021-01-03T07:19:58.414902Z", + "description": "compress digital system", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 50, + "toDepth": 60 + }, + { + "id": 9013056, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-12-11T06:33:04.961483Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-04-27T09:15:41.822909Z", + "description": "Manors 5th generation azure", + "descriptionQualityId": 9000, + "descriptionQuality": null, + "fromDepth": 60, + "toDepth": 70 + }, + { + "id": 9013057, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-12-18T15:54:39.089784Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-10-14T14:34:51.465177Z", + "description": "Handcrafted Metal Salad Investment Account Berkshire", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 70, + "toDepth": 80 + }, + { + "id": 9013058, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-03-08T16:51:08.346598Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-01T02:49:38.70774Z", + "description": "programming Licensed Steel Sausages Square", + "descriptionQualityId": 9000, + "descriptionQuality": null, + "fromDepth": 80, + "toDepth": 90 + }, + { + "id": 9013059, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-11-02T11:46:21.115746Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-04T15:02:52.046929Z", + "description": "Connecticut Credit Card Account Japan", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 90, + "toDepth": 100 + } + ], + "faciesDescriptions": [ + { + "id": 10013050, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-26T20:06:32.652956Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-06-11T21:41:21.374869Z", + "description": "cohesive South Carolina Cambridgeshire", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10013051, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-10-15T05:50:58.037711Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-03T23:37:04.782876Z", + "description": "Group Technician Group", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + }, + { + "id": 10013052, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-02T15:35:23.422465Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-26T01:32:48.190882Z", + "description": "payment Orchard cultivate", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 20, + "toDepth": 30 + }, + { + "id": 10013053, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-01-19T01:19:48.80722Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-20T03:28:31.598889Z", + "description": "generate District navigating", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 30, + "toDepth": 40 + }, + { + "id": 10013054, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-04-22T13:05:11.319341Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-11-20T01:50:29.737489Z", + "description": "Small Plastic Gloves system engine Incredible", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 40, + "toDepth": 50 + }, + { + "id": 10013055, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": null, + "updatedById": 5, + "updatedBy": null, + "updated": "2021-01-03T07:19:58.414902Z", + "description": "compress digital system", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 50, + "toDepth": 60 + }, + { + "id": 10013056, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-12-11T06:33:04.961483Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-04-27T09:15:41.822909Z", + "description": "Manors 5th generation azure", + "descriptionQualityId": 9000, + "descriptionQuality": null, + "fromDepth": 60, + "toDepth": 70 + }, + { + "id": 10013057, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-12-18T15:54:39.089784Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-10-14T14:34:51.465177Z", + "description": "Handcrafted Metal Salad Investment Account Berkshire", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 70, + "toDepth": 80 + }, + { + "id": 10013058, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-03-08T16:51:08.346598Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-01T02:49:38.70774Z", + "description": "programming Licensed Steel Sausages Square", + "descriptionQualityId": 9000, + "descriptionQuality": null, + "fromDepth": 80, + "toDepth": 90 + }, + { + "id": 10013059, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-11-02T11:46:21.115746Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-04T15:02:52.046929Z", + "description": "Connecticut Credit Card Account Japan", + "descriptionQualityId": 9003, + "descriptionQuality": null, + "fromDepth": 90, + "toDepth": 100 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11013050, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-09-27T23:53:27.700981Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-03-15T07:21:36.26583Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001141, + "chronostratigraphy": null + }, + { + "id": 11013051, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-01-15T20:45:22.43328Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-30T08:00:55.034288Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null + }, + { + "id": 11013052, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-05-05T17:37:17.165578Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-06-15T08:40:13.802747Z", + "fromDepth": 20, + "toDepth": 30, + "chronostratigraphyId": 15001147, + "chronostratigraphy": null + }, + { + "id": 11013053, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-08-23T14:29:11.897877Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-31T09:19:32.571205Z", + "fromDepth": 30, + "toDepth": 40, + "chronostratigraphyId": 15001066, + "chronostratigraphy": null + }, + { + "id": 11013054, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-12-11T11:21:06.630176Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-15T09:58:51.339663Z", + "fromDepth": 40, + "toDepth": 50, + "chronostratigraphyId": 30000312, + "chronostratigraphy": null + }, + { + "id": 11013055, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-03-31T08:13:01.362475Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-10-31T10:38:10.108121Z", + "fromDepth": 50, + "toDepth": 60, + "chronostratigraphyId": 15001073, + "chronostratigraphy": null + }, + { + "id": 11013056, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-07-19T05:04:56.094774Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-12-16T11:17:28.87658Z", + "fromDepth": 60, + "toDepth": 70, + "chronostratigraphyId": 15001005, + "chronostratigraphy": null + }, + { + "id": 11013057, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-11-06T01:56:50.827073Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-31T11:56:47.645038Z", + "fromDepth": 70, + "toDepth": 80, + "chronostratigraphyId": 15001079, + "chronostratigraphy": null + }, + { + "id": 11013058, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-02-23T22:48:45.559372Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-18T12:36:06.413496Z", + "fromDepth": 80, + "toDepth": 90, + "chronostratigraphyId": 15001013, + "chronostratigraphy": null + }, + { + "id": 11013059, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-06-13T19:40:40.291671Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-05-03T13:15:25.181955Z", + "fromDepth": 90, + "toDepth": 100, + "chronostratigraphyId": 15001085, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14013050, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-09-27T23:53:27.700981Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-03-15T07:21:36.26583Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15304065, + "lithostratigraphy": null + }, + { + "id": 14013051, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-01-15T20:45:22.43328Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-30T08:00:55.034288Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302158, + "lithostratigraphy": null + }, + { + "id": 14013052, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-05-05T17:37:17.165578Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-06-15T08:40:13.802747Z", + "fromDepth": 20, + "toDepth": 30, + "lithostratigraphyId": 15305017, + "lithostratigraphy": null + }, + { + "id": 14013053, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-08-23T14:29:11.897877Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-31T09:19:32.571205Z", + "fromDepth": 30, + "toDepth": 40, + "lithostratigraphyId": 15302237, + "lithostratigraphy": null + }, + { + "id": 14013054, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-12-11T11:21:06.630176Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-15T09:58:51.339663Z", + "fromDepth": 40, + "toDepth": 50, + "lithostratigraphyId": 15305125, + "lithostratigraphy": null + }, + { + "id": 14013055, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-03-31T08:13:01.362475Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-10-31T10:38:10.108121Z", + "fromDepth": 50, + "toDepth": 60, + "lithostratigraphyId": 15302342, + "lithostratigraphy": null + }, + { + "id": 14013056, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-07-19T05:04:56.094774Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-12-16T11:17:28.87658Z", + "fromDepth": 60, + "toDepth": 70, + "lithostratigraphyId": 15300053, + "lithostratigraphy": null + }, + { + "id": 14013057, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-11-06T01:56:50.827073Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-31T11:56:47.645038Z", + "fromDepth": 70, + "toDepth": 80, + "lithostratigraphyId": 15302421, + "lithostratigraphy": null + }, + { + "id": 14013058, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-02-23T22:48:45.559372Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-18T12:36:06.413496Z", + "fromDepth": 80, + "toDepth": 90, + "lithostratigraphyId": 15300128, + "lithostratigraphy": null + }, + { + "id": 14013059, + "stratigraphyId": 6001305, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-06-13T19:40:40.291671Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-05-03T13:15:25.181955Z", + "fromDepth": 90, + "toDepth": 100, + "lithostratigraphyId": 15302514, + "lithostratigraphy": null + } + ] + } + ], + "completions": [], + "sections": [], + "observations": [], + "workflows": [ + { + "id": 8000631, + "userId": 1, + "boreholeId": 1002670, + "started": "2001-01-19T20:16:25.74119Z", + "finished": null, + "notes": "Legacy Afghani Ferry Profit-focused", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8001835, + "userId": 1, + "boreholeId": 1002670, + "started": "2000-09-12T02:39:13.806924Z", + "finished": null, + "notes": "pink payment Credit Card Account methodical", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [], + "codelists": null, + "boreholeCodelists": [] +} diff --git a/tests/api/TestData/json_import_valid.json b/tests/api/TestData/json_import_valid.json new file mode 100644 index 000000000..7c24bece2 --- /dev/null +++ b/tests/api/TestData/json_import_valid.json @@ -0,0 +1,2332 @@ +[ + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2739000, + "precisionLocationX": 6, + "locationY": 1291100, + "precisionLocationY": 7, + "locationXLV03": 610700, + "precisionLocationXLV03": 4, + "locationYLV03": 102500, + "precisionLocationYLV03": 3, + "originalReferenceSystem": 20104002, + "elevationZ": 3160.6575921925983, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 567.0068294587577, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "PURPLETOLL", + "alternateName": "GREYGOAT", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": "This product works too well.", + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 21109002, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 23101010, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + }, + { + "id": 1000049, + "createdById": 4, + "createdBy": null, + "created": "2021-12-06T23:03:55.072565Z", + "updated": "2021-10-24T21:44:07.044057Z", + "updatedById": 5, + "updatedBy": null, + "locked": null, + "lockedById": 1, + "lockedBy": null, + "workgroupId": 1, + "workgroup": null, + "isPublic": true, + "typeId": null, + "type": null, + "locationX": 2478000, + "precisionLocationX": 8, + "locationY": 1283000, + "precisionLocationY": 7, + "locationXLV03": 543000, + "precisionLocationXLV03": 1, + "locationYLV03": 255000, + "precisionLocationYLV03": 3, + "originalReferenceSystem": 20104002, + "elevationZ": 3160.6575921925983, + "hrsId": 20106001, + "hrs": null, + "totalDepth": 567.0068294587577, + "restrictionId": null, + "restriction": null, + "restrictionUntil": null, + "nationalInterest": false, + "originalName": "JETMONSTER", + "alternateName": "SKYSHOP", + "locationPrecisionId": null, + "locationPrecision": null, + "elevationPrecisionId": 20114002, + "elevationPrecision": null, + "projectName": "Switchable explicit superstructure", + "country": "Montenegro", + "canton": "Texas", + "municipality": "Lake Reecechester", + "purposeId": 22103009, + "purpose": null, + "statusId": 22104006, + "status": null, + "qtDepthId": 22108003, + "qtDepth": null, + "topBedrockFreshMd": 759.5479580385368, + "topBedrockWeatheredMd": 1.338392690447342, + "hasGroundwater": false, + "remarks": null, + "lithologyTopBedrockId": 15104543, + "lithologyTopBedrock": null, + "lithostratigraphyId": 15302037, + "lithostratigraphy": null, + "chronostratigraphyId": 15001060, + "chronostratigraphy": null, + "referenceElevation": 899.1648284248844, + "qtReferenceElevationId": 20114006, + "qtReferenceElevation": null, + "referenceElevationTypeId": 20117005, + "referenceElevationType": null, + "stratigraphies": [ + { + "id": 6001773, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "date": "2021-07-03T22:19:01.256638Z", + "updated": "2021-10-10T06:55:35.566469Z", + "updatedById": 4, + "updatedBy": null, + "created": "2021-11-14T23:20:24.370719Z", + "createdById": 5, + "createdBy": null, + "name": "Marjolaine Hegmann", + "qualityId": 9003, + "quality": null, + "notes": "My co-worker Ali has one of these. He says it looks towering.", + "layers": [ + { + "id": 7017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T14:19:27.827861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-03T15:41:06.161383Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "lithologyId": 15104888, + "lithology": null, + "plasticityId": 21101003, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102003, + "compactness": null, + "grainSize1Id": 21109002, + "grainSize1": null, + "grainSize2Id": 23101009, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "synergistic", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "payment optical copy networks", + "lithostratigraphyId": 15303008, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104470, + "lithologyTopBedrock": null, + "originalLithology": "Handmade connect Data Progressive Danish Krone", + "layerColorCodes": [], + "layerDebrisCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 9104, + "codelist": null + } + ], + "layerGrainShapeCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21110003, + "codelist": null + } + ], + "layerGrainAngularityCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21115007, + "codelist": null + } + ], + "layerOrganicComponentCodes": [ + { + "layerId": 7017730, + "layer": null, + "codelistId": 21108010, + "codelist": null + } + ], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-04-12T10:33:57.963603Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-07-21T21:41:16.901145Z", + "isUndefined": false, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104967, + "lithology": null, + "plasticityId": 21101004, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102007, + "compactness": null, + "grainSize1Id": null, + "grainSize1": null, + "grainSize2Id": 23101024, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101019, + "uscs2": null, + "originalUscs": "Summit", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "Face to face Practical Internal budgetary management", + "lithostratigraphyId": 15303314, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000017, + "gradation": null, + "lithologyTopBedrockId": 15104873, + "lithologyTopBedrock": null, + "originalLithology": "Missouri Technician azure Square Czech Republic", + "layerColorCodes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 21112003, + "codelist": null + } + ], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [ + { + "layerId": 7017731, + "layer": null, + "codelistId": 23101005, + "codelist": null + } + ], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-05-27T05:06:33.303903Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-05T00:07:10.846144Z", + "description": "Bouvet Island (Bouvetoya) Borders networks", + "descriptionQualityId": 9005, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-01-12T14:50:58.688658Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-06-27T02:02:54.254151Z", + "description": "Function-based Operations compressing", + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001134, + "chronostratigraphy": null + }, + { + "id": 11017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001053, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14017730, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-06-23T17:02:34.860115Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-05-12T01:45:32.650546Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303501, + "lithostratigraphy": null + }, + { + "id": 14017731, + "stratigraphyId": 6001773, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-10-11T13:54:29.592414Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-06-27T02:24:51.419005Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302074, + "lithostratigraphy": null + } + ] + }, + { + "id": 6002959, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "date": "2021-02-09T15:59:07.289858Z", + "updated": "2021-08-10T11:13:25.245875Z", + "updatedById": 2, + "updatedBy": null, + "created": "2021-05-30T07:27:17.328273Z", + "createdById": 3, + "createdBy": null, + "name": "Irwin Goldner", + "qualityId": 9001, + "quality": null, + "notes": "I tried to scratch it but got cheeseburger all over it.", + "layers": [ + { + "id": 7029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 5, + "createdBy": null, + "created": "2021-02-14T08:56:17.729001Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-06-23T03:03:59.747165Z", + "isUndefined": true, + "fromDepth": 0, + "toDepth": 10, + "isLast": false, + "descriptionQualityId": 9001, + "descriptionQuality": null, + "lithologyId": 15104797, + "lithology": null, + "plasticityId": 21101005, + "plasticity": null, + "consistanceId": 21103003, + "consistance": null, + "alterationId": null, + "alteration": null, + "compactnessId": 21102001, + "compactness": null, + "grainSize1Id": 21109007, + "grainSize1": null, + "grainSize2Id": 23101025, + "grainSize2": null, + "cohesionId": 21116003, + "cohesion": null, + "uscs1Id": 23101033, + "uscs1": null, + "uscs2Id": 23101030, + "uscs2": null, + "originalUscs": "Home", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": null, + "lithostratigraphyId": 15300031, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": false, + "gradationId": 30000019, + "gradation": null, + "lithologyTopBedrockId": 15104811, + "lithologyTopBedrock": null, + "originalLithology": "Tasty teal rich hack transmitting", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + }, + { + "id": 7029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 4, + "createdBy": null, + "created": "2021-12-31T05:10:47.864743Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-02-08T09:04:10.486928Z", + "isUndefined": true, + "fromDepth": 10, + "toDepth": 20, + "isLast": false, + "descriptionQualityId": 9000, + "descriptionQuality": null, + "lithologyId": 15104875, + "lithology": null, + "plasticityId": 21101006, + "plasticity": null, + "consistanceId": 21103009, + "consistance": null, + "alterationId": 21106005, + "alteration": null, + "compactnessId": 21102005, + "compactness": null, + "grainSize1Id": 21109005, + "grainSize1": null, + "grainSize2Id": null, + "grainSize2": null, + "cohesionId": 21116002, + "cohesion": null, + "uscs1Id": 23101007, + "uscs1": null, + "uscs2Id": 23101031, + "uscs2": null, + "originalUscs": "transmitting", + "uscsDeterminationId": 23107001, + "uscsDetermination": null, + "notes": "orchestrate Ergonomic Clothing, Games & Books Fantastic", + "lithostratigraphyId": 15300346, + "lithostratigraphy": null, + "humidityId": 21105004, + "humidity": null, + "isStriae": true, + "gradationId": 30000018, + "gradation": null, + "lithologyTopBedrockId": null, + "lithologyTopBedrock": null, + "originalLithology": "target Berkshire JBOD quantifying Handmade Granite Table", + "layerColorCodes": [], + "layerDebrisCodes": [], + "layerGrainShapeCodes": [], + "layerGrainAngularityCodes": [], + "layerOrganicComponentCodes": [], + "layerUscs3Codes": [], + "colorCodelistIds": [], + "colorCodelists": null, + "debrisCodelistIds": [], + "debrisCodelists": null, + "grainShapeCodelistIds": [], + "grainShapeCodelists": null, + "grainAngularityCodelistIds": [], + "grainAngularityCodelists": null, + "organicComponentCodelistIds": [], + "organicComponentCodelists": null, + "uscs3CodelistIds": [], + "uscs3Codelists": null + } + ], + "lithologicalDescriptions": [ + { + "id": 9029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 9029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "faciesDescriptions": [ + { + "id": 10029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-01-05T14:04:16.491987Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-01-02T02:47:29.805401Z", + "description": "Malta Steel impactful", + "descriptionQualityId": 9004, + "descriptionQuality": null, + "fromDepth": 0, + "toDepth": 10 + }, + { + "id": 10029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 2, + "createdBy": null, + "created": "2021-08-23T23:48:41.876741Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-04-26T04:43:13.213408Z", + "description": null, + "descriptionQualityId": 9002, + "descriptionQuality": null, + "fromDepth": 10, + "toDepth": 20 + } + ], + "chronostratigraphyLayers": [ + { + "id": 11029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "chronostratigraphyId": 15001128, + "chronostratigraphy": null + }, + { + "id": 11029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "chronostratigraphyId": 15001049, + "chronostratigraphy": null + } + ], + "lithostratigraphyLayers": [ + { + "id": 14029590, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 1, + "createdBy": null, + "created": "2021-06-24T14:21:19.925784Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-06T20:35:26.56566Z", + "fromDepth": 0, + "toDepth": 10, + "lithostratigraphyId": 15303363, + "lithostratigraphy": null + }, + { + "id": 14029591, + "stratigraphyId": 6002959, + "stratigraphy": null, + "createdById": 3, + "createdBy": null, + "created": "2021-10-12T11:13:14.658083Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-01-21T21:14:45.334119Z", + "fromDepth": 10, + "toDepth": 20, + "lithostratigraphyId": 15302016, + "lithostratigraphy": null + } + ] + } + ], + "completions": [ + { + "id": 14000039, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": false, + "name": "Handcrafted Rubber Chair", + "kindId": 16000000, + "kind": null, + "notes": "Ratione ut non in recusandae labore.", + "abandonDate": "2021-01-24", + "createdById": 5, + "createdBy": null, + "created": "2021-02-03T23:26:54.243399Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-02T14:51:58.109498Z", + "instrumentations": [ + { + "id": 15000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "name": "Explorer", + "kindId": 25000201, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000312, + "casing": null, + "notes": "copy Field bandwidth Burg", + "createdById": 5, + "createdBy": null, + "created": "2021-08-16T23:40:46.12209Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-23T15:48:14.865958Z" + } + ], + "backfills": [ + { + "id": 16000377, + "completionId": 14000039, + "completion": null, + "fromDepth": 70, + "toDepth": 80, + "kindId": 25000300, + "kind": null, + "materialId": 25000306, + "material": null, + "isOpenBorehole": false, + "casingId": 17000011, + "casing": null, + "notes": "Licensed Plastic Soap Managed withdrawal Tools & Industrial", + "createdById": 2, + "createdBy": null, + "created": "2021-09-06T07:04:33.886744Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-09-16T13:41:57.627874Z" + } + ], + "casings": [ + { + "id": 17000377, + "completionId": 14000039, + "completion": null, + "name": "Rustic", + "dateStart": "2021-03-24", + "dateFinish": "2021-12-12", + "notes": "matrices Managed withdrawal Tools & Industrial", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000418, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000116, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 7.91766288360472, + "outerDiameter": 4.857009269696199, + "createdById": 4, + "createdBy": null, + "created": "2021-08-19T12:20:23.240861Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-08-09T02:55:16.509448Z" + }, + { + "id": 18000797, + "casingId": 17000377, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000119, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 6.340723261861467, + "outerDiameter": 7.118916691801937, + "createdById": 3, + "createdBy": null, + "created": "2021-06-04T20:39:56.486546Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-19T14:38:11.511527Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-12-23T15:48:14.865958Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-08T10:38:56.903321Z" + } + ] + }, + { + "id": 14000217, + "boreholeId": 1000049, + "borehole": null, + "isPrimary": true, + "name": "Chief", + "kindId": 16000002, + "kind": null, + "notes": "Distinctio omnis fugit harum dolores repellat aspernatur veritatis.", + "abandonDate": "2021-07-06", + "createdById": 2, + "createdBy": null, + "created": "2021-11-12T13:39:58.914416Z", + "updatedById": 3, + "updatedBy": null, + "updated": "2021-02-05T05:34:24.017715Z", + "instrumentations": [ + { + "id": 15000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "name": "F-150", + "kindId": 25000206, + "kind": null, + "statusId": 25000213, + "status": null, + "isOpenBorehole": false, + "casingId": 17000282, + "casing": null, + "notes": "monitor alarm Fresh SSL", + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ], + "backfills": [ + { + "id": 16000326, + "completionId": 14000217, + "completion": null, + "fromDepth": 60, + "toDepth": 70, + "kindId": 25000300, + "kind": null, + "materialId": 25000310, + "material": null, + "isOpenBorehole": false, + "casingId": 17000421, + "casing": null, + "notes": "Handmade Soft Fish Checking Account transmitting salmon", + "createdById": 1, + "createdBy": null, + "created": "2021-09-16T00:26:37.473894Z", + "updatedById": 4, + "updatedBy": null, + "updated": "2021-02-13T06:41:39.324093Z" + } + ], + "casings": [ + { + "id": 17000326, + "completionId": 14000217, + "completion": null, + "name": "Granite", + "dateStart": "2021-04-03", + "dateFinish": "2021-10-31", + "notes": "monitor Checking Account transmitting salmon", + "instrumentations": null, + "backfills": null, + "observations": null, + "casingElements": [ + { + "id": 18000079, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000101, + "kind": null, + "materialId": 25000114, + "material": null, + "innerDiameter": 2.560360856615175, + "outerDiameter": 3.783693659949905, + "createdById": 5, + "createdBy": null, + "created": "2021-11-19T06:13:20.733506Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-09-04T00:59:28.420517Z" + }, + { + "id": 18000458, + "casingId": 17000326, + "casing": null, + "fromDepth": 0, + "toDepth": 10, + "kindId": 25000104, + "kind": null, + "materialId": 25000113, + "material": null, + "innerDiameter": 0.9834212348719227, + "outerDiameter": 6.045601082055644, + "createdById": 4, + "createdBy": null, + "created": "2021-09-04T14:32:53.979192Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-07-15T12:42:23.422596Z" + } + ], + "createdById": 2, + "createdBy": null, + "created": "2021-02-27T12:55:24.861569Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-10-30T02:45:35.127005Z" + } + ] + } + ], + "sections": [ + { + "id": 19000147, + "boreholeId": 1000049, + "borehole": null, + "name": "Gourde", + "createdById": 4, + "createdBy": null, + "created": "2021-05-21T09:08:09.122769Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-08-26T16:14:15.261357Z", + "sectionElements": [ + { + "id": 20000294, + "sectionId": 19000147, + "section": null, + "fromDepth": 60, + "toDepth": 143, + "order": 0, + "drillingMethodId": 22107004, + "drillingStartDate": "2021-04-06", + "drillingEndDate": "2021-05-31", + "cuttingsId": 22102002, + "drillingDiameter": 8.990221083625322, + "drillingCoreDiameter": 18.406672318655378, + "drillingMudTypeId": 22109003, + "drillingMudSubtypeId": 22109020, + "createdById": 5, + "createdBy": null, + "created": "2021-08-21T13:35:32.494658Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-05-10T11:16:47.1862Z" + }, + { + "id": 20000295, + "sectionId": 19000147, + "section": null, + "fromDepth": 12, + "toDepth": 172, + "order": 1, + "drillingMethodId": null, + "drillingStartDate": "2021-10-23", + "drillingEndDate": "2021-12-19", + "cuttingsId": null, + "drillingDiameter": 3.7248316424548773, + "drillingCoreDiameter": 12.15569349571862, + "drillingMudTypeId": null, + "drillingMudSubtypeId": 22109007, + "createdById": 1, + "createdBy": null, + "created": "2021-08-11T16:27:20.790792Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-03-22T23:20:01.892829Z" + } + ] + }, + { + "id": 19000214, + "boreholeId": 1000049, + "borehole": null, + "name": "e-business", + "createdById": 5, + "createdBy": null, + "created": "2021-01-31T15:12:39.773615Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-02-06T12:08:12.748061Z", + "sectionElements": [ + { + "id": 20000428, + "sectionId": 19000214, + "section": null, + "fromDepth": 60, + "toDepth": 175, + "order": 0, + "drillingMethodId": 22107016, + "drillingStartDate": "2021-10-06", + "drillingEndDate": "2021-05-17", + "cuttingsId": null, + "drillingDiameter": 3.4280359667856413, + "drillingCoreDiameter": 0.7755100451295777, + "drillingMudTypeId": 22109021, + "drillingMudSubtypeId": 22109005, + "createdById": 4, + "createdBy": null, + "created": "2021-01-04T13:17:24.176602Z", + "updatedById": 5, + "updatedBy": null, + "updated": "2021-07-20T18:31:37.874428Z" + }, + { + "id": 20000429, + "sectionId": 19000214, + "section": null, + "fromDepth": 13, + "toDepth": 104, + "order": 1, + "drillingMethodId": 22107011, + "drillingStartDate": "2021-04-24", + "drillingEndDate": "2021-12-04", + "cuttingsId": 22102001, + "drillingDiameter": 18.162646525615195, + "drillingCoreDiameter": null, + "drillingMudTypeId": 22109014, + "drillingMudSubtypeId": 22109014, + "createdById": 1, + "createdBy": null, + "created": "2021-12-25T16:09:12.472736Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-06-02T06:34:52.581056Z" + }, + { + "id": 20000430, + "sectionId": 19000214, + "section": null, + "fromDepth": 65, + "toDepth": 133, + "order": 2, + "drillingMethodId": 22107006, + "drillingStartDate": "2021-11-10", + "drillingEndDate": "2021-06-24", + "cuttingsId": 22102001, + "drillingDiameter": null, + "drillingCoreDiameter": 8.273552399256058, + "drillingMudTypeId": 22109007, + "drillingMudSubtypeId": null, + "createdById": 3, + "createdBy": null, + "created": "2021-12-15T19:01:00.76887Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-04-14T18:38:07.287685Z" + } + ] + } + ], + "observations": [ + { + "id": 12000000, + "type": 2, + "startTime": "2021-10-05T17:41:48.389173Z", + "endTime": "2021-09-21T20:42:21.785577Z", + "duration": 1380.508568643829, + "fromDepthM": 1900.0, + "toDepthM": 2227.610979433456, + "fromDepthMasl": 3136.3928836828063, + "toDepthMasl": 4047.543691819787, + "casingId": 17000130, + "isOpenBorehole": true, + "casing": null, + "comment": "Quis repellendus nihil et ipsam ut ad eius.", + "reliabilityId": 15203156, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 4, + "createdBy": null, + "created": "2021-10-09T15:09:45.944463Z", + "updatedById": 1, + "updatedBy": null, + "updated": "2021-04-11T07:21:57.416631Z" + }, + { + "id": 12000067, + "type": 2, + "startTime": "2021-03-18T13:35:45.875877Z", + "endTime": "2021-09-14T15:16:08.77059Z", + "duration": 4444.1706566532, + "fromDepthM": 3358.015691080138, + "toDepthM": 759.5223660401639, + "fromDepthMasl": 4940.758798705768, + "toDepthMasl": 587.5749591791886, + "casingId": 17000495, + "isOpenBorehole": true, + "casing": null, + "comment": "Ut et accusamus praesentium consequuntur nulla dolor.", + "reliabilityId": 15203158, + "reliability": null, + "boreholeId": 1000049, + "borehole": null, + "createdById": 3, + "createdBy": null, + "created": "2021-02-11T01:54:27.815014Z", + "updatedById": 2, + "updatedBy": null, + "updated": "2021-12-22T13:26:28.067476Z" + } + ], + "workflows": [ + { + "id": 8000815, + "userId": 1, + "boreholeId": 1000049, + "started": "1998-10-22T02:25:53.618346Z", + "finished": null, + "notes": "Regional Security Profound Massachusetts", + "user": null, + "borehole": null, + "role": "Editor" + }, + { + "id": 8002019, + "userId": 1, + "boreholeId": 1000049, + "started": "1994-05-15T13:50:42.522916Z", + "finished": null, + "notes": "Tasty Frozen Chicken infrastructures Maine Wisconsin", + "user": null, + "borehole": null, + "role": "Editor" + } + ], + "files": null, + "boreholeFiles": [ + ], + "codelists": null, + "boreholeCodelists": [] + } +] diff --git a/tests/api/TestData/not_a_json_file.csv b/tests/api/TestData/not_a_json_file.csv new file mode 100644 index 000000000..d818aabc1 --- /dev/null +++ b/tests/api/TestData/not_a_json_file.csv @@ -0,0 +1,2 @@ +col1,col2 +BATONORACLE,COTTONBOOK From 78d4d0fa56902d2dca9e1aee2424cef72bb15a73 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 08:20:47 +0100 Subject: [PATCH 04/33] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3206a2dae..59519c2f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Show ChangedAt and ChangedBy information in borehole detail header. - Add JSON export for single and multiple boreholes. - The workgroup name is now displayed in the borehole location tab. +- Add JSON import for boreholes. ### Changed From 69b6b9f82de3dd27a762d95784f8e59d3df644c5 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 10:12:50 +0100 Subject: [PATCH 05/33] Fix warnings --- src/api/Controllers/UploadController.cs | 3 ++- src/api/Models/LayerColorCode.cs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index f2c3c1d95..4c6952a33 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -32,7 +32,8 @@ public class UploadController : ControllerBase PrepareHeaderForMatch = args => args.Header.Humanize(LetterCasing.Title), MissingFieldFound = null, }; - private static readonly JsonSerializerOptions jsonImportOptions = new() { PropertyNameCaseInsensitive = true }; + + private static readonly JsonSerializerOptions jsonImportOptions = new() { PropertyNameCaseInsensitive = true }; public UploadController(BdmsContext context, ILogger logger, LocationService locationService, CoordinateService coordinateService, BoreholeFileCloudService boreholeFileCloudService) { diff --git a/src/api/Models/LayerColorCode.cs b/src/api/Models/LayerColorCode.cs index 513461fc5..38d278fe5 100644 --- a/src/api/Models/LayerColorCode.cs +++ b/src/api/Models/LayerColorCode.cs @@ -13,15 +13,15 @@ public class LayerColorCode : ILayerCode [Column("layer_id")] public int LayerId { get; set; } - [JsonIgnore] /// + [JsonIgnore] public Layer Layer { get; set; } /// [Column("color_id")] public int CodelistId { get; set; } - [JsonIgnore] /// + [JsonIgnore] public Codelist Codelist { get; set; } } From b5eeb10c3b6762c22d32ff52efa2aee27de3674b Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 10:18:13 +0100 Subject: [PATCH 06/33] Fix identation --- src/api/Controllers/UploadController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 4c6952a33..fc03959fd 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -33,7 +33,7 @@ public class UploadController : ControllerBase MissingFieldFound = null, }; - private static readonly JsonSerializerOptions jsonImportOptions = new() { PropertyNameCaseInsensitive = true }; + private static readonly JsonSerializerOptions jsonImportOptions = new() { PropertyNameCaseInsensitive = true }; public UploadController(BdmsContext context, ILogger logger, LocationService locationService, CoordinateService coordinateService, BoreholeFileCloudService boreholeFileCloudService) { From 135ae197c50d8e76f0348bf66fb4d89da4f2fcdc Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 28 Nov 2024 13:14:44 +0100 Subject: [PATCH 07/33] fix tests --- src/api/Controllers/UploadController.cs | 4 ++-- tests/api/Controllers/UploadControllerTest.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index fc03959fd..71f8e36ce 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -64,7 +64,7 @@ public async Task> UploadJsonFile(int workgroupId, IFormFile f return BadRequest("No file uploaded."); } - if (!FileTypeChecker.IsJson(file)) return BadRequest("Invalid file type for borehole json."); + if (!FileTypeChecker.IsJson(file)) return BadRequest("Invalid file type for borehole JSON."); try { @@ -80,7 +80,7 @@ public async Task> UploadJsonFile(int workgroupId, IFormFile f } catch (JsonException) { - return BadRequest("The provided file is not a array of boreholes or is not a valid json format."); + return BadRequest("The provided file is not a array of boreholes or is not a valid JSON format."); } if (boreholes == null || boreholes.Count == 0) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 6747600aa..06b64c7c2 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -86,7 +86,7 @@ public async Task UploadJsonWithSingleObjectInsteadOfArrayShouldReturnError() ActionResultAssert.IsBadRequest(response.Result); BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; - Assert.AreEqual("The provided file is not a list of boreholes or is not a valid json format.", badRequestResult.Value); + Assert.AreEqual("The provided file is not a array of boreholes or is not a valid JSON format.", badRequestResult.Value); } [TestMethod] @@ -439,7 +439,7 @@ public async Task UploadJsonWithNoJsonFileShouldReturnError() ActionResultAssert.IsBadRequest(response.Result); BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; - Assert.AreEqual("Invalid file type for borehole json.", badRequestResult.Value); + Assert.AreEqual("Invalid file type for borehole JSON.", badRequestResult.Value); } [TestMethod] From 8294d67a4205b1ca58ed8b56c76bf881f46915a3 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Fri, 29 Nov 2024 11:19:13 +0100 Subject: [PATCH 08/33] Update properties of LayerCode --- src/api/Models/ILayerCode.cs | 4 ++-- src/api/Models/LayerColorCode.cs | 6 ++---- src/api/Models/LayerDebrisCode.cs | 4 ++-- src/api/Models/LayerGrainAngularityCode.cs | 4 ++-- src/api/Models/LayerGrainShapeCode.cs | 4 ++-- src/api/Models/LayerOrganicComponentCode.cs | 4 ++-- src/api/Models/LayerUscs3Code.cs | 4 ++-- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/api/Models/ILayerCode.cs b/src/api/Models/ILayerCode.cs index 7a13bd35f..b4c0165aa 100644 --- a/src/api/Models/ILayerCode.cs +++ b/src/api/Models/ILayerCode.cs @@ -15,7 +15,7 @@ public interface ILayerCode /// /// Gets or sets the layer in the join table. /// - Layer Layer { get; set; } + Layer? Layer { get; set; } /// /// Gets or sets the ID of the codelist in the join table. @@ -25,5 +25,5 @@ public interface ILayerCode /// /// Gets or sets the codelist in the join table. /// - Codelist Codelist { get; set; } + Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerColorCode.cs b/src/api/Models/LayerColorCode.cs index 38d278fe5..f2ae742f8 100644 --- a/src/api/Models/LayerColorCode.cs +++ b/src/api/Models/LayerColorCode.cs @@ -14,14 +14,12 @@ public class LayerColorCode : ILayerCode public int LayerId { get; set; } /// - [JsonIgnore] - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("color_id")] public int CodelistId { get; set; } /// - [JsonIgnore] - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerDebrisCode.cs b/src/api/Models/LayerDebrisCode.cs index ad3478a49..982c41f4c 100644 --- a/src/api/Models/LayerDebrisCode.cs +++ b/src/api/Models/LayerDebrisCode.cs @@ -13,12 +13,12 @@ public class LayerDebrisCode : ILayerCode public int LayerId { get; set; } /// - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("debris_id")] public int CodelistId { get; set; } /// - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerGrainAngularityCode.cs b/src/api/Models/LayerGrainAngularityCode.cs index a76acc6b4..b973ba036 100644 --- a/src/api/Models/LayerGrainAngularityCode.cs +++ b/src/api/Models/LayerGrainAngularityCode.cs @@ -13,12 +13,12 @@ public class LayerGrainAngularityCode : ILayerCode public int LayerId { get; set; } /// - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("grain_angularity_id")] public int CodelistId { get; set; } /// - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerGrainShapeCode.cs b/src/api/Models/LayerGrainShapeCode.cs index e6a35bf37..5e883b332 100644 --- a/src/api/Models/LayerGrainShapeCode.cs +++ b/src/api/Models/LayerGrainShapeCode.cs @@ -13,12 +13,12 @@ public class LayerGrainShapeCode : ILayerCode public int LayerId { get; set; } /// - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("grain_shape_id")] public int CodelistId { get; set; } /// - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerOrganicComponentCode.cs b/src/api/Models/LayerOrganicComponentCode.cs index 1abf403c6..00284d1cd 100644 --- a/src/api/Models/LayerOrganicComponentCode.cs +++ b/src/api/Models/LayerOrganicComponentCode.cs @@ -13,12 +13,12 @@ public class LayerOrganicComponentCode : ILayerCode public int LayerId { get; set; } /// - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("organic_components_id")] public int CodelistId { get; set; } /// - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } diff --git a/src/api/Models/LayerUscs3Code.cs b/src/api/Models/LayerUscs3Code.cs index 891497e0b..9bad5b8a1 100644 --- a/src/api/Models/LayerUscs3Code.cs +++ b/src/api/Models/LayerUscs3Code.cs @@ -13,12 +13,12 @@ public class LayerUscs3Code : ILayerCode public int LayerId { get; set; } /// - public Layer Layer { get; set; } + public Layer? Layer { get; set; } /// [Column("uscs3_id")] public int CodelistId { get; set; } /// - public Codelist Codelist { get; set; } + public Codelist? Codelist { get; set; } } From 02f0938d3eb36bea08818876d7d962508ebf2b6f Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Tue, 3 Dec 2024 08:37:03 +0100 Subject: [PATCH 09/33] Fix float comparisation --- tests/api/Controllers/UploadControllerTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 06b64c7c2..30b37dead 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -230,7 +230,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert stratigraphy's lithological descriptions Assert.AreEqual(2, stratigraphy.LithologicalDescriptions.Count, "Stratigraphy.LithologicalDescriptions.Count"); - var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0); + var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0f); Assert.IsNotNull(lithologicalDescription.Created, "Created should not be null"); Assert.IsNotNull(lithologicalDescription.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(lithologicalDescription.Updated, "Updated should not be null"); @@ -244,7 +244,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert stratigraphy's facies descriptions Assert.AreEqual(2, stratigraphy.FaciesDescriptions.Count, "Stratigraphy.FaciesDescriptions.Count"); - var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0); + var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0f); Assert.IsNotNull(faciesDescription.Created, "Created should not be null"); Assert.IsNotNull(faciesDescription.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(faciesDescription.Updated, "Updated should not be null"); @@ -258,7 +258,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert stratigraphy's chronostratigraphy layers Assert.AreEqual(2, stratigraphy.ChronostratigraphyLayers.Count, "Stratigraphy.ChronostratigraphyLayers.Count"); - var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0); + var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0f); Assert.IsNotNull(chronostratigraphyLayer.Created, "Created should not be null"); Assert.IsNotNull(chronostratigraphyLayer.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(chronostratigraphyLayer.Updated, "Updated should not be null"); @@ -271,7 +271,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert stratigraphy's lithostratigraphy layers Assert.AreEqual(2, stratigraphy.LithostratigraphyLayers.Count, "Stratigraphy.LithostratigraphyLayers.Count"); - var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0); + var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0f); Assert.IsNotNull(lithostratigraphyLayer.Created, "Created should not be null"); Assert.IsNotNull(lithostratigraphyLayer.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(lithostratigraphyLayer.Updated, "Updated should not be null"); From 75d9b181a23f8b9ae9f57030ea3f510896ad0fff Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Tue, 3 Dec 2024 09:25:00 +0100 Subject: [PATCH 10/33] Update json import test data --- tests/api/Controllers/UploadControllerTest.cs | 20 +++---- tests/api/TestData/json_import_valid.json | 56 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 30b37dead..b8698de13 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -186,7 +186,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.IsNotNull(layer.UpdatedById, "UpdatedById should not be null"); Assert.IsNotNull(layer.Stratigraphy, "layer.Stratigraphy should not be null"); Assert.IsTrue(layer.IsUndefined, "IsUndefined should be true"); - Assert.AreEqual(0, layer.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, layer.FromDepth, "FromDepth"); Assert.AreEqual(10, layer.ToDepth, "ToDepth"); Assert.IsFalse(layer.IsLast, "IsLast should be false"); Assert.AreEqual(9002, layer.DescriptionQualityId, "DescriptionQualityId"); @@ -230,7 +230,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert stratigraphy's lithological descriptions Assert.AreEqual(2, stratigraphy.LithologicalDescriptions.Count, "Stratigraphy.LithologicalDescriptions.Count"); - var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0f); + var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0.1); Assert.IsNotNull(lithologicalDescription.Created, "Created should not be null"); Assert.IsNotNull(lithologicalDescription.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(lithologicalDescription.Updated, "Updated should not be null"); @@ -239,12 +239,12 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", lithologicalDescription.Description, "Description"); Assert.AreEqual(9005, lithologicalDescription.DescriptionQualityId, "DescriptionQualityId"); Assert.IsNull(lithologicalDescription.DescriptionQuality, "DescriptionQuality should be null"); - Assert.AreEqual(0, lithologicalDescription.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, lithologicalDescription.FromDepth, "FromDepth"); Assert.AreEqual(10, lithologicalDescription.ToDepth, "ToDepth"); // Assert stratigraphy's facies descriptions Assert.AreEqual(2, stratigraphy.FaciesDescriptions.Count, "Stratigraphy.FaciesDescriptions.Count"); - var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0f); + var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0.1); Assert.IsNotNull(faciesDescription.Created, "Created should not be null"); Assert.IsNotNull(faciesDescription.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(faciesDescription.Updated, "Updated should not be null"); @@ -253,12 +253,12 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", faciesDescription.Description, "Description"); Assert.AreEqual(9005, faciesDescription.DescriptionQualityId, "DescriptionQualityId"); Assert.IsNull(faciesDescription.DescriptionQuality, "DescriptionQuality should be null"); - Assert.AreEqual(0, faciesDescription.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, faciesDescription.FromDepth, "FromDepth"); Assert.AreEqual(10, faciesDescription.ToDepth, "ToDepth"); // Assert stratigraphy's chronostratigraphy layers Assert.AreEqual(2, stratigraphy.ChronostratigraphyLayers.Count, "Stratigraphy.ChronostratigraphyLayers.Count"); - var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0f); + var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0.1); Assert.IsNotNull(chronostratigraphyLayer.Created, "Created should not be null"); Assert.IsNotNull(chronostratigraphyLayer.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(chronostratigraphyLayer.Updated, "Updated should not be null"); @@ -266,12 +266,12 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.IsNotNull(chronostratigraphyLayer.Stratigraphy, "chronostratigraphyLayer.Stratigraphy should not be null"); Assert.AreEqual(15001134, chronostratigraphyLayer.ChronostratigraphyId, "ChronostratigraphyId"); Assert.IsNull(chronostratigraphyLayer.Chronostratigraphy, "Chronostratigraphy should be null"); - Assert.AreEqual(0, chronostratigraphyLayer.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, chronostratigraphyLayer.FromDepth, "FromDepth"); Assert.AreEqual(10, chronostratigraphyLayer.ToDepth, "ToDepth"); // Assert stratigraphy's lithostratigraphy layers Assert.AreEqual(2, stratigraphy.LithostratigraphyLayers.Count, "Stratigraphy.LithostratigraphyLayers.Count"); - var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0f); + var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0.1); Assert.IsNotNull(lithostratigraphyLayer.Created, "Created should not be null"); Assert.IsNotNull(lithostratigraphyLayer.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(lithostratigraphyLayer.Updated, "Updated should not be null"); @@ -279,7 +279,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.IsNotNull(lithostratigraphyLayer.Stratigraphy, "lithostratigraphyLayer.Stratigraphy should not be null"); Assert.AreEqual(15303501, lithostratigraphyLayer.LithostratigraphyId, "LithostratigraphyId"); Assert.IsNull(lithostratigraphyLayer.Lithostratigraphy, "lithostratigraphyLayer.Lithostratigraphy should not be null"); - Assert.AreEqual(0, lithostratigraphyLayer.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, lithostratigraphyLayer.FromDepth, "FromDepth"); Assert.AreEqual(10, lithostratigraphyLayer.ToDepth, "ToDepth"); // Assert borehole's completions @@ -397,7 +397,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert borehole's observations Assert.AreEqual(2, borehole.Observations.Count, "Observations.Count"); - var observation = borehole.Observations.First(x => x.FromDepthM == 1900); + var observation = borehole.Observations.First(x => x.FromDepthM == 1900.0); Assert.IsNotNull(observation.Created, "Created should not be null"); Assert.IsNotNull(observation.CreatedById, "CreatedById should not be null"); Assert.IsNotNull(observation.Updated, "Updated should not be null"); diff --git a/tests/api/TestData/json_import_valid.json b/tests/api/TestData/json_import_valid.json index 7c24bece2..4a91889a6 100644 --- a/tests/api/TestData/json_import_valid.json +++ b/tests/api/TestData/json_import_valid.json @@ -92,7 +92,7 @@ "updatedBy": null, "updated": "2021-12-03T15:41:06.161383Z", "isUndefined": true, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "isLast": false, "descriptionQualityId": 9002, @@ -290,7 +290,7 @@ "description": "Bouvet Island (Bouvetoya) Borders networks", "descriptionQualityId": 9005, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -324,7 +324,7 @@ "description": "Bouvet Island (Bouvetoya) Borders networks", "descriptionQualityId": 9005, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -355,7 +355,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-05-12T01:45:32.650546Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "chronostratigraphyId": 15001134, "chronostratigraphy": null @@ -387,7 +387,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-05-12T01:45:32.650546Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "lithostratigraphyId": 15303501, "lithostratigraphy": null @@ -437,7 +437,7 @@ "updatedBy": null, "updated": "2021-06-23T03:03:59.747165Z", "isUndefined": true, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "isLast": false, "descriptionQualityId": 9001, @@ -579,7 +579,7 @@ "description": "Malta Steel impactful", "descriptionQualityId": 9004, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -613,7 +613,7 @@ "description": "Malta Steel impactful", "descriptionQualityId": 9004, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -644,7 +644,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-12-06T20:35:26.56566Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "chronostratigraphyId": 15001128, "chronostratigraphy": null @@ -676,7 +676,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-12-06T20:35:26.56566Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "lithostratigraphyId": 15303363, "lithostratigraphy": null @@ -780,7 +780,7 @@ "id": 18000418, "casingId": 17000377, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000116, "kind": null, @@ -799,7 +799,7 @@ "id": 18000797, "casingId": 17000377, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000119, "kind": null, @@ -904,7 +904,7 @@ "id": 18000079, "casingId": 17000326, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000101, "kind": null, @@ -923,7 +923,7 @@ "id": 18000458, "casingId": 17000326, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000104, "kind": null, @@ -1264,7 +1264,7 @@ "updatedBy": null, "updated": "2021-12-03T15:41:06.161383Z", "isUndefined": true, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "isLast": false, "descriptionQualityId": 9002, @@ -1448,7 +1448,7 @@ "description": "Bouvet Island (Bouvetoya) Borders networks", "descriptionQualityId": 9005, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -1482,7 +1482,7 @@ "description": "Bouvet Island (Bouvetoya) Borders networks", "descriptionQualityId": 9005, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -1513,7 +1513,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-05-12T01:45:32.650546Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "chronostratigraphyId": 15001134, "chronostratigraphy": null @@ -1545,7 +1545,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-05-12T01:45:32.650546Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "lithostratigraphyId": 15303501, "lithostratigraphy": null @@ -1595,7 +1595,7 @@ "updatedBy": null, "updated": "2021-06-23T03:03:59.747165Z", "isUndefined": true, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "isLast": false, "descriptionQualityId": 9001, @@ -1737,7 +1737,7 @@ "description": "Malta Steel impactful", "descriptionQualityId": 9004, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -1771,7 +1771,7 @@ "description": "Malta Steel impactful", "descriptionQualityId": 9004, "descriptionQuality": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10 }, { @@ -1802,7 +1802,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-12-06T20:35:26.56566Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "chronostratigraphyId": 15001128, "chronostratigraphy": null @@ -1834,7 +1834,7 @@ "updatedById": 2, "updatedBy": null, "updated": "2021-12-06T20:35:26.56566Z", - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "lithostratigraphyId": 15303363, "lithostratigraphy": null @@ -1938,7 +1938,7 @@ "id": 18000418, "casingId": 17000377, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000116, "kind": null, @@ -1957,7 +1957,7 @@ "id": 18000797, "casingId": 17000377, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000119, "kind": null, @@ -2062,7 +2062,7 @@ "id": 18000079, "casingId": 17000326, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000101, "kind": null, @@ -2081,7 +2081,7 @@ "id": 18000458, "casingId": 17000326, "casing": null, - "fromDepth": 0, + "fromDepth": 0.1, "toDepth": 10, "kindId": 25000104, "kind": null, From cc7c31ced83c12e762f5fbd9fa7dce7e6a7489f6 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Tue, 3 Dec 2024 16:31:46 +0100 Subject: [PATCH 11/33] Create an extension method for IIdentifyable to recursively mark an object as new --- src/api/Models/IIdentifyableExtensions.cs | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/api/Models/IIdentifyableExtensions.cs diff --git a/src/api/Models/IIdentifyableExtensions.cs b/src/api/Models/IIdentifyableExtensions.cs new file mode 100644 index 000000000..96ca90520 --- /dev/null +++ b/src/api/Models/IIdentifyableExtensions.cs @@ -0,0 +1,54 @@ +using System.Collections; +using System.Reflection; + +namespace BDMS.Models; + +internal static class IIdentifyableExtensions +{ + /// + /// Sets the property of the object to 0. + /// + /// object. + public static void MarkAsNew(this IIdentifyable item) + { + item.Id = 0; + } + + /// + /// Sets the property of the objects in the collection to 0, and recursively sets the properties of nested collections of objects to zero. + /// + /// Collection of objects. + public static void MarkAsNew(this IEnumerable items) + { + foreach (var item in items) + { + SetIdToZeroRecursive(item); + } + } + + private static void SetIdToZeroRecursive(IIdentifyable item) + { + item.Id = 0; + var properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (var property in properties) + { + // Check if the property is a collection (excluding string) + if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)) + { + // Try to cast the property value to IEnumerable + var collection = property.GetValue(item) as IEnumerable; + if (collection != null) + { + foreach (var element in collection) + { + if (element is IIdentifyable identifyableElement) + { + SetIdToZeroRecursive(identifyableElement); + } + } + } + } + } + } +} From 3f68f07b18c7e7894310f0dcd0db4f64d162e57a Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Tue, 3 Dec 2024 16:32:38 +0100 Subject: [PATCH 12/33] Use mark as new extension method in controllers --- src/api/Controllers/BoreholeController.cs | 92 ++------------ src/api/Controllers/UploadController.cs | 115 +----------------- tests/api/Controllers/UploadControllerTest.cs | 2 +- 3 files changed, 17 insertions(+), 192 deletions(-) diff --git a/src/api/Controllers/BoreholeController.cs b/src/api/Controllers/BoreholeController.cs index 7741084bd..057c44af2 100644 --- a/src/api/Controllers/BoreholeController.cs +++ b/src/api/Controllers/BoreholeController.cs @@ -170,14 +170,17 @@ await Context.Entry(hydrotest) #pragma warning restore CS8603 } - // Set ids of copied entities to zero. Entities with an id of zero are added as new entities to the DB. - borehole.Id = 0; + borehole.MarkAsNew(); + borehole.Completions?.MarkAsNew(); + borehole.Sections?.MarkAsNew(); + borehole.Observations?.MarkAsNew(); + foreach (var stratigraphy in borehole.Stratigraphies) { - stratigraphy.Id = 0; + stratigraphy.MarkAsNew(); foreach (var layer in stratigraphy.Layers) { - layer.Id = 0; + layer.MarkAsNew(); layer.LayerColorCodes?.ResetLayerIds(); layer.LayerDebrisCodes?.ResetLayerIds(); layer.LayerGrainShapeCodes?.ResetLayerIds(); @@ -186,83 +189,10 @@ await Context.Entry(hydrotest) layer.LayerUscs3Codes?.ResetLayerIds(); } - foreach (var lithologicalDescription in stratigraphy.LithologicalDescriptions) - { - lithologicalDescription.Id = 0; - } - - foreach (var faciesDescription in stratigraphy.FaciesDescriptions) - { - faciesDescription.Id = 0; - } - - foreach (var chronostratigraphy in stratigraphy.ChronostratigraphyLayers) - { - chronostratigraphy.Id = 0; - } - - foreach (var lithostratigraphy in stratigraphy.LithostratigraphyLayers) - { - lithostratigraphy.Id = 0; - } - } - - foreach (var completion in borehole.Completions) - { - completion.Id = 0; - foreach (var casing in completion.Casings) - { - casing.Id = 0; - foreach (var casingElement in casing.CasingElements) - { - casingElement.Id = 0; - } - } - - foreach (var instrumentation in completion.Instrumentations) - { - instrumentation.Id = 0; - } - - foreach (var backfill in completion.Backfills) - { - backfill.Id = 0; - } - } - - foreach (var section in borehole.Sections) - { - section.Id = 0; - foreach (var sectionElement in section.SectionElements) - { - sectionElement.Id = 0; - } - } - - foreach (var observation in borehole.Observations) - { - observation.Id = 0; - if (observation is FieldMeasurement fieldMeasurement) - { - if (fieldMeasurement.FieldMeasurementResults != null) - { - foreach (var fieldMeasurementResult in fieldMeasurement.FieldMeasurementResults) - { - fieldMeasurementResult.Id = 0; - } - } - } - - if (observation is Hydrotest hydrotest) - { - if (hydrotest.HydrotestResults != null) - { - foreach (var hydrotestResult in hydrotest.HydrotestResults) - { - hydrotestResult.Id = 0; - } - } - } + stratigraphy.LithologicalDescriptions?.MarkAsNew(); + stratigraphy.FaciesDescriptions?.MarkAsNew(); + stratigraphy.ChronostratigraphyLayers?.MarkAsNew(); + stratigraphy.LithostratigraphyLayers?.MarkAsNew(); } foreach (var boreholeFile in borehole.BoreholeFiles) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 71f8e36ce..d38849bf2 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -109,119 +109,14 @@ public async Task> UploadJsonFile(int workgroupId, IFormFile f foreach (var borehole in boreholes) { + borehole.MarkAsNew(); borehole.WorkgroupId = workgroupId; - borehole.Id = 0; borehole.LockedById = null; - foreach (var strati in borehole.Stratigraphies) - { - strati.Id = 0; - strati.BoreholeId = 0; - strati.Borehole = borehole; - foreach (var lithology in strati.Layers) - { - lithology.Id = 0; - lithology.StratigraphyId = 0; - lithology.Stratigraphy = strati; - } - - foreach (var chronostratigraphyLayer in strati.ChronostratigraphyLayers) - { - chronostratigraphyLayer.Id = 0; - chronostratigraphyLayer.StratigraphyId = 0; - chronostratigraphyLayer.Stratigraphy = strati; - } - - foreach (var lithostratigraphyLayer in strati.LithostratigraphyLayers) - { - lithostratigraphyLayer.Id = 0; - lithostratigraphyLayer.StratigraphyId = 0; - lithostratigraphyLayer.Stratigraphy = strati; - } - - foreach (var lithologicalDescription in strati.LithologicalDescriptions) - { - lithologicalDescription.Id = 0; - lithologicalDescription.StratigraphyId = 0; - lithologicalDescription.Stratigraphy = strati; - } - - foreach (var faciesDescription in strati.FaciesDescriptions) - { - faciesDescription.Id = 0; - faciesDescription.StratigraphyId = 0; - faciesDescription.Stratigraphy = strati; - } - - foreach (var chronostratigraphyLayer in strati.ChronostratigraphyLayers) - { - chronostratigraphyLayer.Id = 0; - chronostratigraphyLayer.StratigraphyId = 0; - chronostratigraphyLayer.Stratigraphy = strati; - } - } - - foreach (var completion in borehole.Completions) - { - completion.Id = 0; - completion.BoreholeId = 0; - completion.Borehole = borehole; - foreach (var instrumentation in completion.Instrumentations) - { - instrumentation.Id = 0; - instrumentation.CompletionId = 0; - instrumentation.Completion = completion; - } - - foreach (var casing in completion.Casings) - { - casing.Id = 0; - casing.CompletionId = 0; - casing.Completion = completion; - - foreach (var casingElement in casing.CasingElements) - { - casingElement.Id = 0; - casingElement.CasingId = 0; - casingElement.Casing = casing; - } - } - - foreach (var backfill in completion.Backfills) - { - backfill.Id = 0; - backfill.CompletionId = 0; - backfill.Completion = completion; - } - - foreach (var instrumentation in completion.Instrumentations) - { - instrumentation.Id = 0; - instrumentation.CompletionId = 0; - instrumentation.Completion = completion; - } - } - - foreach (var section in borehole.Sections) - { - section.Id = 0; - section.BoreholeId = 0; - section.Borehole = borehole; - - foreach (var sectionElement in section.SectionElements) - { - sectionElement.Id = 0; - sectionElement.SectionId = 0; - sectionElement.Section = section; - } - } - - foreach (var observation in borehole.Observations) - { - observation.Id = 0; - observation.BoreholeId = 0; - observation.Borehole = borehole; - } + borehole?.Stratigraphies?.MarkAsNew(); + borehole?.Completions?.MarkAsNew(); + borehole?.Sections?.MarkAsNew(); + borehole?.Observations?.MarkAsNew(); borehole.Workflows.Clear(); borehole.Workflows.Add(new Workflow { Borehole = borehole, Role = Role.Editor, UserId = user.Id }); diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index b8698de13..1e9d90287 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -356,7 +356,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.IsNotNull(casingElement.Updated, "Updated should not be null"); Assert.IsNotNull(casingElement.UpdatedById, "UpdatedById should not be null"); Assert.IsNotNull(casingElement.Casing, "casingElement.Casing should not be null"); - Assert.AreEqual(0, casingElement.FromDepth, "FromDepth"); + Assert.AreEqual(0.1, casingElement.FromDepth, "FromDepth"); Assert.AreEqual(10, casingElement.ToDepth, "ToDepth"); Assert.AreEqual(25000116, casingElement.KindId, "KindId"); Assert.IsNull(casingElement.Kind, "Kind should be null"); From e977ad73d75ef6571b68dc3f1c92891bd057911d Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Wed, 4 Dec 2024 06:33:53 +0100 Subject: [PATCH 13/33] Replace hard coded assertations in upload tests --- tests/api/Controllers/UploadControllerTest.cs | 580 +++++++++--------- tests/api/Helpers.cs | 6 + 2 files changed, 297 insertions(+), 289 deletions(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 1e9d90287..f47472909 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using System.Globalization; using System.Security.Claims; using System.Text.RegularExpressions; using static BDMS.Helpers; @@ -100,332 +101,333 @@ public async Task UploadJsonWithValidJsonShouldSaveData() OkObjectResult okResult = (OkObjectResult)response.Result!; Assert.AreEqual(2, okResult.Value); - var borehole = GetBoreholesWithIncludes(context.Boreholes).ToList().Find(b => b.OriginalName == "PURPLETOLL"); - - // Assert borehole - Assert.IsNotNull(borehole.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(borehole.Created, "Created should not be null"); - Assert.IsNotNull(borehole.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(borehole.Updated, "Updated should not be null"); - Assert.IsNull(borehole.LockedById, "LockedById should be null"); - Assert.IsNull(borehole.Locked, "Locked should be null"); - Assert.AreEqual(1, borehole.WorkgroupId, "WorkgroupId"); - Assert.IsNotNull(borehole.Workgroup, "Workgroup should not be null"); - Assert.IsTrue(borehole.IsPublic, "IsPublic"); - Assert.IsNull(borehole.TypeId, "TypeId should be null"); - Assert.IsNull(borehole.Type, "Type should be null"); - Assert.AreEqual(2739000, borehole.LocationX, "LocationX"); - Assert.AreEqual(6, borehole.PrecisionLocationX, "PrecisionLocationX"); - Assert.AreEqual(1291100, borehole.LocationY, "LocationY"); - Assert.AreEqual(7, borehole.PrecisionLocationY, "PrecisionLocationY"); - Assert.AreEqual(610700, borehole.LocationXLV03, "LocationXLV03"); - Assert.AreEqual(4, borehole.PrecisionLocationXLV03, "PrecisionLocationXLV03"); - Assert.AreEqual(102500, borehole.LocationYLV03, "LocationYLV03"); - Assert.AreEqual(3, borehole.PrecisionLocationYLV03, "PrecisionLocationYLV03"); - Assert.AreEqual((ReferenceSystem)20104002, borehole.OriginalReferenceSystem, "OriginalReferenceSystem"); - Assert.AreEqual(3160.6575921925983, borehole.ElevationZ, "ElevationZ"); - Assert.AreEqual(20106001, borehole.HrsId, "HrsId"); - Assert.IsNull(borehole.Hrs, "Hrs should be null"); - Assert.AreEqual(567.0068294587577, borehole.TotalDepth, "TotalDepth"); - Assert.IsNull(borehole.RestrictionId, "RestrictionId should be null"); - Assert.IsNull(borehole.Restriction, "Restriction should be null"); - Assert.IsNull(borehole.RestrictionUntil, "RestrictionUntil should be null"); - Assert.IsFalse(borehole.NationalInterest, "NationalInterest"); - Assert.AreEqual("PURPLETOLL", borehole.OriginalName, "OriginalName"); - Assert.AreEqual("GREYGOAT", borehole.AlternateName, "AlternateName"); - Assert.IsNull(borehole.LocationPrecisionId, "LocationPrecisionId should be null"); - Assert.IsNull(borehole.LocationPrecision, "LocationPrecision should be null"); - Assert.AreEqual(20114002, borehole.ElevationPrecisionId, "ElevationPrecisionId"); - Assert.IsNull(borehole.ElevationPrecision, "ElevationPrecision should be null"); - Assert.AreEqual("Switchable explicit superstructure", borehole.ProjectName, "ProjectName"); - Assert.AreEqual("Montenegro", borehole.Country, "Country"); - Assert.AreEqual("Texas", borehole.Canton, "Canton"); - Assert.AreEqual("Lake Reecechester", borehole.Municipality, "Municipality"); - Assert.AreEqual(22103009, borehole.PurposeId, "PurposeId"); - Assert.IsNull(borehole.Purpose, "Purpose should be null"); - Assert.AreEqual(22104006, borehole.StatusId, "StatusId"); - Assert.IsNull(borehole.Status, "Status should be null"); - Assert.AreEqual(22108003, borehole.QtDepthId, "QtDepthId"); - Assert.IsNull(borehole.QtDepth, "QtDepth should be null"); - Assert.AreEqual(759.5479580385368, borehole.TopBedrockFreshMd, "TopBedrockFreshMd"); - Assert.AreEqual(1.338392690447342, borehole.TopBedrockWeatheredMd, "TopBedrockWeatheredMd"); - Assert.IsFalse(borehole.HasGroundwater, "HasGroundwater"); - Assert.AreEqual(borehole.Remarks, "This product works too well."); - Assert.AreEqual(15104543, borehole.LithologyTopBedrockId, "LithologyTopBedrockId"); - Assert.IsNull(borehole.LithologyTopBedrock, "LithologyTopBedrock should be null"); - Assert.AreEqual(15302037, borehole.LithostratigraphyId, "LithostratigraphyId"); - Assert.IsNull(borehole.Lithostratigraphy, "Lithostratigraphy should be null"); - Assert.AreEqual(15001060, borehole.ChronostratigraphyId, "ChronostratigraphyId"); - Assert.IsNull(borehole.Chronostratigraphy, "Chronostratigraphy should be null"); - Assert.AreEqual(899.1648284248844, borehole.ReferenceElevation, "ReferenceElevation"); - Assert.AreEqual(20114006, borehole.QtReferenceElevationId, "QtReferenceElevationId"); - Assert.IsNull(borehole.QtReferenceElevation, "QtReferenceElevation should be null"); - Assert.AreEqual(20117005, borehole.ReferenceElevationTypeId, "ReferenceElevationTypeId"); - Assert.IsNull(borehole.ReferenceElevationType, "ReferenceElevationType should be null"); - - // Assert stratigraphy - Assert.AreEqual(2, borehole.Stratigraphies.Count, "Stratigraphies.Count"); - var stratigraphy = borehole.Stratigraphies.First(); - Assert.IsNotNull(stratigraphy.Borehole, "stratigraphy.Borehole should not be null"); - Assert.IsTrue(stratigraphy.IsPrimary, "IsPrimary"); - Assert.IsNotNull(stratigraphy.Updated, "Updated should not be null"); - Assert.IsNotNull(stratigraphy.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(stratigraphy.Created, "Created should not be null"); - Assert.IsNotNull(stratigraphy.CreatedById, "CreatedById should not be null"); - Assert.AreEqual("Marjolaine Hegmann", stratigraphy.Name, "Name"); - Assert.AreEqual(9003, stratigraphy.QualityId, "QualityId"); - Assert.IsNull(stratigraphy.Quality, "Quality should be null"); - Assert.AreEqual("My co-worker Ali has one of these. He says it looks towering.", stratigraphy.Notes, "Notes"); - - // Assert stratigraphy's layers - Assert.AreEqual(2, stratigraphy.Layers.Count, "Stratigraphy.Layers.Count"); - var layer = stratigraphy.Layers.First(); - Assert.IsNotNull(layer.Created, "Created should not be null"); - Assert.IsNotNull(layer.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(layer.Updated, "Updated should not be null"); - Assert.IsNotNull(layer.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(layer.Stratigraphy, "layer.Stratigraphy should not be null"); - Assert.IsTrue(layer.IsUndefined, "IsUndefined should be true"); - Assert.AreEqual(0.1, layer.FromDepth, "FromDepth"); - Assert.AreEqual(10, layer.ToDepth, "ToDepth"); - Assert.IsFalse(layer.IsLast, "IsLast should be false"); - Assert.AreEqual(9002, layer.DescriptionQualityId, "DescriptionQualityId"); - Assert.IsNull(layer.DescriptionQuality, "DescriptionQuality should be null"); - Assert.AreEqual(15104888, layer.LithologyId, "LithologyId"); - Assert.IsNull(layer.Lithology, "Lithology should be null"); - Assert.AreEqual(21101003, layer.PlasticityId, "PlasticityId"); - Assert.IsNull(layer.Plasticity, "Plasticity should be null"); - Assert.AreEqual(21103003, layer.ConsistanceId, "ConsistanceId"); - Assert.IsNull(layer.Consistance, "Consistance should be null"); - Assert.IsNull(layer.AlterationId, "AlterationId should be null"); - Assert.IsNull(layer.Alteration, "Alteration should be null"); - Assert.AreEqual(21102003, layer.CompactnessId, "CompactnessId"); - Assert.IsNull(layer.Compactness, "Compactness should be null"); - Assert.AreEqual(21109002, layer.GrainSize1Id, "GrainSize1Id"); - Assert.IsNull(layer.GrainSize1, "GrainSize1 should be null"); - Assert.AreEqual(21109002, layer.GrainSize2Id, "GrainSize2Id"); - Assert.IsNull(layer.GrainSize2, "GrainSize2 should be null"); - Assert.AreEqual(21116003, layer.CohesionId, "CohesionId"); - Assert.IsNull(layer.Cohesion, "Cohesion should be null"); - Assert.AreEqual("synergistic", layer.OriginalUscs, "OriginalUscs"); - Assert.AreEqual(23107001, layer.UscsDeterminationId, "UscsDeterminationId"); - Assert.IsNull(layer.UscsDetermination, "UscsDetermination should be null"); - Assert.AreEqual("payment optical copy networks", layer.Notes, "Notes"); - Assert.AreEqual(15303008, layer.LithostratigraphyId, "LithostratigraphyId"); - Assert.IsNull(layer.Lithostratigraphy, "Lithostratigraphy should be null"); - Assert.AreEqual(21105004, layer.HumidityId, "HumidityId"); - Assert.IsNull(layer.Humidity, "Humidity should be null"); - Assert.IsTrue(layer.IsStriae, "IsStriae should be true"); - Assert.AreEqual(30000019, layer.GradationId, "GradationId"); - Assert.IsNull(layer.Gradation, "Gradation should be null"); - Assert.AreEqual(15104470, layer.LithologyTopBedrockId, "LithologyTopBedrockId"); - Assert.IsNull(layer.LithologyTopBedrock, "LithologyTopBedrock should be null"); - Assert.AreEqual("Handmade connect Data Progressive Danish Krone", layer.OriginalLithology, "OriginalLithology"); - Assert.IsNotNull(layer.LayerDebrisCodes, "LayerDebrisCodes should not be null"); - Assert.IsNotNull(layer.LayerGrainShapeCodes, "LayerGrainShapeCodes should not be null"); - Assert.IsNotNull(layer.LayerGrainAngularityCodes, "LayerGrainAngularityCodes should not be null"); - Assert.IsNotNull(layer.LayerOrganicComponentCodes, "LayerOrganicComponentCodes should not be null"); - Assert.IsNotNull(layer.LayerUscs3Codes, "LayerUscs3Codes should not be null"); - Assert.IsNotNull(layer.LayerColorCodes, "LayerColorCodes should not be null"); + var boreholes = await GetBoreholesWithIncludes(context.Boreholes).ToListAsync().ConfigureAwait(false); + + var borehole = boreholes.Find(b => b.OriginalName == "PURPLETOLL"); + + Assert.IsNotNull(borehole.CreatedById, nameof(Borehole.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(borehole.Created, nameof(Borehole.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(borehole.UpdatedById, nameof(Borehole.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(borehole.Updated, nameof(Borehole.Updated).ShouldNotBeNullMessage()); + Assert.IsNull(borehole.LockedById, nameof(Borehole.LockedById).ShouldBeNullMessage()); + Assert.IsNull(borehole.Locked, nameof(Borehole.Locked).ShouldBeNullMessage()); + Assert.AreEqual(1, borehole.WorkgroupId, nameof(Borehole.WorkgroupId)); + Assert.IsNotNull(borehole.Workgroup, nameof(Borehole.Workgroup).ShouldNotBeNullMessage()); + Assert.IsTrue(borehole.IsPublic, nameof(Borehole.IsPublic)); + Assert.IsNull(borehole.TypeId, nameof(Borehole.TypeId).ShouldBeNullMessage()); + Assert.IsNull(borehole.Type, nameof(Borehole.Type).ShouldBeNullMessage()); + Assert.AreEqual(2739000, borehole.LocationX, nameof(Borehole.LocationX)); + Assert.AreEqual(6, borehole.PrecisionLocationX, nameof(Borehole.PrecisionLocationX)); + Assert.AreEqual(1291100, borehole.LocationY, nameof(Borehole.LocationY)); + Assert.AreEqual(7, borehole.PrecisionLocationY, nameof(Borehole.PrecisionLocationY)); + Assert.AreEqual(610700, borehole.LocationXLV03, nameof(Borehole.LocationXLV03)); + Assert.AreEqual(4, borehole.PrecisionLocationXLV03, nameof(Borehole.PrecisionLocationXLV03)); + Assert.AreEqual(102500, borehole.LocationYLV03, nameof(Borehole.LocationYLV03)); + Assert.AreEqual(3, borehole.PrecisionLocationYLV03, nameof(Borehole.PrecisionLocationYLV03)); + Assert.AreEqual((ReferenceSystem)20104002, borehole.OriginalReferenceSystem, nameof(Borehole.OriginalReferenceSystem)); + Assert.AreEqual(3160.6575921925983, borehole.ElevationZ, nameof(Borehole.ElevationZ)); + Assert.AreEqual(20106001, borehole.HrsId, nameof(Borehole.HrsId)); + Assert.IsNull(borehole.Hrs, nameof(Borehole.Hrs).ShouldBeNullMessage()); + Assert.AreEqual(567.0068294587577, borehole.TotalDepth, nameof(Borehole.TotalDepth)); + Assert.IsNull(borehole.RestrictionId, nameof(Borehole.RestrictionId).ShouldBeNullMessage()); + Assert.IsNull(borehole.Restriction, nameof(Borehole.Restriction).ShouldBeNullMessage()); + Assert.IsNull(borehole.RestrictionUntil, nameof(Borehole.RestrictionUntil).ShouldBeNullMessage()); + Assert.IsFalse(borehole.NationalInterest, nameof(Borehole.NationalInterest)); + Assert.AreEqual("PURPLETOLL", borehole.OriginalName, nameof(Borehole.OriginalName)); + Assert.AreEqual("GREYGOAT", borehole.AlternateName, nameof(Borehole.AlternateName)); + Assert.IsNull(borehole.LocationPrecisionId, nameof(Borehole.LocationPrecisionId).ShouldBeNullMessage()); + Assert.IsNull(borehole.LocationPrecision, nameof(Borehole.LocationPrecision).ShouldBeNullMessage()); + Assert.AreEqual(20114002, borehole.ElevationPrecisionId, nameof(Borehole.ElevationPrecisionId)); + Assert.IsNull(borehole.ElevationPrecision, nameof(Borehole.ElevationPrecision).ShouldBeNullMessage()); + Assert.AreEqual("Switchable explicit superstructure", borehole.ProjectName, nameof(Borehole.ProjectName)); + Assert.AreEqual("Montenegro", borehole.Country, nameof(Borehole.Country)); + Assert.AreEqual("Texas", borehole.Canton, nameof(Borehole.Canton)); + Assert.AreEqual("Lake Reecechester", borehole.Municipality, nameof(Borehole.Municipality)); + Assert.AreEqual(22103009, borehole.PurposeId, nameof(Borehole.PurposeId)); + Assert.IsNull(borehole.Purpose, nameof(Borehole.Purpose).ShouldBeNullMessage()); + Assert.AreEqual(22104006, borehole.StatusId, nameof(Borehole.StatusId)); + Assert.IsNull(borehole.Status, nameof(Borehole.Status).ShouldBeNullMessage()); + Assert.AreEqual(22108003, borehole.QtDepthId, nameof(Borehole.QtDepthId)); + Assert.IsNull(borehole.QtDepth, nameof(Borehole.QtDepth).ShouldBeNullMessage()); + Assert.AreEqual(759.5479580385368, borehole.TopBedrockFreshMd, nameof(Borehole.TopBedrockFreshMd)); + Assert.AreEqual(1.338392690447342, borehole.TopBedrockWeatheredMd, nameof(Borehole.TopBedrockWeatheredMd)); + Assert.IsFalse(borehole.HasGroundwater, nameof(Borehole.HasGroundwater)); + Assert.AreEqual("This product works too well.", borehole.Remarks, nameof(Borehole.Remarks)); + Assert.AreEqual(15104543, borehole.LithologyTopBedrockId, nameof(Borehole.LithologyTopBedrockId)); + Assert.IsNull(borehole.LithologyTopBedrock, nameof(Borehole.LithologyTopBedrock).ShouldBeNullMessage()); + Assert.AreEqual(15302037, borehole.LithostratigraphyId, nameof(Borehole.LithostratigraphyId)); + Assert.IsNull(borehole.Lithostratigraphy, nameof(Borehole.Lithostratigraphy).ShouldBeNullMessage()); + Assert.AreEqual(15001060, borehole.ChronostratigraphyId, nameof(Borehole.ChronostratigraphyId)); + Assert.IsNull(borehole.Chronostratigraphy, nameof(Borehole.Chronostratigraphy).ShouldBeNullMessage()); + Assert.AreEqual(899.1648284248844, borehole.ReferenceElevation, nameof(Borehole.ReferenceElevation)); + Assert.AreEqual(20114006, borehole.QtReferenceElevationId, nameof(Borehole.QtReferenceElevationId)); + Assert.IsNull(borehole.QtReferenceElevation, nameof(Borehole.QtReferenceElevation).ShouldBeNullMessage()); + Assert.AreEqual(20117005, borehole.ReferenceElevationTypeId, nameof(Borehole.ReferenceElevationTypeId)); + Assert.IsNull(borehole.ReferenceElevationType, nameof(Borehole.ReferenceElevationType).ShouldBeNullMessage()); // Assert stratigraphy's lithological descriptions - Assert.AreEqual(2, stratigraphy.LithologicalDescriptions.Count, "Stratigraphy.LithologicalDescriptions.Count"); + Assert.AreEqual(2, borehole.Stratigraphies.Count, nameof(borehole.Stratigraphies.Count)); + var stratigraphy = borehole.Stratigraphies.First(); + Assert.IsNotNull(stratigraphy.Borehole, nameof(stratigraphy.Borehole).ShouldNotBeNullMessage()); + Assert.IsTrue(stratigraphy.IsPrimary, nameof(stratigraphy.IsPrimary)); + Assert.IsNotNull(stratigraphy.Updated, nameof(stratigraphy.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(stratigraphy.UpdatedById, nameof(stratigraphy.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(stratigraphy.Created, nameof(stratigraphy.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(stratigraphy.CreatedById, nameof(stratigraphy.CreatedById).ShouldNotBeNullMessage()); + Assert.AreEqual("Marjolaine Hegmann", stratigraphy.Name, nameof(stratigraphy.Name)); + Assert.AreEqual(9003, stratigraphy.QualityId, nameof(stratigraphy.QualityId)); + Assert.IsNull(stratigraphy.Quality, nameof(stratigraphy.Quality).ShouldBeNullMessage()); + Assert.AreEqual("My co-worker Ali has one of these. He says it looks towering.", stratigraphy.Notes, nameof(stratigraphy.Notes)); + + // Assert stratigraphy’s layers + Assert.AreEqual(2, stratigraphy.Layers.Count, nameof(stratigraphy.Layers.Count)); + var layer = stratigraphy.Layers.First(); + Assert.IsNotNull(layer.Created, nameof(layer.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.CreatedById, nameof(layer.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.Updated, nameof(layer.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.UpdatedById, nameof(layer.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.Stratigraphy, nameof(layer.Stratigraphy).ShouldNotBeNullMessage()); + Assert.IsTrue(layer.IsUndefined, nameof(layer.IsUndefined)); + Assert.AreEqual(0.1, layer.FromDepth, nameof(layer.FromDepth)); + Assert.AreEqual(10, layer.ToDepth, nameof(layer.ToDepth)); + Assert.IsFalse(layer.IsLast, nameof(layer.IsLast)); + Assert.AreEqual(9002, layer.DescriptionQualityId, nameof(layer.DescriptionQualityId)); + Assert.IsNull(layer.DescriptionQuality, nameof(layer.DescriptionQuality).ShouldBeNullMessage()); + Assert.AreEqual(15104888, layer.LithologyId, nameof(layer.LithologyId)); + Assert.IsNull(layer.Lithology, nameof(layer.Lithology).ShouldBeNullMessage()); + Assert.AreEqual(21101003, layer.PlasticityId, nameof(layer.PlasticityId)); + Assert.IsNull(layer.Plasticity, nameof(layer.Plasticity).ShouldBeNullMessage()); + Assert.AreEqual(21103003, layer.ConsistanceId, nameof(layer.ConsistanceId)); + Assert.IsNull(layer.Consistance, nameof(layer.Consistance).ShouldBeNullMessage()); + Assert.IsNull(layer.AlterationId, nameof(layer.AlterationId).ShouldBeNullMessage()); + Assert.IsNull(layer.Alteration, nameof(layer.Alteration).ShouldBeNullMessage()); + Assert.AreEqual(21102003, layer.CompactnessId, nameof(layer.CompactnessId)); + Assert.IsNull(layer.Compactness, nameof(layer.Compactness).ShouldBeNullMessage()); + Assert.AreEqual(21109002, layer.GrainSize1Id, nameof(layer.GrainSize1Id)); + Assert.IsNull(layer.GrainSize1, nameof(layer.GrainSize1).ShouldBeNullMessage()); + Assert.AreEqual(21109002, layer.GrainSize2Id, nameof(layer.GrainSize2Id)); + Assert.IsNull(layer.GrainSize2, nameof(layer.GrainSize2).ShouldBeNullMessage()); + Assert.AreEqual(21116003, layer.CohesionId, nameof(layer.CohesionId)); + Assert.IsNull(layer.Cohesion, nameof(layer.Cohesion).ShouldBeNullMessage()); + Assert.AreEqual("synergistic", layer.OriginalUscs, nameof(layer.OriginalUscs)); + Assert.AreEqual(23107001, layer.UscsDeterminationId, nameof(layer.UscsDeterminationId)); + Assert.IsNull(layer.UscsDetermination, nameof(layer.UscsDetermination).ShouldBeNullMessage()); + Assert.AreEqual("payment optical copy networks", layer.Notes, nameof(layer.Notes)); + Assert.AreEqual(15303008, layer.LithostratigraphyId, nameof(layer.LithostratigraphyId)); + Assert.IsNull(layer.Lithostratigraphy, nameof(layer.Lithostratigraphy).ShouldBeNullMessage()); + Assert.AreEqual(21105004, layer.HumidityId, nameof(layer.HumidityId)); + Assert.IsNull(layer.Humidity, nameof(layer.Humidity).ShouldBeNullMessage()); + Assert.IsTrue(layer.IsStriae, nameof(layer.IsStriae)); + Assert.AreEqual(30000019, layer.GradationId, nameof(layer.GradationId)); + Assert.IsNull(layer.Gradation, nameof(layer.Gradation).ShouldBeNullMessage()); + Assert.AreEqual(15104470, layer.LithologyTopBedrockId, nameof(layer.LithologyTopBedrockId)); + Assert.IsNull(layer.LithologyTopBedrock, nameof(layer.LithologyTopBedrock).ShouldBeNullMessage()); + Assert.AreEqual("Handmade connect Data Progressive Danish Krone", layer.OriginalLithology, nameof(layer.OriginalLithology)); + Assert.IsNotNull(layer.LayerDebrisCodes, nameof(layer.LayerDebrisCodes).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.LayerGrainShapeCodes, nameof(layer.LayerGrainShapeCodes).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.LayerGrainAngularityCodes, nameof(layer.LayerGrainAngularityCodes).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.LayerOrganicComponentCodes, nameof(layer.LayerOrganicComponentCodes).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.LayerUscs3Codes, nameof(layer.LayerUscs3Codes).ShouldNotBeNullMessage()); + Assert.IsNotNull(layer.LayerColorCodes, nameof(layer.LayerColorCodes).ShouldNotBeNullMessage()); + + // Assert stratigraphy’s lithological descriptions + Assert.AreEqual(2, stratigraphy.LithologicalDescriptions.Count, nameof(stratigraphy.LithologicalDescriptions.Count)); var lithologicalDescription = stratigraphy.LithologicalDescriptions.First(x => x.FromDepth == 0.1); - Assert.IsNotNull(lithologicalDescription.Created, "Created should not be null"); - Assert.IsNotNull(lithologicalDescription.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(lithologicalDescription.Updated, "Updated should not be null"); - Assert.IsNotNull(lithologicalDescription.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(lithologicalDescription.Stratigraphy, "lithologicalDescription.Stratigraphy should not be null"); - Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", lithologicalDescription.Description, "Description"); - Assert.AreEqual(9005, lithologicalDescription.DescriptionQualityId, "DescriptionQualityId"); - Assert.IsNull(lithologicalDescription.DescriptionQuality, "DescriptionQuality should be null"); - Assert.AreEqual(0.1, lithologicalDescription.FromDepth, "FromDepth"); - Assert.AreEqual(10, lithologicalDescription.ToDepth, "ToDepth"); - - // Assert stratigraphy's facies descriptions - Assert.AreEqual(2, stratigraphy.FaciesDescriptions.Count, "Stratigraphy.FaciesDescriptions.Count"); + Assert.IsNotNull(lithologicalDescription.Created, nameof(lithologicalDescription.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithologicalDescription.CreatedById, nameof(lithologicalDescription.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithologicalDescription.Updated, nameof(lithologicalDescription.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithologicalDescription.UpdatedById, nameof(lithologicalDescription.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithologicalDescription.Stratigraphy, nameof(lithologicalDescription.Stratigraphy).ShouldNotBeNullMessage()); + Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", lithologicalDescription.Description, nameof(lithologicalDescription.Description)); + Assert.AreEqual(9005, lithologicalDescription.DescriptionQualityId, nameof(lithologicalDescription.DescriptionQualityId)); + Assert.IsNull(lithologicalDescription.DescriptionQuality, nameof(lithologicalDescription.DescriptionQuality).ShouldBeNullMessage()); + Assert.AreEqual(0.1, lithologicalDescription.FromDepth, nameof(lithologicalDescription.FromDepth)); + Assert.AreEqual(10, lithologicalDescription.ToDepth, nameof(lithologicalDescription.ToDepth)); + + // Assert stratigraphy’s facies descriptions + Assert.AreEqual(2, stratigraphy.FaciesDescriptions.Count, nameof(stratigraphy.FaciesDescriptions.Count)); var faciesDescription = stratigraphy.FaciesDescriptions.First(x => x.FromDepth == 0.1); - Assert.IsNotNull(faciesDescription.Created, "Created should not be null"); - Assert.IsNotNull(faciesDescription.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(faciesDescription.Updated, "Updated should not be null"); - Assert.IsNotNull(faciesDescription.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(faciesDescription.Stratigraphy, "faciesDescription.Stratigraphy should not be null"); - Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", faciesDescription.Description, "Description"); - Assert.AreEqual(9005, faciesDescription.DescriptionQualityId, "DescriptionQualityId"); - Assert.IsNull(faciesDescription.DescriptionQuality, "DescriptionQuality should be null"); - Assert.AreEqual(0.1, faciesDescription.FromDepth, "FromDepth"); - Assert.AreEqual(10, faciesDescription.ToDepth, "ToDepth"); + Assert.IsNotNull(faciesDescription.Created, nameof(faciesDescription.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(faciesDescription.CreatedById, nameof(faciesDescription.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(faciesDescription.Updated, nameof(faciesDescription.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(faciesDescription.UpdatedById, nameof(faciesDescription.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(faciesDescription.Stratigraphy, nameof(faciesDescription.Stratigraphy).ShouldNotBeNullMessage()); + Assert.AreEqual("Bouvet Island (Bouvetoya) Borders networks", faciesDescription.Description, nameof(faciesDescription.Description)); + Assert.AreEqual(9005, faciesDescription.DescriptionQualityId, nameof(faciesDescription.DescriptionQualityId)); + Assert.IsNull(faciesDescription.DescriptionQuality, nameof(faciesDescription.DescriptionQuality).ShouldBeNullMessage()); + Assert.AreEqual(0.1, faciesDescription.FromDepth, nameof(faciesDescription.FromDepth)); + Assert.AreEqual(10, faciesDescription.ToDepth, nameof(faciesDescription.ToDepth)); // Assert stratigraphy's chronostratigraphy layers - Assert.AreEqual(2, stratigraphy.ChronostratigraphyLayers.Count, "Stratigraphy.ChronostratigraphyLayers.Count"); + Assert.AreEqual(2, stratigraphy.ChronostratigraphyLayers.Count, nameof(stratigraphy.ChronostratigraphyLayers.Count)); var chronostratigraphyLayer = stratigraphy.ChronostratigraphyLayers.First(x => x.FromDepth == 0.1); - Assert.IsNotNull(chronostratigraphyLayer.Created, "Created should not be null"); - Assert.IsNotNull(chronostratigraphyLayer.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(chronostratigraphyLayer.Updated, "Updated should not be null"); - Assert.IsNotNull(chronostratigraphyLayer.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(chronostratigraphyLayer.Stratigraphy, "chronostratigraphyLayer.Stratigraphy should not be null"); - Assert.AreEqual(15001134, chronostratigraphyLayer.ChronostratigraphyId, "ChronostratigraphyId"); - Assert.IsNull(chronostratigraphyLayer.Chronostratigraphy, "Chronostratigraphy should be null"); - Assert.AreEqual(0.1, chronostratigraphyLayer.FromDepth, "FromDepth"); - Assert.AreEqual(10, chronostratigraphyLayer.ToDepth, "ToDepth"); + Assert.IsNotNull(chronostratigraphyLayer.Created, nameof(chronostratigraphyLayer.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(chronostratigraphyLayer.CreatedById, nameof(chronostratigraphyLayer.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(chronostratigraphyLayer.Updated, nameof(chronostratigraphyLayer.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(chronostratigraphyLayer.UpdatedById, nameof(chronostratigraphyLayer.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(chronostratigraphyLayer.Stratigraphy, nameof(chronostratigraphyLayer.Stratigraphy).ShouldNotBeNullMessage()); + Assert.AreEqual(15001134, chronostratigraphyLayer.ChronostratigraphyId, nameof(chronostratigraphyLayer.ChronostratigraphyId)); + Assert.IsNull(chronostratigraphyLayer.Chronostratigraphy, nameof(chronostratigraphyLayer.Chronostratigraphy).ShouldBeNullMessage()); + Assert.AreEqual(0.1, chronostratigraphyLayer.FromDepth, nameof(chronostratigraphyLayer.FromDepth)); + Assert.AreEqual(10, chronostratigraphyLayer.ToDepth, nameof(chronostratigraphyLayer.ToDepth)); // Assert stratigraphy's lithostratigraphy layers - Assert.AreEqual(2, stratigraphy.LithostratigraphyLayers.Count, "Stratigraphy.LithostratigraphyLayers.Count"); + Assert.AreEqual(2, stratigraphy.LithostratigraphyLayers.Count, nameof(stratigraphy.LithostratigraphyLayers.Count)); var lithostratigraphyLayer = stratigraphy.LithostratigraphyLayers.First(x => x.FromDepth == 0.1); - Assert.IsNotNull(lithostratigraphyLayer.Created, "Created should not be null"); - Assert.IsNotNull(lithostratigraphyLayer.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(lithostratigraphyLayer.Updated, "Updated should not be null"); - Assert.IsNotNull(lithostratigraphyLayer.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(lithostratigraphyLayer.Stratigraphy, "lithostratigraphyLayer.Stratigraphy should not be null"); - Assert.AreEqual(15303501, lithostratigraphyLayer.LithostratigraphyId, "LithostratigraphyId"); - Assert.IsNull(lithostratigraphyLayer.Lithostratigraphy, "lithostratigraphyLayer.Lithostratigraphy should not be null"); - Assert.AreEqual(0.1, lithostratigraphyLayer.FromDepth, "FromDepth"); - Assert.AreEqual(10, lithostratigraphyLayer.ToDepth, "ToDepth"); + Assert.IsNotNull(lithostratigraphyLayer.Created, nameof(lithostratigraphyLayer.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithostratigraphyLayer.CreatedById, nameof(lithostratigraphyLayer.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithostratigraphyLayer.Updated, nameof(lithostratigraphyLayer.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithostratigraphyLayer.UpdatedById, nameof(lithostratigraphyLayer.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(lithostratigraphyLayer.Stratigraphy, nameof(lithostratigraphyLayer.Stratigraphy).ShouldNotBeNullMessage()); + Assert.AreEqual(15303501, lithostratigraphyLayer.LithostratigraphyId, nameof(lithostratigraphyLayer.LithostratigraphyId)); + Assert.IsNull(lithostratigraphyLayer.Lithostratigraphy, nameof(lithostratigraphyLayer.Lithostratigraphy).ShouldBeNullMessage()); + Assert.AreEqual(0.1, lithostratigraphyLayer.FromDepth, nameof(lithostratigraphyLayer.FromDepth)); + Assert.AreEqual(10, lithostratigraphyLayer.ToDepth, nameof(lithostratigraphyLayer.ToDepth)); // Assert borehole's completions - Assert.AreEqual(2, borehole.Completions.Count, "Completions.Count"); + Assert.AreEqual(2, borehole.Completions.Count, nameof(borehole.Completions.Count)); var completion = borehole.Completions.First(); - Assert.IsNotNull(completion.Created, "Created should not be null"); - Assert.IsNotNull(completion.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(completion.Updated, "Updated should not be null"); - Assert.IsNotNull(completion.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(completion.Borehole, "completion.Borehole should not be null"); - Assert.AreEqual("Handcrafted Rubber Chair", completion.Name, "Name"); - Assert.AreEqual(16000000, completion.KindId, "KindId"); - Assert.IsNull(completion.Kind, "Kind should be null"); - Assert.AreEqual("Ratione ut non in recusandae labore.", completion.Notes, "Notes"); - Assert.AreEqual(DateOnly.Parse("2021-01-24"), completion.AbandonDate, "AbandonDate"); + Assert.IsNotNull(completion.Created, nameof(completion.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(completion.CreatedById, nameof(completion.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(completion.Updated, nameof(completion.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(completion.UpdatedById, nameof(completion.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(completion.Borehole, nameof(completion.Borehole).ShouldNotBeNullMessage()); + Assert.AreEqual("Handcrafted Rubber Chair", completion.Name, nameof(completion.Name)); + Assert.AreEqual(16000000, completion.KindId, nameof(completion.KindId)); + Assert.IsNull(completion.Kind, nameof(completion.Kind).ShouldBeNullMessage()); + Assert.AreEqual("Ratione ut non in recusandae labore.", completion.Notes, nameof(completion.Notes)); + Assert.AreEqual(DateOnly.Parse("2021-01-24", CultureInfo.InvariantCulture), completion.AbandonDate, nameof(completion.AbandonDate)); // Assert completion's instrumentations - Assert.AreEqual(1, completion.Instrumentations.Count, "Instrumentations.Count"); + Assert.AreEqual(1, completion.Instrumentations.Count, nameof(completion.Instrumentations.Count)); var instrumentation = completion.Instrumentations.First(); - Assert.IsNotNull(instrumentation.Created, "Created should not be null"); - Assert.IsNotNull(instrumentation.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(instrumentation.Updated, "Updated should not be null"); - Assert.IsNotNull(instrumentation.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(instrumentation.Completion, "instrumentation.Completion should be null"); - Assert.AreEqual(70, instrumentation.FromDepth, "FromDepth"); - Assert.AreEqual(80, instrumentation.ToDepth, "ToDepth"); - Assert.AreEqual("Explorer", instrumentation.Name, "Name"); - Assert.AreEqual(25000201, instrumentation.KindId, "KindId"); - Assert.IsNull(instrumentation.Kind, "Kind should be null"); - Assert.AreEqual(25000213, instrumentation.StatusId, "StatusId"); - Assert.IsNull(instrumentation.Status, "Status should be null"); - Assert.IsFalse(instrumentation.IsOpenBorehole, "IsOpenBorehole should be false"); - Assert.AreEqual(17000312, instrumentation.CasingId, "CasingId"); - Assert.IsNotNull(instrumentation.Casing, "instrumentation.Casing should not be null"); - Assert.AreEqual("copy Field bandwidth Burg", instrumentation.Notes, "Notes"); + Assert.IsNotNull(instrumentation.Created, nameof(instrumentation.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(instrumentation.CreatedById, nameof(instrumentation.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(instrumentation.Updated, nameof(instrumentation.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(instrumentation.UpdatedById, nameof(instrumentation.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(instrumentation.Completion, nameof(instrumentation.Completion).ShouldNotBeNullMessage()); + Assert.AreEqual(70, instrumentation.FromDepth, nameof(instrumentation.FromDepth)); + Assert.AreEqual(80, instrumentation.ToDepth, nameof(instrumentation.ToDepth)); + Assert.AreEqual("Explorer", instrumentation.Name, nameof(instrumentation.Name)); + Assert.AreEqual(25000201, instrumentation.KindId, nameof(instrumentation.KindId)); + Assert.IsNull(instrumentation.Kind, nameof(instrumentation.Kind).ShouldBeNullMessage()); + Assert.AreEqual(25000213, instrumentation.StatusId, nameof(instrumentation.StatusId)); + Assert.IsNull(instrumentation.Status, nameof(instrumentation.Status).ShouldBeNullMessage()); + Assert.IsFalse(instrumentation.IsOpenBorehole, nameof(instrumentation.IsOpenBorehole)); + Assert.AreEqual(17000312, instrumentation.CasingId, nameof(instrumentation.CasingId)); + Assert.IsNotNull(instrumentation.Casing, nameof(instrumentation.Casing).ShouldNotBeNullMessage()); + Assert.AreEqual("copy Field bandwidth Burg", instrumentation.Notes, nameof(instrumentation.Notes)); // Assert completion's backfills - Assert.AreEqual(1, completion.Backfills.Count, "Backfills.Count"); + Assert.AreEqual(1, completion.Backfills.Count, nameof(completion.Backfills.Count)); var backfill = completion.Backfills.First(); - Assert.IsNotNull(backfill.Created, "Created should not be null"); - Assert.IsNotNull(backfill.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(backfill.Updated, "Updated should not be null"); - Assert.IsNotNull(backfill.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(backfill.Completion, "backfill.Completion should be null"); - Assert.AreEqual(70, backfill.FromDepth, "FromDepth"); - Assert.AreEqual(80, backfill.ToDepth, "ToDepth"); - Assert.AreEqual(25000300, backfill.KindId, "KindId"); - Assert.IsNull(backfill.Kind, "Kind should be null"); - Assert.AreEqual(25000306, backfill.MaterialId, "MaterialId"); - Assert.IsNull(backfill.Material, "Material should be null"); - Assert.IsFalse(backfill.IsOpenBorehole, "IsOpenBorehole should be false"); - Assert.AreEqual(17000011, backfill.CasingId, "CasingId"); - Assert.IsNotNull(backfill.Casing, "backfill.Casing should not be null"); - Assert.AreEqual("Licensed Plastic Soap Managed withdrawal Tools & Industrial", backfill.Notes, "Notes"); + Assert.IsNotNull(backfill.Created, nameof(backfill.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(backfill.CreatedById, nameof(backfill.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(backfill.Updated, nameof(backfill.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(backfill.UpdatedById, nameof(backfill.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(backfill.Completion, nameof(backfill.Completion).ShouldNotBeNullMessage()); + Assert.AreEqual(70, backfill.FromDepth, nameof(backfill.FromDepth)); + Assert.AreEqual(80, backfill.ToDepth, nameof(backfill.ToDepth)); + Assert.AreEqual(25000300, backfill.KindId, nameof(backfill.KindId)); + Assert.IsNull(backfill.Kind, nameof(backfill.Kind).ShouldBeNullMessage()); + Assert.AreEqual(25000306, backfill.MaterialId, nameof(backfill.MaterialId)); + Assert.IsNull(backfill.Material, nameof(backfill.Material).ShouldBeNullMessage()); + Assert.IsFalse(backfill.IsOpenBorehole, nameof(backfill.IsOpenBorehole)); + Assert.AreEqual(17000011, backfill.CasingId, nameof(backfill.CasingId)); + Assert.IsNotNull(backfill.Casing, nameof(backfill.Casing).ShouldNotBeNullMessage()); + Assert.AreEqual("Licensed Plastic Soap Managed withdrawal Tools & Industrial", backfill.Notes, nameof(backfill.Notes)); // Assert completion's casings - Assert.AreEqual(1, completion.Casings.Count, "Casings.Count"); + Assert.AreEqual(1, completion.Casings.Count, nameof(completion.Casings.Count)); var casing = completion.Casings.First(); - Assert.IsNotNull(casing.Created, "Created should not be null"); - Assert.IsNotNull(casing.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(casing.Updated, "Updated should not be null"); - Assert.IsNotNull(casing.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(casing.Completion, "casing.Completion should not be null"); - Assert.AreEqual("Rustic", casing.Name, "Name"); - Assert.AreEqual(DateOnly.Parse("2021-03-24"), casing.DateStart, "DateStart"); - Assert.AreEqual(DateOnly.Parse("2021-12-12"), casing.DateFinish, "DateFinish"); - Assert.AreEqual("matrices Managed withdrawal Tools & Industrial", casing.Notes, "Notes"); + Assert.IsNotNull(casing.Created, nameof(casing.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(casing.CreatedById, nameof(casing.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(casing.Updated, nameof(casing.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(casing.UpdatedById, nameof(casing.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(casing.Completion, nameof(casing.Completion).ShouldNotBeNullMessage()); + Assert.AreEqual("Rustic", casing.Name, nameof(casing.Name)); + Assert.AreEqual(DateOnly.Parse("2021-03-24", CultureInfo.InvariantCulture), casing.DateStart, nameof(casing.DateStart)); + Assert.AreEqual(DateOnly.Parse("2021-12-12", CultureInfo.InvariantCulture), casing.DateFinish, nameof(casing.DateFinish)); + Assert.AreEqual("matrices Managed withdrawal Tools & Industrial", casing.Notes, nameof(casing.Notes)); // Assert casing's casingelements - Assert.AreEqual(2, casing.CasingElements.Count, "CasingElements.Count"); + Assert.AreEqual(2, casing.CasingElements.Count, nameof(casing.CasingElements.Count)); var casingElement = casing.CasingElements.First(); - Assert.IsNotNull(casingElement.Created, "Created should not be null"); - Assert.IsNotNull(casingElement.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(casingElement.Updated, "Updated should not be null"); - Assert.IsNotNull(casingElement.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(casingElement.Casing, "casingElement.Casing should not be null"); - Assert.AreEqual(0.1, casingElement.FromDepth, "FromDepth"); - Assert.AreEqual(10, casingElement.ToDepth, "ToDepth"); - Assert.AreEqual(25000116, casingElement.KindId, "KindId"); - Assert.IsNull(casingElement.Kind, "Kind should be null"); - Assert.AreEqual(25000114, casingElement.MaterialId, "MaterialId"); - Assert.IsNull(casingElement.Material, "Material should be null"); - Assert.AreEqual(7.91766288360472, casingElement.InnerDiameter, "InnerDiameter"); - Assert.AreEqual(4.857009269696199, casingElement.OuterDiameter, "OuterDiameter"); + Assert.IsNotNull(casingElement.Created, nameof(casingElement.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(casingElement.CreatedById, nameof(casingElement.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(casingElement.Updated, nameof(casingElement.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(casingElement.UpdatedById, nameof(casingElement.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(casingElement.Casing, nameof(casingElement.Casing).ShouldNotBeNullMessage()); + Assert.AreEqual(0.1, casingElement.FromDepth, nameof(casingElement.FromDepth)); + Assert.AreEqual(10, casingElement.ToDepth, nameof(casingElement.ToDepth)); + Assert.AreEqual(25000116, casingElement.KindId, nameof(casingElement.KindId)); + Assert.IsNull(casingElement.Kind, nameof(casingElement.Kind).ShouldBeNullMessage()); + Assert.AreEqual(25000114, casingElement.MaterialId, nameof(casingElement.MaterialId)); + Assert.IsNull(casingElement.Material, nameof(casingElement.Material).ShouldBeNullMessage()); + Assert.AreEqual(7.91766288360472, casingElement.InnerDiameter, nameof(casingElement.InnerDiameter)); + Assert.AreEqual(4.857009269696199, casingElement.OuterDiameter, nameof(casingElement.OuterDiameter)); // Assert borehole's sections - Assert.AreEqual(2, borehole.Sections.Count, "Sections.Count"); + Assert.AreEqual(2, borehole.Sections.Count, nameof(borehole.Sections.Count)); var section = borehole.Sections.First(); - Assert.IsNotNull(section.Created, "Created should not be null"); - Assert.IsNotNull(section.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(section.Updated, "Updated should not be null"); - Assert.IsNotNull(section.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(section.Borehole, "section.Borehole should not be null"); - Assert.AreEqual("Gourde", section.Name, "Name"); + Assert.IsNotNull(section.Created, nameof(section.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(section.CreatedById, nameof(section.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(section.Updated, nameof(section.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(section.UpdatedById, nameof(section.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(section.Borehole, nameof(section.Borehole).ShouldNotBeNullMessage()); + Assert.AreEqual("Gourde", section.Name, nameof(section.Name)); // Assert section's sectionelements - Assert.AreEqual(2, section.SectionElements.Count, "SectionElements.Count"); + Assert.AreEqual(2, section.SectionElements.Count, nameof(section.SectionElements.Count)); var sectionElement = section.SectionElements.First(); - Assert.IsNotNull(sectionElement.Created, "Created should not be null"); - Assert.IsNotNull(sectionElement.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(sectionElement.Updated, "Updated should not be null"); - Assert.IsNotNull(sectionElement.UpdatedById, "UpdatedById should not be null"); - Assert.IsNotNull(sectionElement.Section, "sectionElement.Section should not be null"); - Assert.AreEqual(60, sectionElement.FromDepth, "FromDepth"); - Assert.AreEqual(143, sectionElement.ToDepth, "ToDepth"); - Assert.AreEqual(0, sectionElement.Order, "Order"); - Assert.AreEqual(22107004, sectionElement.DrillingMethodId, "DrillingMethodId"); - Assert.AreEqual(DateOnly.Parse("2021-04-06"), sectionElement.DrillingStartDate, "DrillingStartDate"); - Assert.AreEqual(DateOnly.Parse("2021-05-31"), sectionElement.DrillingEndDate, "DrillingEndDate"); - Assert.AreEqual(22102002, sectionElement.CuttingsId, "CuttingsId"); - Assert.AreEqual(8.990221083625322, sectionElement.DrillingDiameter, "DrillingDiameter"); - Assert.AreEqual(18.406672318655378, sectionElement.DrillingCoreDiameter, "DrillingCoreDiameter"); - Assert.AreEqual(22109003, sectionElement.DrillingMudTypeId, "DrillingMudTypeId"); - Assert.AreEqual(22109020, sectionElement.DrillingMudSubtypeId, "DrillingMudSubtypeId"); + Assert.IsNotNull(sectionElement.Created, nameof(sectionElement.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(sectionElement.CreatedById, nameof(sectionElement.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(sectionElement.Updated, nameof(sectionElement.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(sectionElement.UpdatedById, nameof(sectionElement.UpdatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(sectionElement.Section, nameof(sectionElement.Section).ShouldNotBeNullMessage()); + Assert.AreEqual(60, sectionElement.FromDepth, nameof(sectionElement.FromDepth)); + Assert.AreEqual(143, sectionElement.ToDepth, nameof(sectionElement.ToDepth)); + Assert.AreEqual(0, sectionElement.Order, nameof(sectionElement.Order)); + Assert.AreEqual(22107004, sectionElement.DrillingMethodId, nameof(sectionElement.DrillingMethodId)); + Assert.AreEqual(DateOnly.Parse("2021-04-06"), sectionElement.DrillingStartDate, nameof(sectionElement.DrillingStartDate)); + Assert.AreEqual(DateOnly.Parse("2021-05-31"), sectionElement.DrillingEndDate, nameof(sectionElement.DrillingEndDate)); + Assert.AreEqual(22102002, sectionElement.CuttingsId, nameof(sectionElement.CuttingsId)); + Assert.AreEqual(8.990221083625322, sectionElement.DrillingDiameter, nameof(sectionElement.DrillingDiameter)); + Assert.AreEqual(18.406672318655378, sectionElement.DrillingCoreDiameter, nameof(sectionElement.DrillingCoreDiameter)); + Assert.AreEqual(22109003, sectionElement.DrillingMudTypeId, nameof(sectionElement.DrillingMudTypeId)); + Assert.AreEqual(22109020, sectionElement.DrillingMudSubtypeId, nameof(sectionElement.DrillingMudSubtypeId)); // Assert borehole's observations - Assert.AreEqual(2, borehole.Observations.Count, "Observations.Count"); + Assert.AreEqual(2, borehole.Observations.Count, nameof(borehole.Observations.Count)); var observation = borehole.Observations.First(x => x.FromDepthM == 1900.0); - Assert.IsNotNull(observation.Created, "Created should not be null"); - Assert.IsNotNull(observation.CreatedById, "CreatedById should not be null"); - Assert.IsNotNull(observation.Updated, "Updated should not be null"); - Assert.IsNotNull(observation.UpdatedById, "UpdatedById should not be null"); - Assert.AreEqual((ObservationType)2, observation.Type, "Type"); - Assert.AreEqual(DateTime.Parse("2021-10-05T17:41:48.389173Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.StartTime, "StartTime"); - Assert.AreEqual(DateTime.Parse("2021-09-21T20:42:21.785577Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.EndTime, "EndTime"); - Assert.AreEqual(1380.508568643829, observation.Duration, "Duration"); - Assert.AreEqual(1900.0, observation.FromDepthM, "FromDepthM"); - Assert.AreEqual(2227.610979433456, observation.ToDepthM, "ToDepthM"); - Assert.AreEqual(3136.3928836828063, observation.FromDepthMasl, "FromDepthMasl"); - Assert.AreEqual(4047.543691819787, observation.ToDepthMasl, "ToDepthMasl"); - Assert.IsTrue(observation.IsOpenBorehole, "IsOpenBorehole"); - Assert.IsNotNull(observation.Casing, "observation.Casing should be null"); - Assert.AreEqual("Quis repellendus nihil et ipsam ut ad eius.", observation.Comment, "Comment"); - Assert.AreEqual(15203156, observation.ReliabilityId, "ReliabilityId"); - Assert.IsNull(observation.Reliability, "Reliability should be null"); - Assert.IsNotNull(observation.Borehole, "observation.Borehole should not be null"); + Assert.IsNotNull(observation.Created, nameof(observation.Created).ShouldNotBeNullMessage()); + Assert.IsNotNull(observation.CreatedById, nameof(observation.CreatedById).ShouldNotBeNullMessage()); + Assert.IsNotNull(observation.Updated, nameof(observation.Updated).ShouldNotBeNullMessage()); + Assert.IsNotNull(observation.UpdatedById, nameof(observation.UpdatedById).ShouldNotBeNullMessage()); + Assert.AreEqual((ObservationType)2, observation.Type, nameof(observation.Type)); + Assert.AreEqual(DateTime.Parse("2021-10-05T17:41:48.389173Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.StartTime, nameof(observation.StartTime)); + Assert.AreEqual(DateTime.Parse("2021-09-21T20:42:21.785577Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.EndTime, nameof(observation.EndTime)); + Assert.AreEqual(1380.508568643829, observation.Duration, nameof(observation.Duration)); + Assert.AreEqual(1900.0, observation.FromDepthM, nameof(observation.FromDepthM)); + Assert.AreEqual(2227.610979433456, observation.ToDepthM, nameof(observation.ToDepthM)); + Assert.AreEqual(3136.3928836828063, observation.FromDepthMasl, nameof(observation.FromDepthMasl)); + Assert.AreEqual(4047.543691819787, observation.ToDepthMasl, nameof(observation.ToDepthMasl)); + Assert.IsTrue(observation.IsOpenBorehole, nameof(observation.IsOpenBorehole)); + Assert.IsNotNull(observation.Casing, nameof(observation.Casing).ShouldNotBeNullMessage()); + Assert.AreEqual("Quis repellendus nihil et ipsam ut ad eius.", observation.Comment, nameof(observation.Comment)); + Assert.AreEqual(15203156, observation.ReliabilityId, nameof(observation.ReliabilityId)); + Assert.IsNull(observation.Reliability, nameof(observation.Reliability).ShouldBeNullMessage()); + Assert.IsNotNull(observation.Borehole, nameof(observation.Borehole).ShouldNotBeNullMessage()); // Assert borehole's workflows - Assert.AreEqual(1, borehole.Workflows.Count, "Workflows.Count"); + Assert.AreEqual(1, borehole.Workflows.Count, nameof(borehole.Workflows.Count)); var workflow = borehole.Workflows.First(); - Assert.IsNull(workflow.Started, "Started should be null"); - Assert.IsNull(workflow.Finished, "Finished should be null"); - Assert.IsNull(workflow.Notes, "Notes should be null"); - Assert.AreEqual(Role.Editor, workflow.Role, "Role"); - Assert.IsNotNull(workflow.User, "User should be null"); - Assert.IsNotNull(workflow.Borehole, "workflow.Borehole should not be null"); + Assert.IsNull(workflow.Started, nameof(workflow.Started).ShouldBeNullMessage()); + Assert.IsNull(workflow.Finished, nameof(workflow.Finished).ShouldBeNullMessage()); + Assert.IsNull(workflow.Notes, nameof(workflow.Notes).ShouldBeNullMessage()); + Assert.AreEqual(Role.Editor, workflow.Role, nameof(workflow.Role)); + Assert.IsNotNull(workflow.User, nameof(workflow.User).ShouldNotBeNullMessage()); + Assert.IsNotNull(workflow.Borehole, nameof(workflow.Borehole).ShouldNotBeNullMessage()); Assert.AreEqual(borehole.CreatedById, workflow.UserId); Assert.AreEqual(borehole.CreatedById, workflow.UserId); } diff --git a/tests/api/Helpers.cs b/tests/api/Helpers.cs index ac23f4e96..7bb06e167 100644 --- a/tests/api/Helpers.cs +++ b/tests/api/Helpers.cs @@ -181,4 +181,10 @@ internal static IQueryable GetLayersWithIncludes(IQueryable query) .Include(l => l.LayerOrganicComponentCodes) .Include(l => l.OrganicComponentCodelists); } + + internal static string ShouldBeNullMessage(this string propertyName) + => $"{propertyName} should be null."; + + internal static string ShouldNotBeNullMessage(this string propertyName) + => $"{propertyName} should not be null."; } From 5e0b15900403b1552cb71cf1561359a9c2a63e2b Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Wed, 4 Dec 2024 09:49:32 +0100 Subject: [PATCH 14/33] Remove unnecessary null checks --- src/api/Controllers/UploadController.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index d38849bf2..ce1c0ff55 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -113,10 +113,10 @@ public async Task> UploadJsonFile(int workgroupId, IFormFile f borehole.WorkgroupId = workgroupId; borehole.LockedById = null; - borehole?.Stratigraphies?.MarkAsNew(); - borehole?.Completions?.MarkAsNew(); - borehole?.Sections?.MarkAsNew(); - borehole?.Observations?.MarkAsNew(); + borehole.Stratigraphies?.MarkAsNew(); + borehole.Completions?.MarkAsNew(); + borehole.Sections?.MarkAsNew(); + borehole.Observations?.MarkAsNew(); borehole.Workflows.Clear(); borehole.Workflows.Add(new Workflow { Borehole = borehole, Role = Role.Editor, UserId = user.Id }); From c599440b2f9d44ff56de9953569e66cb4d2c10dc Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Wed, 4 Dec 2024 09:50:04 +0100 Subject: [PATCH 15/33] Provide format provider for date parse --- tests/api/Controllers/UploadControllerTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index f47472909..2e40e73f1 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -389,8 +389,8 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.AreEqual(143, sectionElement.ToDepth, nameof(sectionElement.ToDepth)); Assert.AreEqual(0, sectionElement.Order, nameof(sectionElement.Order)); Assert.AreEqual(22107004, sectionElement.DrillingMethodId, nameof(sectionElement.DrillingMethodId)); - Assert.AreEqual(DateOnly.Parse("2021-04-06"), sectionElement.DrillingStartDate, nameof(sectionElement.DrillingStartDate)); - Assert.AreEqual(DateOnly.Parse("2021-05-31"), sectionElement.DrillingEndDate, nameof(sectionElement.DrillingEndDate)); + Assert.AreEqual(DateOnly.Parse("2021-04-06", CultureInfo.InvariantCulture), sectionElement.DrillingStartDate, nameof(sectionElement.DrillingStartDate)); + Assert.AreEqual(DateOnly.Parse("2021-05-31", CultureInfo.InvariantCulture), sectionElement.DrillingEndDate, nameof(sectionElement.DrillingEndDate)); Assert.AreEqual(22102002, sectionElement.CuttingsId, nameof(sectionElement.CuttingsId)); Assert.AreEqual(8.990221083625322, sectionElement.DrillingDiameter, nameof(sectionElement.DrillingDiameter)); Assert.AreEqual(18.406672318655378, sectionElement.DrillingCoreDiameter, nameof(sectionElement.DrillingCoreDiameter)); @@ -405,8 +405,8 @@ public async Task UploadJsonWithValidJsonShouldSaveData() Assert.IsNotNull(observation.Updated, nameof(observation.Updated).ShouldNotBeNullMessage()); Assert.IsNotNull(observation.UpdatedById, nameof(observation.UpdatedById).ShouldNotBeNullMessage()); Assert.AreEqual((ObservationType)2, observation.Type, nameof(observation.Type)); - Assert.AreEqual(DateTime.Parse("2021-10-05T17:41:48.389173Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.StartTime, nameof(observation.StartTime)); - Assert.AreEqual(DateTime.Parse("2021-09-21T20:42:21.785577Z", null, System.Globalization.DateTimeStyles.AdjustToUniversal), observation.EndTime, nameof(observation.EndTime)); + Assert.AreEqual(DateTime.Parse("2021-10-05T17:41:48.389173Z", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal), observation.StartTime, nameof(observation.StartTime)); + Assert.AreEqual(DateTime.Parse("2021-09-21T20:42:21.785577Z", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal), observation.EndTime, nameof(observation.EndTime)); Assert.AreEqual(1380.508568643829, observation.Duration, nameof(observation.Duration)); Assert.AreEqual(1900.0, observation.FromDepthM, nameof(observation.FromDepthM)); Assert.AreEqual(2227.610979433456, observation.ToDepthM, nameof(observation.ToDepthM)); From 79c3543de1bb5e968098d50a6a46f2760906dfc7 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Wed, 4 Dec 2024 10:35:41 +0100 Subject: [PATCH 16/33] Reduce complexity of mark as new extension method --- src/api/Models/IIdentifyableExtensions.cs | 26 ++++++++++------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/api/Models/IIdentifyableExtensions.cs b/src/api/Models/IIdentifyableExtensions.cs index 96ca90520..bde053d66 100644 --- a/src/api/Models/IIdentifyableExtensions.cs +++ b/src/api/Models/IIdentifyableExtensions.cs @@ -28,25 +28,21 @@ public static void MarkAsNew(this IEnumerable items) private static void SetIdToZeroRecursive(IIdentifyable item) { - item.Id = 0; - var properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + item.MarkAsNew(); + + // Select all IEnumerable properties of the object that are not strings + var collectionProperties = item.GetType() + .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(property => typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)); - foreach (var property in properties) + foreach (var property in collectionProperties) { - // Check if the property is a collection (excluding string) - if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)) + // If the property value is an IEnumerable of IIdentifyable objects, process it recursively + if (property.GetValue(item) is IEnumerable collection) { - // Try to cast the property value to IEnumerable - var collection = property.GetValue(item) as IEnumerable; - if (collection != null) + foreach (var identifyableElement in collection.OfType()) { - foreach (var element in collection) - { - if (element is IIdentifyable identifyableElement) - { - SetIdToZeroRecursive(identifyableElement); - } - } + SetIdToZeroRecursive(identifyableElement); } } } From b8b19a0ba05baa49c3bfbc4c1e34478c39edb6d4 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Wed, 4 Dec 2024 10:37:33 +0100 Subject: [PATCH 17/33] Reduce complexity of borehole validation during upload --- src/api/Controllers/UploadController.cs | 125 ++++++++++++++---------- 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index ce1c0ff55..3513e9831 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -404,69 +404,90 @@ internal static int GetPrecision(IReaderRow row, string fieldName) private void ValidateBoreholeImports(int workgroupId, List boreholesFromFile, bool zeroBasedIndex, IList? attachments = null) { - // Get boreholes from db with same workgroupId as provided. + var prefix = zeroBasedIndex ? "Borehole" : "Row"; + + foreach (var borehole in boreholesFromFile.Select((value, index) => (value, index))) + { + var processingIndex = zeroBasedIndex ? borehole.index : borehole.index + 1; + var boreholeValue = borehole.value; + + ValidateBorehole(boreholeValue, boreholesFromFile, workgroupId, processingIndex, prefix, attachments); + } + } + + private void ValidateBorehole(BoreholeImport borehole, List boreholesFromFile, int workgroupId, int processingIndex, string prefix, IList? attachments) + { + ValidateRequiredFields(borehole, processingIndex, prefix); + ValidateDuplicateInFile(borehole, boreholesFromFile, processingIndex, prefix); + ValidateDuplicateInDb(borehole, workgroupId, processingIndex, prefix); + ValidateAttachments(borehole, attachments, processingIndex, prefix); + } + + private void ValidateRequiredFields(BoreholeImport borehole, int processingIndex, string prefix) + { + if (string.IsNullOrEmpty(borehole.OriginalName)) + { + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name")); + } + + if (borehole.LocationX == null && borehole.LocationXLV03 == null) + { + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x")); + } + + if (borehole.LocationY == null && borehole.LocationYLV03 == null) + { + ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y")); + } + } + + private void ValidateDuplicateInFile(BoreholeImport borehole, List boreholesFromFile, int processingIndex, string prefix) + { + if (boreholesFromFile.Any(b => + b.ImportId != borehole.ImportId && + CompareValuesWithTolerance(b.TotalDepth, borehole.TotalDepth, 0) && + CompareValuesWithTolerance(b.LocationX, borehole.LocationX, 2) && + CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2))) + { + ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); + } + } + + private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int processingIndex, string prefix) + { var boreholesFromDb = context.Boreholes .Where(b => b.WorkgroupId == workgroupId) .AsNoTracking() .Select(b => new { b.Id, b.TotalDepth, b.LocationX, b.LocationY, b.LocationXLV03, b.LocationYLV03 }) .ToList(); - // Iterate over provided boreholes, validate them, and create error messages when necessary. Use a non-zero based index for error message keys (e.g. 'Row1'). - foreach (var boreholeFromFile in boreholesFromFile.Select((value, index) => (value, index))) + if (boreholesFromDb.Any(b => + CompareValuesWithTolerance(b.TotalDepth, borehole.TotalDepth, 0) && + (CompareValuesWithTolerance(b.LocationX, borehole.LocationX, 2) || CompareValuesWithTolerance(b.LocationXLV03, borehole.LocationX, 2)) && + (CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2) || CompareValuesWithTolerance(b.LocationYLV03, borehole.LocationY, 2)))) { - var processingIndex = zeroBasedIndex ? boreholeFromFile.index : boreholeFromFile.index + 1; - var prefix = zeroBasedIndex ? "Borehole" : "Row"; - if (string.IsNullOrEmpty(boreholeFromFile.value.OriginalName)) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name")); - } - - if (boreholeFromFile.value.LocationX == null && boreholeFromFile.value.LocationXLV03 == null) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x")); - } - - if (boreholeFromFile.value.LocationY == null && boreholeFromFile.value.LocationYLV03 == null) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y")); - } + ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database."); + } + } - // Check if any borehole with same coordinates (in tolerance) and same total depth is duplicated in file - if (boreholesFromFile.Any(b => - b.ImportId != boreholeFromFile.value.ImportId && - CompareValuesWithTolerance(b.TotalDepth, boreholeFromFile.value.TotalDepth, 0) && - CompareValuesWithTolerance(b.LocationX, boreholeFromFile.value.LocationX, 2) && - CompareValuesWithTolerance(b.LocationY, boreholeFromFile.value.LocationY, 2))) - { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); - } + private void ValidateAttachments(BoreholeImport borehole, IList? attachments, int processingIndex, string prefix) + { + if (attachments == null || string.IsNullOrEmpty(borehole.Attachments)) + { + return; + } - // Check if borehole with same coordinates (in tolerance) and same total depth already exists in db. - if (boreholesFromDb.Any(b => - CompareValuesWithTolerance(b.TotalDepth, boreholeFromFile.value.TotalDepth, 0) && - (CompareValuesWithTolerance(b.LocationX, boreholeFromFile.value.LocationX, 2) || CompareValuesWithTolerance(b.LocationXLV03, boreholeFromFile.value.LocationX, 2)) && - (CompareValuesWithTolerance(b.LocationY, boreholeFromFile.value.LocationY, 2) || CompareValuesWithTolerance(b.LocationYLV03, boreholeFromFile.value.LocationY, 2)))) - { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database."); - } + var attachmentFileNamesToLink = borehole.Attachments + .Split(",") + .Select(s => s.Trim()) + .Where(s => !string.IsNullOrEmpty(s)) + .ToList(); - if (attachments != null && !string.IsNullOrEmpty(boreholeFromFile.value.Attachments)) + foreach (var attachmentFileNameToLink in attachmentFileNamesToLink) + { + if (!attachments.Any(a => a.FileName.Equals(attachmentFileNameToLink, StringComparison.OrdinalIgnoreCase))) { - // Checks if each file name in the comma separated string is present in the list of the attachments. - var attachmentFileNamesToLink = boreholeFromFile.value.Attachments? - .Split(",") - .Select(s => s.Replace(" ", "", StringComparison.OrdinalIgnoreCase)) - .Where(s => !string.IsNullOrEmpty(s)) - .ToList() - ?? new List(); - - foreach (var attachmentFileNameToLink in attachmentFileNamesToLink) - { - if (attachments?.Any(a => a.FileName.Equals(attachmentFileNameToLink, StringComparison.OrdinalIgnoreCase)) == false) - { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Attachment file '{attachmentFileNameToLink}' not found."); - } - } + ModelState.AddModelError($"{prefix}{processingIndex}", $"Attachment file '{attachmentFileNameToLink}' not found."); } } } From 01dd2201b6a3ab7bb3c6645c737d4cf7f3b765e1 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 06:26:50 +0100 Subject: [PATCH 18/33] Rename upload json action method --- src/api/Controllers/UploadController.cs | 2 +- tests/api/Controllers/UploadControllerTest.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 3513e9831..ac3e3b990 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -54,7 +54,7 @@ public UploadController(BdmsContext context, ILogger logger, L [Authorize(Policy = PolicyNames.Viewer)] [RequestSizeLimit(int.MaxValue)] [RequestFormLimits(MultipartBodyLengthLimit = MaxFileSize)] - public async Task> UploadJsonFile(int workgroupId, IFormFile file) + public async Task> UploadJsonFileAsync(int workgroupId, IFormFile file) { // Increase max allowed errors to be able to return more validation errors at once. ModelState.MaxAllowedErrors = 1000; diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 2e40e73f1..97ecda58d 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -83,7 +83,7 @@ public async Task UploadJsonWithSingleObjectInsteadOfArrayShouldReturnError() { var boreholeJsonFile = GetFormFileByExistingFile("json_import_single.json"); - ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); ActionResultAssert.IsBadRequest(response.Result); BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; @@ -95,7 +95,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() { var boreholeJsonFile = GetFormFileByExistingFile("json_import_valid.json"); - ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); ActionResultAssert.IsOk(response.Result); OkObjectResult okResult = (OkObjectResult)response.Result!; @@ -437,7 +437,7 @@ public async Task UploadJsonWithNoJsonFileShouldReturnError() { var boreholeJsonFile = GetFormFileByExistingFile("not_a_json_file.csv"); - ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); ActionResultAssert.IsBadRequest(response.Result); BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; @@ -449,7 +449,7 @@ public async Task UploadJsonWithDuplicateBoreholesByLocationShouldReturnError() { var boreholeJsonFile = GetFormFileByExistingFile("json_import_duplicated_by_location.json"); - ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); ObjectResult result = (ObjectResult)response.Result!; @@ -467,7 +467,7 @@ public async Task UploadJsonWithDuplicatesExistingBoreholeShouldReturnError() { var boreholeJsonFile = GetFormFileByExistingFile("json_import_duplicates_existing.json"); - ActionResult response = await controller.UploadJsonFile(workgroupId: 1, boreholeJsonFile); + ActionResult response = await controller.UploadJsonFileAsync(workgroupId: 1, boreholeJsonFile); Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); ObjectResult result = (ObjectResult)response.Result!; From 611d1485c39ceaa02794a05f4efb9972a90b5c9f Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 06:45:12 +0100 Subject: [PATCH 19/33] Change to single line if statements in upload controller --- src/api/Controllers/UploadController.cs | 31 ++++++------------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index ac3e3b990..8a94ca7c7 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -59,10 +59,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF // Increase max allowed errors to be able to return more validation errors at once. ModelState.MaxAllowedErrors = 1000; - if (file == null || file.Length == 0) - { - return BadRequest("No file uploaded."); - } + if (file == null || file.Length == 0) return BadRequest("No file uploaded."); if (!FileTypeChecker.IsJson(file)) return BadRequest("Invalid file type for borehole JSON."); @@ -83,10 +80,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF return BadRequest("The provided file is not a array of boreholes or is not a valid JSON format."); } - if (boreholes == null || boreholes.Count == 0) - { - return BadRequest("No boreholes found in file."); - } + if (boreholes == null || boreholes.Count == 0) return BadRequest("No boreholes found in file."); for (var i = 0; i < boreholes.Count; i++) { @@ -95,10 +89,8 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF ValidateBoreholeImports(workgroupId, boreholes, true); - if (!ModelState.IsValid) - { - return ValidationProblem(statusCode: (int)HttpStatusCode.BadRequest); - } + // If any validation error occured, return a bad request. + if (!ModelState.IsValid) return ValidationProblem(statusCode: (int)HttpStatusCode.BadRequest); var subjectId = HttpContext.GetUserSubjectId(); @@ -179,10 +171,7 @@ public async Task> UploadFileAsync(int workgroupId, IFormFile } // If any validation error occured, return a bad request. - if (!ModelState.IsValid) - { - return ValidationProblem(statusCode: (int)HttpStatusCode.BadRequest); - } + if (!ModelState.IsValid) return ValidationProblem(statusCode: (int)HttpStatusCode.BadRequest); var subjectId = HttpContext.GetUserSubjectId(); @@ -350,10 +339,7 @@ public async Task> UploadFileAsync(int workgroupId, IFormFile /// A list of integers parsed from the input string. internal List ParseIds(string ids) { - if (string.IsNullOrEmpty(ids)) - { - return new List(); - } + if (string.IsNullOrEmpty(ids)) return new List(); return ids .Split(',') @@ -472,10 +458,7 @@ private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int private void ValidateAttachments(BoreholeImport borehole, IList? attachments, int processingIndex, string prefix) { - if (attachments == null || string.IsNullOrEmpty(borehole.Attachments)) - { - return; - } + if (attachments == null || string.IsNullOrEmpty(borehole.Attachments)) return; var attachmentFileNamesToLink = borehole.Attachments .Split(",") From 053d5185b1c2f72dbb2f23c93e813c900e1f3ef2 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 06:47:08 +0100 Subject: [PATCH 20/33] Return the response on the same line --- src/api/Controllers/UploadController.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 8a94ca7c7..5fb07fcf5 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -115,9 +115,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF } await context.Boreholes.AddRangeAsync(boreholes).ConfigureAwait(false); - var result = await SaveChangesAsync(() => Ok(boreholes.Count)).ConfigureAwait(false); - - return result; + return await SaveChangesAsync(() => Ok(boreholes.Count)).ConfigureAwait(false); } catch (Exception ex) { @@ -459,7 +457,7 @@ private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int private void ValidateAttachments(BoreholeImport borehole, IList? attachments, int processingIndex, string prefix) { if (attachments == null || string.IsNullOrEmpty(borehole.Attachments)) return; - + var attachmentFileNamesToLink = borehole.Attachments .Split(",") .Select(s => s.Trim()) From 456929aa10a06c7bf87e96c56d2a8185a5d8c739 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 06:53:04 +0100 Subject: [PATCH 21/33] Optimize json content reading and deserialization in UploadJsonFileAsync --- src/api/Controllers/UploadController.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 5fb07fcf5..1f9b9a820 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -65,15 +65,12 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF try { - using var stream = file.OpenReadStream(); - using var reader = new StreamReader(stream); - var jsonContent = await reader.ReadToEndAsync().ConfigureAwait(false); - + using var reader = new StreamReader(file.OpenReadStream()); List? boreholes; try { - boreholes = JsonSerializer.Deserialize>(jsonContent, jsonImportOptions); + boreholes = JsonSerializer.Deserialize>(await reader.ReadToEndAsync().ConfigureAwait(false), jsonImportOptions); } catch (JsonException) { From d7503301c25cba4254bb90bd8306eb715b03a5c8 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 06:54:40 +0100 Subject: [PATCH 22/33] Fix typo --- src/api/Controllers/UploadController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 1f9b9a820..23f0545f3 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -74,7 +74,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF } catch (JsonException) { - return BadRequest("The provided file is not a array of boreholes or is not a valid JSON format."); + return BadRequest("The provided file is not an array of boreholes or is not a valid JSON format."); } if (boreholes == null || boreholes.Count == 0) return BadRequest("No boreholes found in file."); From 17f1ad7cd80a673937650fc3aa18f7a57bf63c1d Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 07:04:44 +0100 Subject: [PATCH 23/33] Add logging to upload json file method --- src/api/Controllers/UploadController.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 23f0545f3..85c36d204 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -59,6 +59,8 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF // Increase max allowed errors to be able to return more validation errors at once. ModelState.MaxAllowedErrors = 1000; + logger.LogInformation("Import boreholes json to workgroup with id <{WorkgroupId}>", workgroupId); + if (file == null || file.Length == 0) return BadRequest("No file uploaded."); if (!FileTypeChecker.IsJson(file)) return BadRequest("Invalid file type for borehole JSON."); @@ -72,8 +74,9 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF { boreholes = JsonSerializer.Deserialize>(await reader.ReadToEndAsync().ConfigureAwait(false), jsonImportOptions); } - catch (JsonException) + catch (JsonException ex) { + logger.LogError("Error while deserializing borehole json file: <{Error}>", ex); return BadRequest("The provided file is not an array of boreholes or is not a valid JSON format."); } @@ -116,7 +119,8 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF } catch (Exception ex) { - return StatusCode(500, $"Internal server error: {ex.Message}"); + logger.LogError("Error while importing borehole(s) to workgroup with id <{WorkgroupId}>: <{Error}>", workgroupId, ex); + return Problem("Error while importing borehole(s) via json file."); } } From d27a2c14e682c16e96414cd545c0fcfde3d3baef Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 07:51:19 +0100 Subject: [PATCH 24/33] Optimize duplicate detection in file by using count --- src/api/Controllers/UploadController.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 85c36d204..0ebaec29b 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -82,11 +82,6 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF if (boreholes == null || boreholes.Count == 0) return BadRequest("No boreholes found in file."); - for (var i = 0; i < boreholes.Count; i++) - { - boreholes[i].ImportId = i + 1; - } - ValidateBoreholeImports(workgroupId, boreholes, true); // If any validation error occured, return a bad request. @@ -428,11 +423,10 @@ private void ValidateRequiredFields(BoreholeImport borehole, int processingIndex private void ValidateDuplicateInFile(BoreholeImport borehole, List boreholesFromFile, int processingIndex, string prefix) { - if (boreholesFromFile.Any(b => - b.ImportId != borehole.ImportId && + if (boreholesFromFile.Count(b => CompareValuesWithTolerance(b.TotalDepth, borehole.TotalDepth, 0) && CompareValuesWithTolerance(b.LocationX, borehole.LocationX, 2) && - CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2))) + CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2)) > 1) { ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); } From 195a8ae486ff0d3468f5ec61489cd85c176509b0 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 09:39:50 +0100 Subject: [PATCH 25/33] Reduce complexity of borehole import validation methods --- src/api/Controllers/UploadController.cs | 100 +++++++----------- tests/api/Controllers/UploadControllerTest.cs | 4 +- 2 files changed, 42 insertions(+), 62 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 0ebaec29b..78bc52caa 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -382,57 +382,43 @@ internal static int GetPrecision(IReaderRow row, string fieldName) return 0; } - private void ValidateBoreholeImports(int workgroupId, List boreholesFromFile, bool zeroBasedIndex, IList? attachments = null) + private void ValidateBoreholeImports(int workgroupId, List boreholesFromFile, bool isJsonFile, IList? attachments = null) { - var prefix = zeroBasedIndex ? "Borehole" : "Row"; - foreach (var borehole in boreholesFromFile.Select((value, index) => (value, index))) { - var processingIndex = zeroBasedIndex ? borehole.index : borehole.index + 1; - var boreholeValue = borehole.value; - - ValidateBorehole(boreholeValue, boreholesFromFile, workgroupId, processingIndex, prefix, attachments); + ValidateBorehole(borehole.value, boreholesFromFile, workgroupId, borehole.index, isJsonFile, attachments); } } - private void ValidateBorehole(BoreholeImport borehole, List boreholesFromFile, int workgroupId, int processingIndex, string prefix, IList? attachments) + private void ValidateBorehole(BoreholeImport borehole, List boreholesFromFile, int workgroupId, int boreholeIndex, bool isJsonFile, IList? attachments) { - ValidateRequiredFields(borehole, processingIndex, prefix); - ValidateDuplicateInFile(borehole, boreholesFromFile, processingIndex, prefix); - ValidateDuplicateInDb(borehole, workgroupId, processingIndex, prefix); - ValidateAttachments(borehole, attachments, processingIndex, prefix); + ValidateRequiredFields(borehole, boreholeIndex, isJsonFile); + ValidateDuplicateInFile(borehole, boreholesFromFile, boreholeIndex, isJsonFile); + ValidateDuplicateInDb(borehole, workgroupId, boreholeIndex, isJsonFile); + ValidateAttachments(borehole, attachments, boreholeIndex, isJsonFile); } - private void ValidateRequiredFields(BoreholeImport borehole, int processingIndex, string prefix) + private void ValidateRequiredFields(BoreholeImport borehole, int processingIndex, bool isJsonFile) { - if (string.IsNullOrEmpty(borehole.OriginalName)) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name")); - } + if (string.IsNullOrEmpty(borehole.OriginalName)) AddValidationErrorToModelState(processingIndex, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "original_name"), isJsonFile); - if (borehole.LocationX == null && borehole.LocationXLV03 == null) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x")); - } + if (borehole.LocationX == null && borehole.LocationXLV03 == null) AddValidationErrorToModelState(processingIndex, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_x"), isJsonFile); - if (borehole.LocationY == null && borehole.LocationYLV03 == null) - { - ModelState.AddModelError($"{prefix}{processingIndex}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y")); - } + if (borehole.LocationY == null && borehole.LocationYLV03 == null) AddValidationErrorToModelState(processingIndex, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "location_y"), isJsonFile); } - private void ValidateDuplicateInFile(BoreholeImport borehole, List boreholesFromFile, int processingIndex, string prefix) + private void ValidateDuplicateInFile(BoreholeImport borehole, List boreholesFromFile, int processingIndex, bool isJsonFile) { if (boreholesFromFile.Count(b => CompareValuesWithTolerance(b.TotalDepth, borehole.TotalDepth, 0) && CompareValuesWithTolerance(b.LocationX, borehole.LocationX, 2) && CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2)) > 1) { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times."); + AddValidationErrorToModelState(processingIndex, $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} is provided multiple times.", isJsonFile); } } - private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int processingIndex, string prefix) + private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int processingIndex, bool isJsonFile) { var boreholesFromDb = context.Boreholes .Where(b => b.WorkgroupId == workgroupId) @@ -445,59 +431,45 @@ private void ValidateDuplicateInDb(BoreholeImport borehole, int workgroupId, int (CompareValuesWithTolerance(b.LocationX, borehole.LocationX, 2) || CompareValuesWithTolerance(b.LocationXLV03, borehole.LocationX, 2)) && (CompareValuesWithTolerance(b.LocationY, borehole.LocationY, 2) || CompareValuesWithTolerance(b.LocationYLV03, borehole.LocationY, 2)))) { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database."); + AddValidationErrorToModelState(processingIndex, $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database.", isJsonFile); } } - private void ValidateAttachments(BoreholeImport borehole, IList? attachments, int processingIndex, string prefix) + private void ValidateAttachments(BoreholeImport borehole, IList? attachments, int processingIndex, bool isJsonFile) { if (attachments == null || string.IsNullOrEmpty(borehole.Attachments)) return; - - var attachmentFileNamesToLink = borehole.Attachments + + var boreholeFileNames = borehole.Attachments .Split(",") .Select(s => s.Trim()) .Where(s => !string.IsNullOrEmpty(s)) .ToList(); - foreach (var attachmentFileNameToLink in attachmentFileNamesToLink) + foreach (var boreholeFileName in boreholeFileNames) { - if (!attachments.Any(a => a.FileName.Equals(attachmentFileNameToLink, StringComparison.OrdinalIgnoreCase))) + // Check if the name of any attached file matches the name of the borehole file + if (!attachments.Any(a => a.FileName.Equals(boreholeFileName, StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError($"{prefix}{processingIndex}", $"Attachment file '{attachmentFileNameToLink}' not found."); + AddValidationErrorToModelState(processingIndex, $"Attachment file '{boreholeFileName}' not found.", isJsonFile); } } } private void ValidateLithologyImports(List importIds, List lithologyImports) { - // Iterate over provided lithology imports, validate them, and create error messages when necessary. Use a non-zero based index for error message keys (e.g. 'Row1'). - foreach (var lithology in lithologyImports.Select((value, index) => (value, index: index + 1))) + // Iterate over provided lithology imports, validate them, and create error messages when necessary. + foreach (var lithology in lithologyImports.Select((value, index) => (value, index))) { - if (lithology.value.ImportId == 0) - { - ModelState.AddModelError($"Row{lithology.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "import_id")); - } + if (lithology.value.ImportId == 0) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "import_id"), false); - if (lithology.value.StratiImportId == 0) - { - ModelState.AddModelError($"Row{lithology.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "strati_import_id")); - } + if (lithology.value.StratiImportId == 0) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "strati_import_id"), false); - if (lithology.value.FromDepth == null) - { - ModelState.AddModelError($"Row{lithology.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "from_depth")); - } + if (lithology.value.FromDepth == null) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "from_depth"), false); - if (lithology.value.ToDepth == null) - { - ModelState.AddModelError($"Row{lithology.index}", string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "to_depth")); - } + if (lithology.value.ToDepth == null) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "to_depth"), false); // Check if all import ids exist in the list of provided import ids (from borehole import file) - if (!importIds.Contains(lithology.value.ImportId)) - { - ModelState.AddModelError($"Row{lithology.index}", $"Borehole with {nameof(LithologyImport.ImportId)} '{lithology.value.ImportId}' not found."); - } + if (!importIds.Contains(lithology.value.ImportId)) AddValidationErrorToModelState(lithology.index, $"Borehole with {nameof(LithologyImport.ImportId)} '{lithology.value.ImportId}' not found.", false); // Check if all multi code list values are numbers try @@ -506,7 +478,7 @@ private void ValidateLithologyImports(List importIds, List } catch { - ModelState.AddModelError($"Row{lithology.index}", $"One or more invalid (not a number) code list id in any of the following properties: {nameof(LithologyImport.ColorIds)}, {nameof(LithologyImport.OrganicComponentIds)}, {nameof(LithologyImport.GrainShapeIds)}, {nameof(LithologyImport.GrainGranularityIds)}, {nameof(LithologyImport.Uscs3Ids)}, {nameof(LithologyImport.DebrisIds)}."); + AddValidationErrorToModelState(lithology.index, $"One or more invalid (not a number) code list id in any of the following properties: {nameof(LithologyImport.ColorIds)}, {nameof(LithologyImport.OrganicComponentIds)}, {nameof(LithologyImport.GrainShapeIds)}, {nameof(LithologyImport.GrainGranularityIds)}, {nameof(LithologyImport.Uscs3Ids)}, {nameof(LithologyImport.DebrisIds)}.", false); } } @@ -522,13 +494,13 @@ private void ValidateLithologyImports(List importIds, List // Check if all records with the same strati import id have the same strati name. if (stratiGroup.Select(s => s.StratiName).Distinct().Count() > 1) { - ModelState.AddModelError($"Row{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiName)}."); + ModelState.AddModelError($"import_id{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiName)}."); } // Check if all records with the same strati import id have the same strati date. if (stratiGroup.Select(s => s.StratiDate).Distinct().Count() > 1) { - ModelState.AddModelError($"Row{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiDate)}."); + ModelState.AddModelError($"import_id{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiDate)}."); } } } @@ -583,6 +555,14 @@ private async Task UpdateBoreholeLocationAndCoordinates(Borehole borehole) } } + private void AddValidationErrorToModelState(int boreholeIndex, string errorMessage, bool isJsonFile) + { + // Use 'Borehole' as prefix and zero based index for json files, 'Row' as prefix and one based index for csv files. E.g. 'Borehole0' or 'Row1'. + var fileTypeBasedPrefix = isJsonFile ? "Borehole" : "Row"; + boreholeIndex = isJsonFile ? boreholeIndex : boreholeIndex + 1; + ModelState.AddModelError($"{fileTypeBasedPrefix}{boreholeIndex}", errorMessage); + } + private sealed class CsvImportBoreholeMap : ClassMap { private readonly CultureInfo swissCulture = new("de-CH"); diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index 97ecda58d..f038c73a2 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -87,7 +87,7 @@ public async Task UploadJsonWithSingleObjectInsteadOfArrayShouldReturnError() ActionResultAssert.IsBadRequest(response.Result); BadRequestObjectResult badRequestResult = (BadRequestObjectResult)response.Result!; - Assert.AreEqual("The provided file is not a array of boreholes or is not a valid JSON format.", badRequestResult.Value); + Assert.AreEqual("The provided file is not an array of boreholes or is not a valid JSON format.", badRequestResult.Value); } [TestMethod] @@ -1188,7 +1188,7 @@ public async Task UploadLithologyDiffInStratiAttributesForSameStratiIdShouldRetu $"Lithology with {nameof(LithologyImport.StratiImportId)} '1001' has various {nameof(LithologyImport.StratiName)}.", $"Lithology with {nameof(LithologyImport.StratiImportId)} '1001' has various {nameof(LithologyImport.StratiDate)}.", }, - problemDetails.Errors["Row1"]); + problemDetails.Errors["import_id1"]); } [TestMethod] From b20a7cf37f375641127b908f659d93f4b8e6111a Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 09:49:36 +0100 Subject: [PATCH 26/33] Add comment to added workflow --- src/api/Controllers/UploadController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 78bc52caa..8f604559f 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -105,8 +105,9 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF borehole.Sections?.MarkAsNew(); borehole.Observations?.MarkAsNew(); + // Do not import any workflows from the json file but add a new unfinished workflow for the current user. borehole.Workflows.Clear(); - borehole.Workflows.Add(new Workflow { Borehole = borehole, Role = Role.Editor, UserId = user.Id }); + borehole.Workflows.Add(new Workflow { Borehole = borehole, Role = Role.Editor, UserId = user.Id, Started = DateTime.Now.ToUniversalTime() }); } await context.Boreholes.AddRangeAsync(boreholes).ConfigureAwait(false); From 5374268e7b6e7d9c5aab3922c8bab62916c1cf7c Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 09:58:22 +0100 Subject: [PATCH 27/33] Improve comments and complexity of mark as new extension methods --- src/api/Models/IIdentifyableExtensions.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/api/Models/IIdentifyableExtensions.cs b/src/api/Models/IIdentifyableExtensions.cs index bde053d66..51ca72c97 100644 --- a/src/api/Models/IIdentifyableExtensions.cs +++ b/src/api/Models/IIdentifyableExtensions.cs @@ -6,16 +6,13 @@ namespace BDMS.Models; internal static class IIdentifyableExtensions { /// - /// Sets the property of the object to 0. + /// Sets the property of the object to 0. Entity Framework interprets this as a added object. /// /// object. - public static void MarkAsNew(this IIdentifyable item) - { - item.Id = 0; - } + public static void MarkAsNew(this IIdentifyable item) => item.Id = 0; /// - /// Sets the property of the objects in the collection to 0, and recursively sets the properties of nested collections of objects to zero. + /// Mark the objects in the collection as new, and recursively mark objects of nested collections as new. /// /// Collection of objects. public static void MarkAsNew(this IEnumerable items) From 6028fc21d71400e852d817dd1e652c403708afce Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 10:43:25 +0100 Subject: [PATCH 28/33] Update error logging in upload controller --- src/api/Controllers/UploadController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 8f604559f..0a1105705 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -76,7 +76,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF } catch (JsonException ex) { - logger.LogError("Error while deserializing borehole json file: <{Error}>", ex); + logger.LogError(ex, "Error while deserializing borehole json file."); return BadRequest("The provided file is not an array of boreholes or is not a valid JSON format."); } @@ -115,7 +115,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF } catch (Exception ex) { - logger.LogError("Error while importing borehole(s) to workgroup with id <{WorkgroupId}>: <{Error}>", workgroupId, ex); + logger.LogError(ex, "Error while importing borehole(s) to workgroup with id <{WorkgroupId}>", workgroupId); return Problem("Error while importing borehole(s) via json file."); } } @@ -322,7 +322,7 @@ public async Task> UploadFileAsync(int workgroupId, IFormFile } catch (Exception ex) { - logger.LogError("Error while importing borehole(s) to workgroup with id <{WorkgroupId}>: <{Error}>", workgroupId, ex); + logger.LogError(ex, "Error while importing borehole(s) to workgroup with id <{WorkgroupId}>.", workgroupId); return Problem("Error while importing borehole(s)."); } } From c66279c73a024292c773f802ba8909541939cff8 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 10:48:17 +0100 Subject: [PATCH 29/33] Fix test --- tests/api/Controllers/UploadControllerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index f038c73a2..dd2e1cd73 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -422,7 +422,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert borehole's workflows Assert.AreEqual(1, borehole.Workflows.Count, nameof(borehole.Workflows.Count)); var workflow = borehole.Workflows.First(); - Assert.IsNull(workflow.Started, nameof(workflow.Started).ShouldBeNullMessage()); + Assert.IsNull(workflow.Started, nameof(workflow.Started).ShouldNotBeNullMessage()); Assert.IsNull(workflow.Finished, nameof(workflow.Finished).ShouldBeNullMessage()); Assert.IsNull(workflow.Notes, nameof(workflow.Notes).ShouldBeNullMessage()); Assert.AreEqual(Role.Editor, workflow.Role, nameof(workflow.Role)); From 796339f454cdbda9974fd66f863c6104eb98e573 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Thu, 5 Dec 2024 11:05:15 +0100 Subject: [PATCH 30/33] Fix assert --- tests/api/Controllers/UploadControllerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index dd2e1cd73..8d662c492 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -422,7 +422,7 @@ public async Task UploadJsonWithValidJsonShouldSaveData() // Assert borehole's workflows Assert.AreEqual(1, borehole.Workflows.Count, nameof(borehole.Workflows.Count)); var workflow = borehole.Workflows.First(); - Assert.IsNull(workflow.Started, nameof(workflow.Started).ShouldNotBeNullMessage()); + Assert.IsNotNull(workflow.Started, nameof(workflow.Started).ShouldNotBeNullMessage()); Assert.IsNull(workflow.Finished, nameof(workflow.Finished).ShouldBeNullMessage()); Assert.IsNull(workflow.Notes, nameof(workflow.Notes).ShouldBeNullMessage()); Assert.AreEqual(Role.Editor, workflow.Role, nameof(workflow.Role)); From 4076c696c15cccfeccddcd71138cf5bf5c47f939 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Fri, 6 Dec 2024 07:44:06 +0100 Subject: [PATCH 31/33] Optimize json file deserialization --- src/api/Controllers/UploadController.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 0a1105705..e7390a82f 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -67,12 +67,11 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF try { - using var reader = new StreamReader(file.OpenReadStream()); List? boreholes; - try { - boreholes = JsonSerializer.Deserialize>(await reader.ReadToEndAsync().ConfigureAwait(false), jsonImportOptions); + using var stream = file.OpenReadStream(); + boreholes = JsonSerializer.Deserialize>(stream, jsonImportOptions); } catch (JsonException ex) { From eb9f4b74562415a0bda59984bdd6537faa5f50a9 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Fri, 6 Dec 2024 08:05:20 +0100 Subject: [PATCH 32/33] Use deserialize async method --- src/api/Controllers/UploadController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index e7390a82f..fa42d8da6 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -71,7 +71,7 @@ public async Task> UploadJsonFileAsync(int workgroupId, IFormF try { using var stream = file.OpenReadStream(); - boreholes = JsonSerializer.Deserialize>(stream, jsonImportOptions); + boreholes = await JsonSerializer.DeserializeAsync>(stream, jsonImportOptions).ConfigureAwait(false); } catch (JsonException ex) { From 9fe668ff5b9f24f5d13673f66a1cd981f1b4b2d7 Mon Sep 17 00:00:00 2001 From: Frederic Stahel Date: Mon, 16 Dec 2024 10:32:34 +0100 Subject: [PATCH 33/33] Clean up files --- src/api/Controllers/BoreholeController.cs | 61 +----- src/api/Controllers/UploadController.cs | 60 +----- tests/api/Controllers/UploadControllerTest.cs | 194 ------------------ tests/api/Helpers.cs | 8 + 4 files changed, 15 insertions(+), 308 deletions(-) diff --git a/src/api/Controllers/BoreholeController.cs b/src/api/Controllers/BoreholeController.cs index 9ad890cae..6dd349f2b 100644 --- a/src/api/Controllers/BoreholeController.cs +++ b/src/api/Controllers/BoreholeController.cs @@ -150,7 +150,6 @@ public async Task> CopyAsync([Required] int id, [Required] int borehole.MarkAsNew(); borehole.Completions?.MarkAsNew(); borehole.Sections?.MarkAsNew(); - borehole.Observations?.MarkAsNew(); foreach (var stratigraphy in borehole.Stratigraphies) { @@ -171,69 +170,17 @@ public async Task> CopyAsync([Required] int id, [Required] int stratigraphy.ChronostratigraphyLayers?.MarkAsNew(); stratigraphy.LithostratigraphyLayers?.MarkAsNew(); } - foreach (var lithologicalDescription in stratigraphy.LithologicalDescriptions) - { - lithologicalDescription.Id = 0; - } - - foreach (var faciesDescription in stratigraphy.FaciesDescriptions) - { - faciesDescription.Id = 0; - } - - foreach (var chronostratigraphy in stratigraphy.ChronostratigraphyLayers) - { - chronostratigraphy.Id = 0; - } - - foreach (var lithostratigraphy in stratigraphy.LithostratigraphyLayers) - { - lithostratigraphy.Id = 0; - } - } - - foreach (var completion in borehole.Completions) - { - completion.Id = 0; - foreach (var casing in completion.Casings) - { - casing.Id = 0; - foreach (var casingElement in casing.CasingElements) - { - casingElement.Id = 0; - } - } - - foreach (var instrumentation in completion.Instrumentations) - { - instrumentation.Id = 0; - } - - foreach (var backfill in completion.Backfills) - { - backfill.Id = 0; - } - } - - foreach (var section in borehole.Sections) - { - section.Id = 0; - foreach (var sectionElement in section.SectionElements) - { - sectionElement.Id = 0; - } - } foreach (var observation in borehole.Observations) { - observation.Id = 0; + observation.MarkAsNew(); if (observation is FieldMeasurement fieldMeasurement) { if (fieldMeasurement.FieldMeasurementResults != null) { foreach (var fieldMeasurementResult in fieldMeasurement.FieldMeasurementResults) { - fieldMeasurementResult.Id = 0; + fieldMeasurementResult.MarkAsNew(); } } } @@ -244,7 +191,7 @@ public async Task> CopyAsync([Required] int id, [Required] int { foreach (var hydrotestResult in hydrotest.HydrotestResults) { - hydrotestResult.Id = 0; + hydrotestResult.MarkAsNew(); } } @@ -279,7 +226,7 @@ public async Task> CopyAsync([Required] int id, [Required] int foreach (var boreholeGeometry in borehole.BoreholeGeometry) { - boreholeGeometry.Id = 0; + boreholeGeometry.MarkAsNew(); } borehole.UpdatedBy = null; diff --git a/src/api/Controllers/UploadController.cs b/src/api/Controllers/UploadController.cs index 97eaa616c..64a020959 100644 --- a/src/api/Controllers/UploadController.cs +++ b/src/api/Controllers/UploadController.cs @@ -251,9 +251,6 @@ public async Task> UploadFileAsync(int workgroupId, IFormFile return Problem("Error while importing borehole(s)."); } } - { - return new List(); - } internal static int GetPrecision(IReaderRow row, string fieldName) { @@ -329,6 +326,9 @@ private void ValidateAttachments(BoreholeImport borehole, IList? atta var boreholeFileNames = borehole.Attachments .Split(",") .Select(s => s.Trim()) + .Where(s => !string.IsNullOrEmpty(s)) + .ToList(); + foreach (var boreholeFileName in boreholeFileNames) { // Check if the name of any attached file matches the name of the borehole file @@ -339,60 +339,6 @@ private void ValidateAttachments(BoreholeImport borehole, IList? atta } } - private void ValidateLithologyImports(List importIds, List lithologyImports) - { - // Iterate over provided lithology imports, validate them, and create error messages when necessary. - foreach (var lithology in lithologyImports.Select((value, index) => (value, index))) - { - if (lithology.value.ImportId == 0) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "import_id"), false); - - if (lithology.value.StratiImportId == 0) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "strati_import_id"), false); - - if (lithology.value.FromDepth == null) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "from_depth"), false); - - if (lithology.value.ToDepth == null) AddValidationErrorToModelState(lithology.index, string.Format(CultureInfo.InvariantCulture, nullOrEmptyMsg, "to_depth"), false); - - // Check if all import ids exist in the list of provided import ids (from borehole import file) - if (!importIds.Contains(lithology.value.ImportId)) AddValidationErrorToModelState(lithology.index, $"Borehole with {nameof(LithologyImport.ImportId)} '{lithology.value.ImportId}' not found.", false); - { - // Check if all multi code list values are numbers - try - { - ParseMultiValueCodeListIds(lithology.value); - } - catch - { - AddValidationErrorToModelState(lithology.index, $"One or more invalid (not a number) code list id in any of the following properties: {nameof(LithologyImport.ColorIds)}, {nameof(LithologyImport.OrganicComponentIds)}, {nameof(LithologyImport.GrainShapeIds)}, {nameof(LithologyImport.GrainGranularityIds)}, {nameof(LithologyImport.Uscs3Ids)}, {nameof(LithologyImport.DebrisIds)}.", false); - } - } - - // Group lithology records by import id to get lithologies per borehole. - var boreholeGroups = lithologyImports.GroupBy(l => l.ImportId); - - foreach (var boreholeLithologies in boreholeGroups) - { - // Group lithology records per borehole by strati import id to get lithologies per stratigraphy. - var stratiGroups = boreholeLithologies.GroupBy(bhoGroup => bhoGroup.StratiImportId); - foreach (var stratiGroup in stratiGroups) - { - // Check if all records with the same strati import id have the same strati name. - if (stratiGroup.Select(s => s.StratiName).Distinct().Count() > 1) - { - ModelState.AddModelError($"import_id{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiName)}."); - } - - // Check if all records with the same strati import id have the same strati date. - if (stratiGroup.Select(s => s.StratiDate).Distinct().Count() > 1) - { - ModelState.AddModelError($"import_id{stratiGroup.First().ImportId}", $"Lithology with {nameof(LithologyImport.StratiImportId)} '{stratiGroup.Key}' has various {nameof(LithologyImport.StratiDate)}."); - } - } - } - } - - } - } - internal static bool CompareValuesWithTolerance(double? firstValue, double? secondValue, double tolerance) { if (firstValue == null && secondValue == null) return true; diff --git a/tests/api/Controllers/UploadControllerTest.cs b/tests/api/Controllers/UploadControllerTest.cs index b91872304..b699ac8c7 100644 --- a/tests/api/Controllers/UploadControllerTest.cs +++ b/tests/api/Controllers/UploadControllerTest.cs @@ -479,137 +479,6 @@ public async Task UploadJsonWithDuplicatesExistingBoreholeShouldReturnError() CollectionAssert.AreEquivalent(new[] { $"Borehole with same Coordinates (+/- 2m) and same {nameof(Borehole.TotalDepth)} already exists in database.", }, problemDetails.Errors["Borehole0"]); } - [TestMethod] - public async Task UploadLithologyShouldSaveData() - { - httpClientFactoryMock - .Setup(cf => cf.CreateClient(It.IsAny())) - .Returns(() => new HttpClient()) - .Verifiable(); - - var boreholeCsvFile = GetFormFileByExistingFile("data_sets/import_litho/borehole.csv"); - var lithoCsvFile = GetFormFileByExistingFile("data_sets/import_litho/litho.csv"); - - ActionResult response = await controller.UploadFileAsync(workgroupId: 1, boreholeCsvFile, lithologyFile: lithoCsvFile, attachments: null); - - ActionResultAssert.IsOk(response.Result); - OkObjectResult okResult = (OkObjectResult)response.Result!; - Assert.AreEqual(1, okResult.Value); - - // Assert imported values - var borehole = GetBoreholesWithIncludes(context.Boreholes).ToList().Find(b => b.OriginalName == "Seth Patel"); - Assert.AreEqual(1, borehole.WorkgroupId); - Assert.AreEqual("Seth Patel", borehole.OriginalName); - - // Assert imported stratigraphy & lithologies - Assert.AreEqual(2, borehole.Stratigraphies.Count); - - // First stratigraphy - var stratigraphy = borehole.Stratigraphies.First(); - Assert.AreEqual(new DateTime(2021, 8, 6), stratigraphy.Date?.Date); - Assert.AreEqual("Bennett", stratigraphy.Name); - Assert.AreEqual(2, stratigraphy.Layers.Count); - var lithology = stratigraphy.Layers.First(l => l.FromDepth == 0.125); - Assert.AreEqual(100, lithology.ToDepth); - Assert.AreEqual(false, lithology.IsLast); - Assert.AreEqual(9001, lithology.DescriptionQualityId); - Assert.AreEqual(15104915, lithology.LithologyId); - Assert.AreEqual(15302034, lithology.LithostratigraphyId); - Assert.AreEqual("Granite", lithology.OriginalUscs); - Assert.AreEqual(23107001, lithology.UscsDeterminationId); - Assert.AreEqual(23101005, lithology.Uscs1Id); - Assert.AreEqual(21101001, lithology.GrainSize1Id); - Assert.AreEqual(23101008, lithology.Uscs2Id); - Assert.AreEqual(21103008, lithology.GrainSize2Id); - Assert.AreEqual(false, lithology.IsStriae); - Assert.AreEqual(21103003, lithology.ConsistanceId); - Assert.AreEqual(21101001, lithology.PlasticityId); - Assert.AreEqual(21102007, lithology.CompactnessId); - Assert.AreEqual(21116005, lithology.CohesionId); - Assert.AreEqual(21105002, lithology.HumidityId); - Assert.AreEqual(21106004, lithology.AlterationId); - Assert.AreEqual("instruction set Dynamic backing up Lock", lithology.Notes); - Assert.AreEqual("trace back Peso", lithology.OriginalLithology); - Assert.AreEqual(30000018, lithology.GradationId); - Assert.AreEqual(15104916, lithology.LithologyTopBedrockId); - Assert.AreEqual(2, lithology.ColorCodelists.Count); - Assert.AreEqual(2, lithology.DebrisCodelists.Count); - Assert.AreEqual(2, lithology.GrainAngularityCodelists.Count); - Assert.AreEqual(2, lithology.GrainShapeCodelists.Count); - Assert.AreEqual(3, lithology.OrganicComponentCodelists.Count); - Assert.AreEqual(3, lithology.Uscs3Codelists.Count); - - lithology = stratigraphy.Layers.First(l => l.FromDepth == 11); - Assert.AreEqual(12, lithology.ToDepth); - - // Second stratigraphy - stratigraphy = borehole.Stratigraphies.Skip(1).First(); - Assert.AreEqual(1, stratigraphy.Layers.Count); - lithology = stratigraphy.Layers.First(); - Assert.AreEqual(55, lithology.FromDepth); - Assert.AreEqual(55.23, lithology.ToDepth); - } - - [TestMethod] - public async Task UploadLithologyWithMultiCodeListPropertiesProvidedShouldSaveData() - { - httpClientFactoryMock - .Setup(cf => cf.CreateClient(It.IsAny())) - .Returns(() => new HttpClient()) - .Verifiable(); - - var boreholeCsvFile = GetFormFileByExistingFile("data_sets/import_litho_with_multi_code_list_properties/borehole.csv"); - var lithoCsvFile = GetFormFileByExistingFile("data_sets/import_litho_with_multi_code_list_properties/litho.csv"); - - ActionResult response = await controller.UploadFileAsync(workgroupId: 1, boreholeCsvFile, lithologyFile: lithoCsvFile, attachments: null); - - ActionResultAssert.IsOk(response.Result); - OkObjectResult okResult = (OkObjectResult)response.Result!; - Assert.AreEqual(1, okResult.Value); - - // Assert imported values - var borehole = GetBoreholesWithIncludes(context.Boreholes) - .ToList().Find(b => b.OriginalName == "Seth Patel"); - Assert.AreEqual(1, borehole.WorkgroupId); - Assert.AreEqual("Seth Patel", borehole.OriginalName); - - // Assert imported stratigraphy & lithologies - Assert.AreEqual(2, borehole.Stratigraphies.Count); - - // First stratigraphy - var stratigraphy = borehole.Stratigraphies.First(); - Assert.AreEqual(2, stratigraphy.Layers.Count); - var lithology = stratigraphy.Layers.First(l => l.FromDepth == 0.125); - Assert.AreEqual(100, lithology.ToDepth); - Assert.AreEqual(2, lithology.ColorCodelists.Count); - Assert.AreEqual(2, lithology.DebrisCodelists.Count); - Assert.AreEqual(3, lithology.GrainAngularityCodelists.Count); - Assert.AreEqual(3, lithology.GrainShapeCodelists.Count); - Assert.AreEqual(3, lithology.OrganicComponentCodelists.Count); - Assert.AreEqual(3, lithology.Uscs3Codelists.Count); - lithology = stratigraphy.Layers.First(l => l.FromDepth == 11); - Assert.AreEqual(12, lithology.ToDepth); - Assert.AreEqual(0, lithology.ColorCodelists.Count); - Assert.AreEqual(1, lithology.DebrisCodelists.Count); - Assert.AreEqual(0, lithology.GrainAngularityCodelists.Count); - Assert.AreEqual(0, lithology.GrainShapeCodelists.Count); - Assert.AreEqual(0, lithology.OrganicComponentCodelists.Count); - Assert.AreEqual(0, lithology.Uscs3Codelists.Count); - - // Second stratigraphy - stratigraphy = borehole.Stratigraphies.Skip(1).First(); - Assert.AreEqual(1, stratigraphy.Layers.Count); - lithology = stratigraphy.Layers.First(); - Assert.AreEqual(55, lithology.FromDepth); - Assert.AreEqual(55.23, lithology.ToDepth); - Assert.AreEqual(0, lithology.ColorCodelists.Count); - Assert.AreEqual(0, lithology.DebrisCodelists.Count); - Assert.AreEqual(0, lithology.GrainAngularityCodelists.Count); - Assert.AreEqual(0, lithology.GrainShapeCodelists.Count); - Assert.AreEqual(0, lithology.OrganicComponentCodelists.Count); - Assert.AreEqual(2, lithology.Uscs3Codelists.Count); - } - [TestMethod] public async Task UploadShouldSaveDataToDatabaseAsync() { @@ -1128,69 +997,6 @@ public async Task UploadRequiredHeadersMissingShouldReturnError() StringAssert.Contains(problemDetails.Detail, "Header with name 'ImportId'[0] was not found."); } - [TestMethod] - public async Task UploadLithologyRequiredHeadersMissingShouldReturnError() - { - var boreholeCsvFile = GetFormFileByExistingFile("data_sets/import_litho_missing_required_headers/borehole.csv"); - var lithoCsvFile = GetFormFileByExistingFile("data_sets/import_litho_missing_required_headers/litho.csv"); - - ActionResult response = await controller.UploadFileAsync(workgroupId: 1, boreholeCsvFile, lithoCsvFile); - - Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); - ObjectResult result = (ObjectResult)response.Result!; - ActionResultAssert.IsBadRequest(result); - - ProblemDetails problemDetails = (ProblemDetails)result.Value!; - StringAssert.Contains(problemDetails.Detail, "Header with name 'ImportId'[0] was not found."); - StringAssert.Contains(problemDetails.Detail, "Header with name 'StratiImportId'[0] was not found."); - StringAssert.Contains(problemDetails.Detail, "Header with name 'FromDepth'[0] was not found."); - StringAssert.Contains(problemDetails.Detail, "Header with name 'ToDepth'[0] was not found."); - } - - [TestMethod] - public async Task UploadLithologyDiffInStratiAttributesForSameStratiIdShouldReturnError() - { - var boreholeCsvFile = GetFormFileByExistingFile("data_sets/import_litho_diff_in_strati_attributes_for_same_starti_id/borehole.csv"); - var lithoCsvFile = GetFormFileByExistingFile("data_sets/import_litho_diff_in_strati_attributes_for_same_starti_id/litho.csv"); - - ActionResult response = await controller.UploadFileAsync(workgroupId: 1, boreholeCsvFile, lithoCsvFile); - - Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); - ObjectResult result = (ObjectResult)response.Result!; - ActionResultAssert.IsBadRequest(result); - - ValidationProblemDetails problemDetails = (ValidationProblemDetails)result.Value!; - Assert.AreEqual(1, problemDetails.Errors.Count); - - CollectionAssert.AreEquivalent( - new[] - { - $"Lithology with {nameof(LithologyImport.StratiImportId)} '1001' has various {nameof(LithologyImport.StratiName)}.", - $"Lithology with {nameof(LithologyImport.StratiImportId)} '1001' has various {nameof(LithologyImport.StratiDate)}.", - }, - problemDetails.Errors["import_id1"]); - } - - [TestMethod] - public async Task UploadLithologyWithImportIdNotPresentInBoreholeFileShouldReturnError() - { - var boreholeCsvFile = GetFormFileByExistingFile("data_sets/import_litho_import_id_not_present_in_borehole_file/borehole.csv"); - var lithoCsvFile = GetFormFileByExistingFile("data_sets/import_litho_import_id_not_present_in_borehole_file/litho.csv"); - - ActionResult response = await controller.UploadFileAsync(workgroupId: 1, boreholeCsvFile, lithoCsvFile); - - Assert.IsInstanceOfType(response.Result, typeof(ObjectResult)); - ObjectResult result = (ObjectResult)response.Result!; - ActionResultAssert.IsBadRequest(result); - - ValidationProblemDetails problemDetails = (ValidationProblemDetails)result.Value!; - Assert.AreEqual(1, problemDetails.Errors.Count); - - CollectionAssert.AreEquivalent( - new[] { "Borehole with ImportId '2' not found." }, - problemDetails.Errors["Row2"]); - } - [TestMethod] public async Task UploadDuplicateBoreholesInFileShouldReturnError() { diff --git a/tests/api/Helpers.cs b/tests/api/Helpers.cs index 7bb06e167..161b9758b 100644 --- a/tests/api/Helpers.cs +++ b/tests/api/Helpers.cs @@ -182,6 +182,14 @@ internal static IQueryable GetLayersWithIncludes(IQueryable query) .Include(l => l.OrganicComponentCodelists); } + /// + /// Get the codelists for the provided codelist ids. + /// + internal static async Task> GetCodelists(BdmsContext context, List codelistIds) + { + return await context.Codelists.Where(c => codelistIds.Contains(c.Id)).ToListAsync().ConfigureAwait(false); + } + internal static string ShouldBeNullMessage(this string propertyName) => $"{propertyName} should be null.";