From 519b0d327412a137282e0eeb1953826d97102934 Mon Sep 17 00:00:00 2001 From: Jason Barden Date: Wed, 3 Sep 2025 22:35:51 +0100 Subject: [PATCH] bring over offline changes --- .editorconfig | 380 ++++----- .github/dependabot.yml | 1 - .github/workflows/dotnet.yml | 70 +- .github/workflows/publish.yml | 32 + .../.idea/.gitignore | 13 + .../.idea/.name | 1 + .../.idea/encodings.xml | 4 + .../.idea/indexLayout.xml | 8 + .../inspectionProfiles/Project_Default.xml | 5 + .../.idea/misc.xml | 4 + .../.idea/vcs.xml | 13 + AStar.Dev.Example.sln.sln | 57 -- AStar.Dev.Infrastructure.FilesDb.slnx | 19 + CodeMaid.config | 82 -- astar.ico | Bin 0 -> 16958 bytes astar.png | Bin 0 -> 15984 bytes nuget.ci.config | 5 - nuget.config | 6 - .../AStar.Dev.Example.ClassLib.csproj | 9 - src/AStar.Dev.Example.ClassLib/Class1.cs | 6 - .../AStar.Dev.Infrastructure.FilesDb.csproj | 73 ++ .../AStar.Dev.Infrastructure.FilesDb.xml | 794 ++++++++++++++++++ .../DeletionStatusConfiguration.cs | 0 .../Configurations/EventConfiguration.cs | 0 .../Configurations/EventTypeConfiguration.cs | 0 .../FileClassificationConfiguration.cs | 0 .../Configurations/FileDetailConfiguration.cs | 0 .../FileNamePartConfiguration.cs | 0 .../ImageDetailConfiguration.cs | 0 .../Constants.cs | 10 + .../DeletionStatusConfiguration.cs | 27 + .../DirectoryNameConfiguration.cs | 14 + .../Data/Configurations/EventConfiguration.cs | 26 + .../Configurations/EventTypeConfiguration.cs | 15 + .../FileClassificationConfiguration.cs | 21 + .../Configurations/FileDetailConfiguration.cs | 50 ++ .../Configurations/FileNameConfiguration.cs | 14 + .../FileNamePartConfiguration.cs | 20 + .../ImageDetailConfiguration.cs | 15 + .../Data/FileContextExtensions.cs | 0 .../FileDetailDeletionStatusExtensions.cs | 20 + .../Data/FileDetailDirectoryNameExtensions.cs | 20 + .../Data/FileDetailLastViewedExtensions.cs | 21 + .../Data/FileDetailOrderingExtensions.cs | 24 + .../Data/FileDetailPagingExtensions.cs | 34 + .../Data/FileDetailSearchTypeExtensions.cs | 28 + .../Data/FileDetailTextContainsExtensions.cs | 18 + .../Data/FilesContext.cs | 71 ++ .../EnumerableExtensions.cs | 0 src/AStar.Dev.Infrastructure.FilesDb/LICENSE | 21 + ...20250715194331_InitialCreation.Designer.cs | 0 .../20250715194331_InitialCreation.cs | 0 .../20250725184934_RecreateAgain.Designer.cs | 343 ++++++++ .../20250725184934_RecreateAgain.cs | 218 +++++ .../20250725190252_RecreateAgain2.Designer.cs | 351 ++++++++ .../20250725190252_RecreateAgain2.cs | 26 + ...35_UpdateFileNameConfiguration.Designer.cs | 353 ++++++++ ...50729201535_UpdateFileNameConfiguration.cs | 24 + ...729202510_AddFileDetailIndexes.Designer.cs | 353 ++++++++ .../20250729202510_AddFileDetailIndexes.cs | 21 + ...163238_AddDuplicateImagesIndex.Designer.cs | 359 ++++++++ .../20250808163238_AddDuplicateImagesIndex.cs | 51 ++ .../Migrations/FilesContextModelSnapshot.cs | 356 ++++++++ .../Models/DeletionStatus.cs | 22 + .../Models/DirectoryName.cs | 6 + .../Models/DuplicateDetail.cs | 82 ++ .../Models/Event.cs | 57 ++ .../Models/EventType.cs | 100 +++ .../Models/FileClassification.cs | 26 + .../Models/FileDetail.cs | 104 +++ .../Models/FileHandle.cs | 19 + .../Models/FileId.cs | 7 + .../Models/FileName.cs | 15 + .../Models/FileNamePart.cs | 18 + .../Models/FileSize.cs | 55 ++ .../Models/FileSizeEqualityComparer.cs | 44 + .../Models/IFileDetail.cs | 0 .../Models/ImageDetail.cs | 8 + .../Models/SearchType.cs | 27 + .../Models/SortOrder.cs | 30 + .../Readme.md | 7 + .../astar.ico | Bin 0 -> 16958 bytes .../astar.png | Bin 0 -> 15984 bytes ...v.Infrastructure.FilesDb.Tests.Unit.csproj | 25 + .../UnitTest1.cs | 5 +- ...tar.Dev.Example.ClassLib.Tests.Unit.csproj | 25 - 86 files changed, 4781 insertions(+), 407 deletions(-) create mode 100644 .github/workflows/publish.yml create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.gitignore create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.name create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/encodings.xml create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/indexLayout.xml create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/misc.xml create mode 100644 .idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/vcs.xml delete mode 100644 AStar.Dev.Example.sln.sln create mode 100644 AStar.Dev.Infrastructure.FilesDb.slnx delete mode 100644 CodeMaid.config create mode 100644 astar.ico create mode 100644 astar.png delete mode 100644 nuget.ci.config delete mode 100644 nuget.config delete mode 100644 src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj delete mode 100644 src/AStar.Dev.Example.ClassLib/Class1.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.csproj create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.xml create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/DeletionStatusConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventTypeConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileClassificationConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileDetailConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileNamePartConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Configurations/ImageDetailConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Constants.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DeletionStatusConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DirectoryNameConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventTypeConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileClassificationConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileDetailConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNameConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNamePartConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/ImageDetailConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileContextExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDeletionStatusExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDirectoryNameExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailLastViewedExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailOrderingExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailPagingExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailSearchTypeExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailTextContainsExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Data/FilesContext.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/EnumerableExtensions.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/LICENSE create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.Designer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Migrations/FilesContextModelSnapshot.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/DeletionStatus.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/DirectoryName.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/DuplicateDetail.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/Event.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/EventType.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileClassification.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileDetail.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileHandle.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileId.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileName.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileNamePart.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileSize.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/FileSizeEqualityComparer.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/IFileDetail.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/ImageDetail.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/SearchType.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Models/SortOrder.cs create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/Readme.md create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/astar.ico create mode 100644 src/AStar.Dev.Infrastructure.FilesDb/astar.png create mode 100644 test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/AStar.Dev.Infrastructure.FilesDb.Tests.Unit.csproj rename test/{unit/AStar.Dev.Example.ClassLib.Tests.Unit => AStar.Dev.Infrastructure.FilesDb.Tests.Unit}/UnitTest1.cs (55%) delete mode 100644 test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj diff --git a/.editorconfig b/.editorconfig index 326085a..e25eb42 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,270 +7,270 @@ root = true #### Core EditorConfig Options #### # Indentation and spacing -indent_size = 4 -indent_style = space -tab_width = 4 +indent_size = 4 +indent_style = space +tab_width = 4 # New line preferences -end_of_line = crlf -insert_final_newline = false +end_of_line = crlf +insert_final_newline = false #### .NET Coding Conventions #### # Organize usings -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = true -file_header_template = unset +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true +file_header_template = unset # this. and Me. preferences -dotnet_style_qualification_for_event = false:error -dotnet_style_qualification_for_field = false -dotnet_style_qualification_for_method = false:error -dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_event = false:error +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_property = false:error # Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true -dotnet_style_predefined_type_for_member_access = true +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true # Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning -dotnet_style_parentheses_in_other_operators = never_if_unnecessary -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning # Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members +dotnet_style_require_accessibility_modifiers = for_non_interface_members # Expression-level preferences -dotnet_style_coalesce_expression = true:warning -dotnet_style_collection_initializer = true:error -dotnet_style_explicit_tuple_names = true:error -dotnet_style_namespace_match_folder = true -dotnet_style_null_propagation = true:warning -dotnet_style_object_initializer = true:error -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true:warning -dotnet_style_prefer_collection_expression = when_types_loosely_match -dotnet_style_prefer_compound_assignment = true:error -dotnet_style_prefer_conditional_expression_over_assignment = true:error -dotnet_style_prefer_conditional_expression_over_return = true:error -dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed -dotnet_style_prefer_inferred_anonymous_type_member_names = true:error -dotnet_style_prefer_inferred_tuple_names = true:error -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning -dotnet_style_prefer_simplified_boolean_expressions = true:error -dotnet_style_prefer_simplified_interpolation = true +dotnet_style_coalesce_expression = true:warning +dotnet_style_collection_initializer = true:error +dotnet_style_explicit_tuple_names = true:error +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true:warning +dotnet_style_object_initializer = true:error +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true:error +dotnet_style_prefer_conditional_expression_over_assignment = true:error +dotnet_style_prefer_conditional_expression_over_return = true:error +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true:error +dotnet_style_prefer_inferred_tuple_names = true:error +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_simplified_boolean_expressions = true:error +dotnet_style_prefer_simplified_interpolation = true # Field preferences -dotnet_style_readonly_field = true:warning +dotnet_style_readonly_field = true:warning # Parameter preferences -dotnet_code_quality_unused_parameters = all:error +dotnet_code_quality_unused_parameters = all:error # Suppression preferences -dotnet_remove_unnecessary_suppression_exclusions = none +dotnet_remove_unnecessary_suppression_exclusions = none # New line preferences -dotnet_style_allow_multiple_blank_lines_experimental = false:error -dotnet_style_allow_statement_immediately_after_block_experimental = false:warning +dotnet_style_allow_multiple_blank_lines_experimental = false:error +dotnet_style_allow_statement_immediately_after_block_experimental = false:warning #### C# Coding Conventions #### # var preferences -csharp_style_var_elsewhere = true:silent -csharp_style_var_for_built_in_types = true:silent -csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent # Expression-bodied members -csharp_style_expression_bodied_accessors = true:warning -csharp_style_expression_bodied_constructors = true:warning -csharp_style_expression_bodied_indexers = true:warning -csharp_style_expression_bodied_lambdas = true:warning -csharp_style_expression_bodied_local_functions = false:silent -csharp_style_expression_bodied_methods = true:warning -csharp_style_expression_bodied_operators = true:warning -csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_accessors = true:warning +csharp_style_expression_bodied_constructors = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_lambdas = true:warning +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = true:warning +csharp_style_expression_bodied_operators = true:warning +csharp_style_expression_bodied_properties = true:warning # Pattern matching preferences -csharp_style_pattern_matching_over_as_with_null_check = true:error -csharp_style_pattern_matching_over_is_with_cast_check = true:error -csharp_style_prefer_extended_property_pattern = true:suggestion -csharp_style_prefer_not_pattern = true:error -csharp_style_prefer_pattern_matching = true:error -csharp_style_prefer_switch_expression = true:error +csharp_style_pattern_matching_over_as_with_null_check = true:error +csharp_style_pattern_matching_over_is_with_cast_check = true:error +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_not_pattern = true:error +csharp_style_prefer_pattern_matching = true:error +csharp_style_prefer_switch_expression = true:error # Null-checking preferences -csharp_style_conditional_delegate_call = true:warning +csharp_style_conditional_delegate_call = true:warning # Modifier preferences -csharp_prefer_static_local_function = true:warning -csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async -csharp_style_prefer_readonly_struct = true:warning -csharp_style_prefer_readonly_struct_member = true:suggestion +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async +csharp_style_prefer_readonly_struct = true:warning +csharp_style_prefer_readonly_struct_member = true:suggestion # Code-block preferences -csharp_prefer_braces = true:error -csharp_prefer_simple_using_statement = true:warning -csharp_style_namespace_declarations = file_scoped:warning -csharp_style_prefer_method_group_conversion = true:warning -csharp_style_prefer_primary_constructors = true:suggestion -csharp_style_prefer_top_level_statements = false:silent +csharp_prefer_braces = true:error +csharp_prefer_simple_using_statement = true:warning +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_method_group_conversion = true:warning +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = false:silent # Expression-level preferences -csharp_prefer_simple_default_expression = true:error -csharp_style_deconstructed_variable_declaration = true:warning -csharp_style_implicit_object_creation_when_type_is_apparent = true:error -csharp_style_inlined_variable_declaration = true:warning -csharp_style_prefer_index_operator = true:error -csharp_style_prefer_local_over_anonymous_function = true:error -csharp_style_prefer_null_check_over_type_check = true:warning -csharp_style_prefer_range_operator = true:error -csharp_style_prefer_tuple_swap = true:error -csharp_style_prefer_utf8_string_literals = true:suggestion -csharp_style_throw_expression = true:warning -csharp_style_unused_value_assignment_preference = discard_variable:warning -csharp_style_unused_value_expression_statement_preference = discard_variable:warning +csharp_prefer_simple_default_expression = true:error +csharp_style_deconstructed_variable_declaration = true:warning +csharp_style_implicit_object_creation_when_type_is_apparent = true:error +csharp_style_inlined_variable_declaration = true:warning +csharp_style_prefer_index_operator = true:error +csharp_style_prefer_local_over_anonymous_function = true:error +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_style_prefer_range_operator = true:error +csharp_style_prefer_tuple_swap = true:error +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_throw_expression = true:warning +csharp_style_unused_value_assignment_preference = discard_variable:warning +csharp_style_unused_value_expression_statement_preference = discard_variable:warning # 'using' directive preferences -csharp_using_directive_placement = outside_namespace:warning +csharp_using_directive_placement = outside_namespace:warning # New line preferences csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:warning csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false:warning -csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false:warning -csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error -csharp_style_allow_embedded_statements_on_same_line_experimental = true:warning +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false:warning +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error +csharp_style_allow_embedded_statements_on_same_line_experimental = true:warning #### C# Formatting Rules #### # New line preferences -csharp_new_line_before_catch = true -csharp_new_line_before_else = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = all -csharp_new_line_between_query_expression_clauses = true +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true # Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = false -csharp_indent_labels = one_less_than_current -csharp_indent_switch_labels = true +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = false +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true # Space preferences -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = false -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = ignore -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false # Wrapping preferences -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false #### Naming styles #### # Naming rules -dotnet_naming_rule.interface_should_be_begins_with_i.severity = error -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i +dotnet_naming_rule.interface_should_be_begins_with_i.severity = error +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i -dotnet_naming_rule.types_should_be_pascal_case.severity = error -dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.types_should_be_pascal_case.severity = error +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case -dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning -dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case -dotnet_naming_rule.static_field_should_be_pascal_case.severity = warning -dotnet_naming_rule.static_field_should_be_pascal_case.symbols = static_field -dotnet_naming_rule.static_field_should_be_pascal_case.style = pascal_case +dotnet_naming_rule.static_field_should_be_pascal_case.severity = warning +dotnet_naming_rule.static_field_should_be_pascal_case.symbols = static_field +dotnet_naming_rule.static_field_should_be_pascal_case.style = pascal_case # Symbol specifications -dotnet_naming_symbols.interface.applicable_kinds = interface -dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = -dotnet_naming_symbols.static_field.applicable_kinds = field -dotnet_naming_symbols.static_field.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.static_field.required_modifiers = static +dotnet_naming_symbols.static_field.applicable_kinds = field +dotnet_naming_symbols.static_field.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.static_field.required_modifiers = static -dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum -dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = -dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method -dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case [*.{cs,vb}] -dotnet_style_operator_placement_when_wrapping = beginning_of_line -tab_width = 4 -indent_size = 4 -end_of_line = crlf -dotnet_style_coalesce_expression = true:warning -dotnet_style_null_propagation = true:warning -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning -dotnet_style_prefer_auto_properties = true:warning -dotnet_style_object_initializer = true:error -dotnet_style_collection_initializer = true:error -dotnet_style_prefer_simplified_boolean_expressions = true:error -dotnet_style_prefer_conditional_expression_over_assignment = true:error -dotnet_style_explicit_tuple_names = true:error -dotnet_style_prefer_conditional_expression_over_return = true:error -dotnet_style_prefer_inferred_tuple_names = true:error -dotnet_style_prefer_inferred_anonymous_type_member_names = true:error -dotnet_style_prefer_compound_assignment = true:error -dotnet_style_prefer_simplified_interpolation = true:suggestion -dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion -dotnet_style_namespace_match_folder = true:suggestion -dotnet_style_readonly_field = true:warning -dotnet_style_predefined_type_for_member_access = true:silent -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent -dotnet_style_allow_multiple_blank_lines_experimental = false:error +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:warning +dotnet_style_null_propagation = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_object_initializer = true:error +dotnet_style_collection_initializer = true:error +dotnet_style_prefer_simplified_boolean_expressions = true:error +dotnet_style_prefer_conditional_expression_over_assignment = true:error +dotnet_style_explicit_tuple_names = true:error +dotnet_style_prefer_conditional_expression_over_return = true:error +dotnet_style_prefer_inferred_tuple_names = true:error +dotnet_style_prefer_inferred_anonymous_type_member_names = true:error +dotnet_style_prefer_compound_assignment = true:error +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_readonly_field = true:warning +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_allow_multiple_blank_lines_experimental = false:error dotnet_style_allow_statement_immediately_after_block_experimental = false:warning -dotnet_code_quality_unused_parameters = all:error -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_property = false:error -dotnet_style_qualification_for_method = false:error -dotnet_style_qualification_for_event = false:error \ No newline at end of file +dotnet_code_quality_unused_parameters = all:error +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_event = false:error diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fd126ee..446b951 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,4 +4,3 @@ updates: directory: "/" schedule: interval: "weekly" - diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 0473985..125d797 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -1,9 +1,7 @@ -# This workflow will build a .NET project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net - name: .NET on: + workflow_dispatch: push: branches: [ "main" ] pull_request: @@ -11,25 +9,51 @@ on: jobs: build: + name: Build and analyze + runs-on: windows-latest + + steps: + - name: Set up JDK + uses: actions/setup-java@v4.4.0 + with: + java-version: 17 + distribution: 'zulu' - runs-on: ubuntu-latest + - name: Checkout + uses: actions/checkout@v4.2.1 + with: + fetch-depth: 0 - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x - - - name: Delete nuget*.config files - run: rm -f nuget*.config - - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --no-restore - - - name: Test - run: dotnet test --no-build --verbosity normal + - name: 🛠 Cache SonarQube Cloud packages + uses: actions/cache@v4.2.3 + with: + path: ~\sonar\cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: 🛠 Cache SonarQube Cloud scanner + id: cache-sonar-scanner + uses: actions/cache@v4.2.3 + with: + path: .\.sonar\scanner + key: ${{ runner.os }}-sonar-scanner + restore-keys: ${{ runner.os }}-sonar-scanner + + - name: 🛠 Install SonarQube Cloud scanner + if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' + shell: powershell + run: | + New-Item -Path .\.sonar\scanner -ItemType Directory + dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner + + - name: 🔍 Restore, 🛠 Build and 🧪 Test with ☁️ SonarCloud / Qube project - ${{ vars.SONAR_PROJECT_NAME }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + shell: powershell + run: | + dotnet tool install --global dotnet-coverage + .\.sonar\scanner\dotnet-sonarscanner begin /k:"astar-development_${{ github.event.repository.name }}" /o:"astar-development" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.scanner.scanAll=false /d:sonar.scanner.skipJreProvisioning=true + dotnet build --configuration Release + dotnet-coverage collect 'dotnet test --filter "FullyQualifiedName!~Tests.EndToEnd"' -f xml -o 'coverage.xml' + .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..1f8c366 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,32 @@ +name: 🚀 Publish NuGet Package + +on: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: 🧾 Checkout code + uses: actions/checkout@v4 + + - name: 🛠 Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.x' + + - name: 🔍 Restore dependencies + run: dotnet restore + + - name: 🛠 Build solution + run: dotnet build --configuration Release + + - name: 📦 Pack NuGet package for ${{ github.event.repository.name }} + run: dotnet pack ./src/**/*.csproj --configuration Release --output ./nupkg + + - name: 🚀 Publish to NuGet.org + run: dotnet nuget push ./nupkg/*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NuGet_API_Key }} # + diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.gitignore b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.gitignore new file mode 100644 index 0000000..361073b --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/modules.xml +/projectSettingsUpdater.xml +/.idea.AStar.Dev.Infrastructure.FilesDb.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.name b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.name new file mode 100644 index 0000000..a22f43b --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/.name @@ -0,0 +1 @@ +AStar.Dev.Infrastructure.FilesDb \ No newline at end of file diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/encodings.xml b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/indexLayout.xml b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/inspectionProfiles/Project_Default.xml b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8d66637 --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/misc.xml b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/misc.xml new file mode 100644 index 0000000..90dee70 --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/misc.xml @@ -0,0 +1,4 @@ + + + {} + \ No newline at end of file diff --git a/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/vcs.xml b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/vcs.xml new file mode 100644 index 0000000..1364320 --- /dev/null +++ b/.idea/.idea.AStar.Dev.Infrastructure.FilesDb/.idea/vcs.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/AStar.Dev.Example.sln.sln b/AStar.Dev.Example.sln.sln deleted file mode 100644 index be68fef..0000000 --- a/AStar.Dev.Example.sln.sln +++ /dev/null @@ -1,57 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ADD5430F-CD80-42C7-80DA-90048E210EE7}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{73794993-9898-4968-AF19-C3E7450C94E4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Example.ClassLib", "src\AStar.Dev.Example.ClassLib\AStar.Dev.Example.ClassLib.csproj", "{A9C19332-40FE-4E24-A890-405D46CD72A5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "end-to-end", "end-to-end", "{F1C7FB9E-2F0F-41C9-822A-7320339193CA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{D724595D-C6BC-4F31-9D2A-4F4707436F10}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{10DD984D-6788-4E04-A89C-3270006F5C56}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Example.ClassLib.Tests.Unit", "test\unit\AStar.Dev.Example.ClassLib.Tests.Unit\AStar.Dev.Example.ClassLib.Tests.Unit.csproj", "{1D7D41F6-3866-4C00-A1BA-1675227FA9FA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E1CEEE40-22D0-4F7B-AB2B-A308F8DE6A54}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitignore = .gitignore - build-and-test.ps1 = build-and-test.ps1 - CodeMaid.config = CodeMaid.config - LICENSE = LICENSE - nuget.ci.config = nuget.ci.config - nuget.config = nuget.config - README.md = README.md - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A9C19332-40FE-4E24-A890-405D46CD72A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A9C19332-40FE-4E24-A890-405D46CD72A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A9C19332-40FE-4E24-A890-405D46CD72A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A9C19332-40FE-4E24-A890-405D46CD72A5}.Release|Any CPU.Build.0 = Release|Any CPU - {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1D7D41F6-3866-4C00-A1BA-1675227FA9FA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {A9C19332-40FE-4E24-A890-405D46CD72A5} = {ADD5430F-CD80-42C7-80DA-90048E210EE7} - {F1C7FB9E-2F0F-41C9-822A-7320339193CA} = {73794993-9898-4968-AF19-C3E7450C94E4} - {D724595D-C6BC-4F31-9D2A-4F4707436F10} = {73794993-9898-4968-AF19-C3E7450C94E4} - {10DD984D-6788-4E04-A89C-3270006F5C56} = {73794993-9898-4968-AF19-C3E7450C94E4} - {1D7D41F6-3866-4C00-A1BA-1675227FA9FA} = {10DD984D-6788-4E04-A89C-3270006F5C56} - EndGlobalSection -EndGlobal diff --git a/AStar.Dev.Infrastructure.FilesDb.slnx b/AStar.Dev.Infrastructure.FilesDb.slnx new file mode 100644 index 0000000..57c7220 --- /dev/null +++ b/AStar.Dev.Infrastructure.FilesDb.slnx @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/CodeMaid.config b/CodeMaid.config deleted file mode 100644 index 54f2ebe..0000000 --- a/CodeMaid.config +++ /dev/null @@ -1,82 +0,0 @@ - - - - -
- - - - - - <?xml version="1.0" encoding="utf-16"?> - <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - <string>ReSharper disable </string> - <string>ReSharper enable </string> - </ArrayOfString> - - - - True - - - 1 - - - False - - - True - - - True - - - 1 - - - 2 - - - True - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - False - - - True - - - 1 - - - - \ No newline at end of file diff --git a/astar.ico b/astar.ico new file mode 100644 index 0000000000000000000000000000000000000000..38b6709a751659db6d84ef77d794c46015e49f91 GIT binary patch literal 16958 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 literal 0 HcmV?d00001 diff --git a/nuget.ci.config b/nuget.ci.config deleted file mode 100644 index aa5beec..0000000 --- a/nuget.ci.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/nuget.config b/nuget.config deleted file mode 100644 index 782724b..0000000 --- a/nuget.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj b/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj deleted file mode 100644 index 125f4c9..0000000 --- a/src/AStar.Dev.Example.ClassLib/AStar.Dev.Example.ClassLib.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net9.0 - enable - enable - - - diff --git a/src/AStar.Dev.Example.ClassLib/Class1.cs b/src/AStar.Dev.Example.ClassLib/Class1.cs deleted file mode 100644 index 27e9361..0000000 --- a/src/AStar.Dev.Example.ClassLib/Class1.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace AStar.Dev.Example.ClassLib; - -public class Class1 -{ - -} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.csproj b/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.csproj new file mode 100644 index 0000000..d6dbf74 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.csproj @@ -0,0 +1,73 @@ + + + + net9.0 + enable + enable + latest-recommended + True + + + + AStar Developement, Jason Barden + AStar Development + AStar Developement, 2025 + Defines the context and models for the FilesDb. + $(AssemblyName).xml + true + true + true + true + astar.png + $(AssemblyName) + MIT + https://github.com/astar-development/astar-dev-infrastructure-filesdb + Readme.md + true + Initial creation + true + git + https://github.com/astar-development/astar-dev-infrastructure-filesdb.git + snupkg + AStar Dev Infrastructure FilesDb + 0.1.0 + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + True + 1701;1702; + + + + True + 1701;1702; + + + diff --git a/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.xml b/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.xml new file mode 100644 index 0000000..b4cac2c --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/AStar.Dev.Infrastructure.FilesDb.xml @@ -0,0 +1,794 @@ + + + + AStar.Dev.Infrastructure.FilesDb + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A lot of variations of this method have been tried, but none of them worked as expected. + This one does not work as we're using SQLite for testing, and it does not support DateTimeOffset. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The class + + + The list of files in the dB + + + + + + + + + + + + + + The list of files in the dB + + + + + + + + + The list of Events + + + + + Gets or sets the File Classifications + + + + + Gets or sets the Duplicate Details + + + + + The overridden OnModelCreating method + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines dates/times for soft and hard deletion + + + + + Gets or sets when the file was 'soft deleted'. I know, shocking... + + + + + Gets or sets when the file was marked as 'soft delete pending'. I know, shocking... + + + + + Gets or sets when the file was marked as 'hard delete pending'. I know, shocking... + + + + + + + + + + + + + + + + + + The class defines the fields that will be mapped from the vw_DuplicateDetails in the database + + + + + Gets or sets the File Name + + + + + Gets or sets the Directory Name + + + + + Gets or sets the File Height + + + + + Gets or sets the File Width + + + + + Gets or sets the File Size + + + + + Gets or sets the File Handle + + + + + Gets or sets whether File is an image + + + + + Gets or sets the Instance count for the duplicate group + + + + + Gets or sets the Details Last Updated + + + + + Gets or sets the Last Viewed date + + + + + Gets or sets the Soft Deleted flag + + + + + Gets or sets the SoftDeletePending flag + + + + + Gets or sets the Move Required flag + + + + + Gets or sets the Hard Delete Pending flag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets or sets the Updated By property to track who made the change + + + + + Represents a sealed class for defining distinct event types such as Add, Update, and Delete. + This class ensures that only predefined instances of event types can be used, + providing type safety and preventing the creation of arbitrary states. + + + + + Private constructor to prevent external instantiation. + This ensures that only the static readonly instances above can be created. + + The integer value representing the event type. + The string name of the event type. + + + + Represents an 'Add' event type, typically used for new record creation. + + + + + Represents an 'Update' event type, typically used for modifying existing records. + + + + + Represents a 'SoftDelete' event type, typically used for 'soft' removing records. + + + + + Represents a 'HardDelete' event type, typically used for permanently removing records. + + + + + Gets the integer value associated with the event type. + + + + + Gets the string name of the event type. + + + + + + + + + + + Returns the string name of the event type, useful for debugging and display. + + The name of the event type. + + + + + + + Overloads the equality operator to compare two objects. + + The first to compare. + The second to compare. + true if the two objects are equal; otherwise, false. + + + + Overloads the inequality operator to compare two objects. + + The first to compare. + The second to compare. + true if the two objects are not equal; otherwise, false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + The FileDetail class containing the current properties + + + + + The default constructor required by EF Core etc + + + + + The copy constructor that allows for passing an instance of FileInfo to this class, simplifying consumer code + + + The instance of FileInfo to map + + + + + + + + + Gets or sets the ID of the . I know, shocking... + + + + + + + + + Gets or sets the file name. I know, shocking... + + + + + Gets or sets the name of the directory containing the file detail. I know, shocking... + + + + + Gets the full name of the file with the path combined + + + + + Gets or sets the file size. I know, shocking... + + + + + Gets or sets whether the file is of a supported image type + + + + + Gets or sets the file handle. I know, shocking... + + + + + + + + + + + + + + + + + Gets or sets whether the file has been marked as 'needs to move'. I know, shocking... + + + + + Gets or sets the file deletion status. I know, shocking... + + + + + Returns this object in JSON format + + + This object serialized as a JSON object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the FileId + + The value of the File Id + + + + Defines the FileId + + The value of the File Id + + + The value of the File Id + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the file length property + + + + + Gets the file height property + + + + + Gets the file width property + + + + + The Create method will return a populated instance of the class + + + The length of the file + + + The height of the file if an image + + + The width of the file if an image + + + A populated instance of . + + + + + Returns this object in JSON format + + + This object serialized as a JSON object + + + + + The class that defines how the file sizes are deemed to be equal + + + + + The Equals method has been overridden to perform the equality check currently required. The equality check is for + Height, Width and Length - making this more of an ImageComparer... + + + An instance of the class to compare + + + The other instance of the class to compare + + + true if the files are deemed to be the same size, false otherwise + + + + + The GetHashCode has been overridden to return the hash-codes as per the fields compared in the overridden Equals + method + + + The to calculate the appropriate hash-code for + + + The hash-code, combined from the relevant properties own hash-codes + + + + + + + + + + + + + The enumeration defining the available search types + + + + + Search for images only + + + + + Search for all file types + + + + + Search for duplicates - file type is ignored + + + + + Search for duplicate images + + + + + The currently supported SortOrders + + + + + Order by the size descending + + + + + Order by the size ascending + + + + + Order by the name descending + + + + + Order by the name ascending + + + + diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/DeletionStatusConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/DeletionStatusConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventTypeConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/EventTypeConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileClassificationConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileClassificationConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileDetailConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileDetailConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileNamePartConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/FileNamePartConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Configurations/ImageDetailConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Configurations/ImageDetailConfiguration.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Constants.cs b/src/AStar.Dev.Infrastructure.FilesDb/Constants.cs new file mode 100644 index 0000000..5b3063e --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Constants.cs @@ -0,0 +1,10 @@ +namespace AStar.Dev.Infrastructure.FilesDb; + +/// +/// +public static class Constants +{ + /// + /// + public const string SchemaName = "files"; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DeletionStatusConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DeletionStatusConfiguration.cs new file mode 100644 index 0000000..6c0fe09 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DeletionStatusConfiguration.cs @@ -0,0 +1,27 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +internal sealed class DeletionStatusConfiguration : IComplexPropertyConfiguration +{ + public void Configure(ComplexPropertyBuilder builder) + { + _ = builder + .Property(deletionStatus => deletionStatus.HardDeletePending) + .HasColumnName("HardDeletePending") + .HasColumnType("datetimeoffset"); + + _ = builder + .Property(deletionStatus => deletionStatus.SoftDeletePending) + .HasColumnName("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + _ = builder + .Property(deletionStatus => deletionStatus.SoftDeleted) + .HasColumnName("SoftDeleted") + .HasColumnType("datetimeoffset"); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DirectoryNameConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DirectoryNameConfiguration.cs new file mode 100644 index 0000000..8e7d470 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/DirectoryNameConfiguration.cs @@ -0,0 +1,14 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +internal sealed class DirectoryNameConfiguration : IComplexPropertyConfiguration +{ + public void Configure(ComplexPropertyBuilder builder) + => builder.Property(directoryName => directoryName.Value) + .HasColumnName("DirectoryName") + .HasColumnType("nvarchar(256)"); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventConfiguration.cs new file mode 100644 index 0000000..d5f8839 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventConfiguration.cs @@ -0,0 +1,26 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +/// +/// +public class EventConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + _ = builder + .ToTable(nameof(Event), Constants.SchemaName) + .HasKey(fileDetail => fileDetail.Id); + + _ = builder.Property(fileDetail => fileDetail.FileName).HasMaxLength(256); + _ = builder.Property(fileDetail => fileDetail.DirectoryName).HasMaxLength(256); + _ = builder.Property(fileDetail => fileDetail.Handle).HasMaxLength(256); + _ = builder.Property(fileDetail => fileDetail.UpdatedBy).HasMaxLength(30); + + _ = builder.ComplexProperty(fileDetail => fileDetail.Type).Configure(new EventTypeConfiguration()); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventTypeConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventTypeConfiguration.cs new file mode 100644 index 0000000..5f7defd --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/EventTypeConfiguration.cs @@ -0,0 +1,15 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +internal sealed class EventTypeConfiguration : IComplexPropertyConfiguration +{ + public void Configure(ComplexPropertyBuilder builder) + { + _ = builder.Property(eventType => eventType.Value).HasColumnName("EventType").IsRequired(); + _ = builder.Property(eventType => eventType.Name).HasColumnName("EventName").IsRequired(); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileClassificationConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileClassificationConfiguration.cs new file mode 100644 index 0000000..7cc7943 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileClassificationConfiguration.cs @@ -0,0 +1,21 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +/// +/// +public class FileClassificationConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + _ = builder + .ToTable(nameof(FileClassification), Constants.SchemaName) + .HasKey(fileClassification => fileClassification.Id); + + _ = builder.HasMany(); + _ = builder.Property(fileClassification => fileClassification.Name).HasMaxLength(150); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileDetailConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileDetailConfiguration.cs new file mode 100644 index 0000000..8817e16 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileDetailConfiguration.cs @@ -0,0 +1,50 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +/// +/// +public class FileDetailConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + _ = builder.ToTable("FileDetail"); + + _ = builder.HasKey(file => file.Id); + + _ = builder.Property(file => file.Id) + .HasConversion(fileId => fileId.Value, fileId => new(fileId)); + + _ = builder.Ignore(fileDetail => fileDetail.FileName); + _ = builder.Ignore(fileDetail => fileDetail.DirectoryName); + _ = builder.Ignore(fileDetail => fileDetail.FullNameWithPath); + + _ = builder.Property(file => file.FileHandle) + .HasColumnType("nvarchar(256)") + .HasConversion(fileHandle => fileHandle.Value, fileHandle => new(fileHandle)); + + _ = builder.ComplexProperty(fileDetail => fileDetail.ImageDetail) + .Configure(new ImageDetailConfiguration()); + + _ = builder.ComplexProperty(fileDetail => fileDetail.DirectoryName) + .Configure(new DirectoryNameConfiguration()); + + _ = builder.ComplexProperty(fileDetail => fileDetail.FileName) + .Configure(new FileNameConfiguration()); + + _ = builder.ComplexProperty(fileDetail => fileDetail.DeletionStatus) + .Configure(new DeletionStatusConfiguration()); + + _ = builder.HasIndex(fileDetail => fileDetail.FileHandle).IsUnique(); + _ = builder.HasIndex(fileDetail => fileDetail.FileSize); + + // Composite index to optimize duplicate images search (partial optimization) + // Note: ImageHeight and ImageWidth can't be indexed directly as they're complex properties + _ = builder.HasIndex(fileDetail => new { fileDetail.IsImage, fileDetail.FileSize }) + .HasDatabaseName("IX_FileDetail_DuplicateImages"); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNameConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNameConfiguration.cs new file mode 100644 index 0000000..a8afc7e --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNameConfiguration.cs @@ -0,0 +1,14 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +internal sealed class FileNameConfiguration : IComplexPropertyConfiguration +{ + public void Configure(ComplexPropertyBuilder builder) + => builder.Property(fileName => fileName.Value) + .HasColumnName("FileName") + .HasColumnType("nvarchar(256)"); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNamePartConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNamePartConfiguration.cs new file mode 100644 index 0000000..f6016fb --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/FileNamePartConfiguration.cs @@ -0,0 +1,20 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +/// +/// +public class FileNamePartConfiguration : IEntityTypeConfiguration +{ + /// + public void Configure(EntityTypeBuilder builder) + { + _ = builder + .ToTable(nameof(FileNamePart), Constants.SchemaName) + .HasKey(fileNamePart => fileNamePart.Id); + + _ = builder.Property(fileNamePart => fileNamePart.Text).HasMaxLength(150); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/ImageDetailConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/ImageDetailConfiguration.cs new file mode 100644 index 0000000..5e8d738 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/Configurations/ImageDetailConfiguration.cs @@ -0,0 +1,15 @@ +using AStar.Dev.Infrastructure.Data.Configurations; +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace AStar.Dev.Infrastructure.FilesDb.Data.Configurations; + +internal sealed class ImageDetailConfiguration : IComplexPropertyConfiguration +{ + public void Configure(ComplexPropertyBuilder builder) + { + _ = builder.Property(image => image.Width).HasColumnName("ImageWidth"); + _ = builder.Property(image => image.Height).HasColumnName("ImageHeight"); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileContextExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileContextExtensions.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDeletionStatusExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDeletionStatusExtensions.cs new file mode 100644 index 0000000..c08bd28 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDeletionStatusExtensions.cs @@ -0,0 +1,20 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailDeletionStatusExtensions +{ + /// + /// + /// + /// + /// + public static IQueryable IncludeDeletedOrDeletePending(this IQueryable files, bool includeDeleted) + => includeDeleted + ? files + : files.Where(f => f.DeletionStatus.HardDeletePending == null + && f.DeletionStatus.SoftDeletePending == null + && f.DeletionStatus.SoftDeleted == null); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDirectoryNameExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDirectoryNameExtensions.cs new file mode 100644 index 0000000..c22d542 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailDirectoryNameExtensions.cs @@ -0,0 +1,20 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; +using AStar.Dev.Utilities; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailDirectoryNameExtensions +{ + /// + /// + /// + /// + /// + /// + public static IQueryable WhereDirectoryNameMatches(this IQueryable files, string directoryName, bool includeSubDirectories) + => includeSubDirectories + ? files.Where(file => file.DirectoryName.Value.Contains(directoryName.RemoveTrailing(@"\"))) + : files.Where(file => file.DirectoryName.Value == directoryName.RemoveTrailing(@"\")); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailLastViewedExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailLastViewedExtensions.cs new file mode 100644 index 0000000..e93f614 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailLastViewedExtensions.cs @@ -0,0 +1,21 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailLastViewedExtensions +{ + /// + /// A lot of variations of this method have been tried, but none of them worked as expected. + /// This one does not work as we're using SQLite for testing, and it does not support DateTimeOffset. + /// + /// + /// + /// + /// + public static IQueryable WhereLastViewedIsOlderThan(this IQueryable files, int days, TimeProvider time) + => days == 0 + ? files + : files.Where(file => !file.FileLastViewed.HasValue || file.FileLastViewed.Value <= time.GetUtcNow().AddDays(-days)); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailOrderingExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailOrderingExtensions.cs new file mode 100644 index 0000000..8fa956b --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailOrderingExtensions.cs @@ -0,0 +1,24 @@ +using System.Diagnostics; +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailOrderingExtensions +{ + /// + /// + /// + /// + /// + public static IQueryable OrderResultsBy(this IQueryable files, SortOrder sortOrder) + => sortOrder switch + { + SortOrder.NameAscending => files.OrderBy(f => f.FileName.Value), + SortOrder.NameDescending => files.OrderByDescending(f => f.FileName.Value), + SortOrder.SizeAscending => files.OrderBy(f => f.FileSize), + SortOrder.SizeDescending => files.OrderByDescending(f => f.FileSize), + _ => throw new UnreachableException("If we reach here, a new SortOrder has been added but not included...") + }; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailPagingExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailPagingExtensions.cs new file mode 100644 index 0000000..07f92d3 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailPagingExtensions.cs @@ -0,0 +1,34 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailPagingExtensions +{ + /// + /// + /// + /// + /// + /// + public static IQueryable GetPage(this IQueryable files, int pageNumber, int pageSize) + { + pageSize = RestrictPageSize(pageSize); + + if(pageNumber < 1) + { + pageNumber = 1; + } + + return files.Skip(pageNumber * pageSize).Take(pageSize); + } + + private static int RestrictPageSize(int pageSize) + => pageSize switch + { + < 1 => 1, + > 50 => 50, + _ => pageSize + }; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailSearchTypeExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailSearchTypeExtensions.cs new file mode 100644 index 0000000..637ec7b --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailSearchTypeExtensions.cs @@ -0,0 +1,28 @@ +using System.Diagnostics; +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailSearchTypeExtensions +{ + /// + /// + /// + /// + /// + public static IQueryable OfSearchType(this IQueryable files, SearchType searchType) + => searchType switch + { + SearchType.All => files, + SearchType.Images => files.Where(f => f.IsImage), + SearchType.Duplicates => files.Where(f => files.Count(x => x.FileSize == f.FileSize) > 1), + SearchType.DuplicateImages => files.Where(f => f.IsImage && + files.Count(x => x.IsImage && + x.FileSize == f.FileSize && + x.ImageDetail.Height == f.ImageDetail.Height && + x.ImageDetail.Width == f.ImageDetail.Width) > 1), + _ => throw new UnreachableException("If we reach here, a new SearchType has been added but not included...") + }; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailTextContainsExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailTextContainsExtensions.cs new file mode 100644 index 0000000..3720692 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FileDetailTextContainsExtensions.cs @@ -0,0 +1,18 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// +public static class FileDetailTextContainsExtensions +{ + /// + /// + /// + /// + /// + public static IQueryable SelectFilesMatching(this IQueryable files, string? searchText) + => string.IsNullOrEmpty(searchText) + ? files + : files.Where(file => file.DirectoryName.Value.Contains(searchText) || file.FileName.Value.Contains(searchText)); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Data/FilesContext.cs b/src/AStar.Dev.Infrastructure.FilesDb/Data/FilesContext.cs new file mode 100644 index 0000000..c4dbfe1 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Data/FilesContext.cs @@ -0,0 +1,71 @@ +using AStar.Dev.Infrastructure.FilesDb.Models; +using Microsoft.EntityFrameworkCore; + +namespace AStar.Dev.Infrastructure.FilesDb.Data; + +/// +/// The class +/// +/// +/// The list of files in the dB +/// +public class FilesContext : DbContext +{ + /// + /// + /// + public FilesContext(DbContextOptions options) + : base(options) + { + } + + /// + /// + public FilesContext() + : base(new DbContextOptions()) + { + } + + /// + /// The list of files in the dB + /// + public virtual DbSet FileDetails { get; set; } = null!; + + /// + /// + public DbSet FileNameParts { get; set; } = null!; + + /// + /// The list of Events + /// + public virtual DbSet Events { get; set; } = null!; + + /// + /// Gets or sets the File Classifications + /// + public DbSet FileClassifications { get; set; } = null!; + + /// + /// Gets or sets the Duplicate Details + /// + public DbSet DuplicateDetails { get; set; } + + /// + /// The overridden OnModelCreating method + /// + /// + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + _ = modelBuilder.UseCollation("SQL_Latin1_General_CP1_CI_AS"); + _ = modelBuilder.HasDefaultSchema(Constants.SchemaName); + _ = modelBuilder.ApplyConfigurationsFromAssembly(typeof(FilesContext).Assembly); + + _ = modelBuilder + .Entity(eb => + { + _ = eb.HasNoKey(); + _ = eb.ToView("vw_DuplicateDetails"); + }); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/EnumerableExtensions.cs b/src/AStar.Dev.Infrastructure.FilesDb/EnumerableExtensions.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/LICENSE b/src/AStar.Dev.Infrastructure.FilesDb/LICENSE new file mode 100644 index 0000000..0b1b024 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 AStar Development, Jason Barden + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250715194331_InitialCreation.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.Designer.cs new file mode 100644 index 0000000..1d12a66 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.Designer.cs @@ -0,0 +1,343 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + [Migration("20250725184934_RecreateAgain")] + partial class RecreateAgain + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle"); + + b.HasIndex("FileName"); + + b.HasIndex("FileSize"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.cs new file mode 100644 index 0000000..01badff --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725184934_RecreateAgain.cs @@ -0,0 +1,218 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations; + +/// +public partial class RecreateAgain : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.EnsureSchema( + name: "files"); + + _ = migrationBuilder.CreateTable( + name: "Event", + schema: "files", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + EventOccurredAt = table.Column(type: "datetimeoffset", nullable: false), + FileName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + DirectoryName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Handle = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Width = table.Column(type: "int", nullable: true), + Height = table.Column(type: "int", nullable: true), + FileSize = table.Column(type: "bigint", nullable: false), + FileCreated = table.Column(type: "datetimeoffset", nullable: false), + FileLastModified = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(30)", maxLength: 30, nullable: false), + EventName = table.Column(type: "nvarchar(max)", nullable: false), + EventType = table.Column(type: "int", nullable: false) + }, + constraints: table => _ = table.PrimaryKey("PK_Event", x => x.Id)); + + _ = migrationBuilder.CreateTable( + name: "FileClassification", + schema: "files", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: false), + Celebrity = table.Column(type: "bit", nullable: false) + }, + constraints: table => _ = table.PrimaryKey("PK_FileClassification", x => x.Id)); + + _ = migrationBuilder.CreateTable( + name: "FileDetail", + schema: "files", + columns: table => new + { + Id = table.Column(type: "int", nullable: false), + FileName = table.Column(type: "nvarchar(256)", nullable: false), + FileSize = table.Column(type: "bigint", nullable: false), + IsImage = table.Column(type: "bit", nullable: false), + FileHandle = table.Column(type: "nvarchar(256)", nullable: false), + FileCreated = table.Column(type: "datetimeoffset", nullable: false), + FileLastModified = table.Column(type: "datetimeoffset", nullable: false), + FileLastViewed = table.Column(type: "datetimeoffset", nullable: true), + MoveRequired = table.Column(type: "bit", nullable: false), + HardDeletePending = table.Column(type: "datetimeoffset", nullable: true), + SoftDeletePending = table.Column(type: "datetimeoffset", nullable: true), + SoftDeleted = table.Column(type: "datetimeoffset", nullable: true), + ImageHeight = table.Column(type: "int", nullable: true), + ImageWidth = table.Column(type: "int", nullable: true), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: false), + UpdatedOn = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => _ = table.PrimaryKey("PK_FileDetail", x => x.Id)); + + _ = migrationBuilder.CreateTable( + name: "FileNamePart", + schema: "files", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Text = table.Column(type: "nvarchar(150)", maxLength: 150, nullable: false), + FileClassificationId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + _ = table.PrimaryKey("PK_FileNamePart", x => x.Id); + + _ = table.ForeignKey( + name: "FK_FileNamePart_FileClassification_FileClassificationId", + column: x => x.FileClassificationId, + principalSchema: "files", + principalTable: "FileClassification", + principalColumn: "Id"); + }); + + _ = migrationBuilder.CreateTable( + name: "FileClassificationFileDetail", + schema: "files", + columns: table => new + { + FileClassificationsId = table.Column(type: "int", nullable: false), + FileDetailsId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + _ = table.PrimaryKey("PK_FileClassificationFileDetail", x => new { x.FileClassificationsId, x.FileDetailsId }); + + _ = table.ForeignKey( + name: "FK_FileClassificationFileDetail_FileClassification_FileClassificationsId", + column: x => x.FileClassificationsId, + principalSchema: "files", + principalTable: "FileClassification", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + _ = table.ForeignKey( + name: "FK_FileClassificationFileDetail_FileDetail_FileDetailsId", + column: x => x.FileDetailsId, + principalSchema: "files", + principalTable: "FileDetail", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + _ = migrationBuilder.CreateTable( + name: "FileClassificationFileNamePart", + schema: "files", + columns: table => new + { + FileClassificationsId = table.Column(type: "int", nullable: false), + FileNamePartsId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + _ = table.PrimaryKey("PK_FileClassificationFileNamePart", x => new { x.FileClassificationsId, x.FileNamePartsId }); + + _ = table.ForeignKey( + name: "FK_FileClassificationFileNamePart_FileClassification_FileClassificationsId", + column: x => x.FileClassificationsId, + principalSchema: "files", + principalTable: "FileClassification", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + _ = table.ForeignKey( + name: "FK_FileClassificationFileNamePart_FileNamePart_FileNamePartsId", + column: x => x.FileNamePartsId, + principalSchema: "files", + principalTable: "FileNamePart", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileClassificationFileDetail_FileDetailsId", + schema: "files", + table: "FileClassificationFileDetail", + column: "FileDetailsId"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileClassificationFileNamePart_FileNamePartsId", + schema: "files", + table: "FileClassificationFileNamePart", + column: "FileNamePartsId"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileHandle", + schema: "files", + table: "FileDetail", + column: "FileHandle"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileName", + schema: "files", + table: "FileDetail", + column: "FileName"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileSize", + schema: "files", + table: "FileDetail", + column: "FileSize"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileNamePart_FileClassificationId", + schema: "files", + table: "FileNamePart", + column: "FileClassificationId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.DropTable( + name: "Event", + schema: "files"); + + _ = migrationBuilder.DropTable( + name: "FileClassificationFileDetail", + schema: "files"); + + _ = migrationBuilder.DropTable( + name: "FileClassificationFileNamePart", + schema: "files"); + + _ = migrationBuilder.DropTable( + name: "FileDetail", + schema: "files"); + + _ = migrationBuilder.DropTable( + name: "FileNamePart", + schema: "files"); + + _ = migrationBuilder.DropTable( + name: "FileClassification", + schema: "files"); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.Designer.cs new file mode 100644 index 0000000..25147bd --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.Designer.cs @@ -0,0 +1,351 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + [Migration("20250725190252_RecreateAgain2")] + partial class RecreateAgain2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("DirectoryName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DirectoryName#DirectoryName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("DirectoryName"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle"); + + b.HasIndex("FileName"); + + b.HasIndex("FileSize"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.cs new file mode 100644 index 0000000..821b1f2 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250725190252_RecreateAgain2.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations; + +/// +public partial class RecreateAgain2 : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + => migrationBuilder.AddColumn( + name: "DirectoryName", + schema: "files", + table: "FileDetail", + type: "nvarchar(256)", + nullable: false, + defaultValue: ""); + + /// + protected override void Down(MigrationBuilder migrationBuilder) + => migrationBuilder.DropColumn( + name: "DirectoryName", + schema: "files", + table: "FileDetail"); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.Designer.cs new file mode 100644 index 0000000..a83c27b --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.Designer.cs @@ -0,0 +1,353 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + [Migration("20250729201535_UpdateFileNameConfiguration")] + partial class UpdateFileNameConfiguration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("DirectoryName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DirectoryName#DirectoryName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("DirectoryName"); + }); + + b.ComplexProperty>("FileName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.FileName#FileName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("FileName"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle"); + + b.HasIndex("FileSize"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.cs new file mode 100644 index 0000000..96028ca --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729201535_UpdateFileNameConfiguration.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations; + +/// +public partial class UpdateFileNameConfiguration : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + => migrationBuilder.DropIndex( + name: "IX_FileDetail_FileName", + schema: "files", + table: "FileDetail"); + + /// + protected override void Down(MigrationBuilder migrationBuilder) + => migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileName", + schema: "files", + table: "FileDetail", + column: "FileName"); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.Designer.cs new file mode 100644 index 0000000..1f1b5f3 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.Designer.cs @@ -0,0 +1,353 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + [Migration("20250729202510_AddFileDetailIndexes")] + partial class AddFileDetailIndexes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("DirectoryName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DirectoryName#DirectoryName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("DirectoryName"); + }); + + b.ComplexProperty>("FileName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.FileName#FileName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("FileName"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle"); + + b.HasIndex("FileSize"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.cs new file mode 100644 index 0000000..3990a25 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250729202510_AddFileDetailIndexes.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations; + +/// +public partial class AddFileDetailIndexes : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // NAR - the code changes did not produce a dB change + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + // NAR - the code changes did not produce a dB change + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.Designer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.Designer.cs new file mode 100644 index 0000000..72fb318 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.Designer.cs @@ -0,0 +1,359 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + [Migration("20250808163238_AddDuplicateImagesIndex")] + partial class AddDuplicateImagesIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("DirectoryName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DirectoryName#DirectoryName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("DirectoryName"); + }); + + b.ComplexProperty>("FileName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.FileName#FileName", b1 => + { + b1.IsRequired(); + + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("FileName"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle") + .IsUnique(); + + b.HasIndex("FileSize"); + + b.HasIndex("IsImage", "FileSize") + .HasDatabaseName("IX_FileDetail_DuplicateImages"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.cs new file mode 100644 index 0000000..c3d91b0 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/20250808163238_AddDuplicateImagesIndex.cs @@ -0,0 +1,51 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations; + +/// +public partial class AddDuplicateImagesIndex : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.DropIndex( + name: "IX_FileDetail_FileHandle", + schema: "files", + table: "FileDetail"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_DuplicateImages", + schema: "files", + table: "FileDetail", + columns: ["IsImage", "FileSize"]); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileHandle", + schema: "files", + table: "FileDetail", + column: "FileHandle", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + _ = migrationBuilder.DropIndex( + name: "IX_FileDetail_DuplicateImages", + schema: "files", + table: "FileDetail"); + + _ = migrationBuilder.DropIndex( + name: "IX_FileDetail_FileHandle", + schema: "files", + table: "FileDetail"); + + _ = migrationBuilder.CreateIndex( + name: "IX_FileDetail_FileHandle", + schema: "files", + table: "FileDetail", + column: "FileHandle"); + } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Migrations/FilesContextModelSnapshot.cs b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/FilesContextModelSnapshot.cs new file mode 100644 index 0000000..5a4bfd3 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Migrations/FilesContextModelSnapshot.cs @@ -0,0 +1,356 @@ +// + +using System.Collections.Generic; +using AStar.Dev.Infrastructure.FilesDb.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AStar.Dev.Infrastructure.FilesDb.Migrations +{ + [DbContext(typeof(FilesContext))] + partial class FilesContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("files") + .UseCollation("SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.DuplicateDetail", b => + { + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileHandle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("HardDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("Instances") + .HasColumnType("int"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("SoftDeletePending") + .HasColumnType("datetimeoffset"); + + b.Property("SoftDeleted") + .HasColumnType("datetimeoffset"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ToTable((string)null); + + b.ToView("vw_DuplicateDetails", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DirectoryName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EventOccurredAt") + .HasColumnType("datetimeoffset"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("Handle") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Height") + .HasColumnType("int"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Width") + .HasColumnType("int"); + + b.ComplexProperty>("Type", "AStar.Dev.Infrastructure.FilesDb.Models.Event.Type#EventType", b1 => + { + b1.IsRequired(); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("EventName"); + + b1.Property("Value") + .HasColumnType("int") + .HasColumnName("EventType"); + }); + + b.HasKey("Id"); + + b.ToTable("Event", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Celebrity") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.ToTable("FileClassification", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("FileCreated") + .HasColumnType("datetimeoffset"); + + b.Property("FileHandle") + .IsRequired() + .HasColumnType("nvarchar(256)"); + + b.Property("FileLastModified") + .HasColumnType("datetimeoffset"); + + b.Property("FileLastViewed") + .HasColumnType("datetimeoffset"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("IsImage") + .HasColumnType("bit"); + + b.Property("MoveRequired") + .HasColumnType("bit"); + + b.Property("UpdatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdatedOn") + .HasColumnType("datetimeoffset"); + + b.ComplexProperty>("DeletionStatus", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DeletionStatus#DeletionStatus", b1 => + { + b1.IsRequired(); + + b1.Property("HardDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("HardDeletePending"); + + b1.Property("SoftDeletePending") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeletePending"); + + b1.Property("SoftDeleted") + .HasColumnType("datetimeoffset") + .HasColumnName("SoftDeleted"); + }); + + b.ComplexProperty>("DirectoryName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.DirectoryName#DirectoryName", b1 => + { + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("DirectoryName"); + }); + + b.ComplexProperty>("FileName", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.FileName#FileName", b1 => + { + b1.IsRequired(); + + b1.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasColumnName("FileName"); + }); + + b.ComplexProperty>("ImageDetail", "AStar.Dev.Infrastructure.FilesDb.Models.FileDetail.ImageDetail#ImageDetail", b1 => + { + b1.IsRequired(); + + b1.Property("Height") + .HasColumnType("int") + .HasColumnName("ImageHeight"); + + b1.Property("Width") + .HasColumnType("int") + .HasColumnName("ImageWidth"); + }); + + b.HasKey("Id"); + + b.HasIndex("FileHandle") + .IsUnique(); + + b.HasIndex("FileSize"); + + b.HasIndex("IsImage", "FileSize") + .HasDatabaseName("IX_FileDetail_DuplicateImages"); + + b.ToTable("FileDetail", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FileClassificationId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.HasKey("Id"); + + b.HasIndex("FileClassificationId"); + + b.ToTable("FileNamePart", "files"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileDetailsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileDetailsId"); + + b.HasIndex("FileDetailsId"); + + b.ToTable("FileClassificationFileDetail", "files"); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.Property("FileClassificationsId") + .HasColumnType("int"); + + b.Property("FileNamePartsId") + .HasColumnType("int"); + + b.HasKey("FileClassificationsId", "FileNamePartsId"); + + b.HasIndex("FileNamePartsId"); + + b.ToTable("FileClassificationFileNamePart", "files"); + }); + + modelBuilder.Entity("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationId"); + }); + + modelBuilder.Entity("FileClassificationFileDetail", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileDetail", null) + .WithMany() + .HasForeignKey("FileDetailsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("FileClassificationFileNamePart", b => + { + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileClassification", null) + .WithMany() + .HasForeignKey("FileClassificationsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AStar.Dev.Infrastructure.FilesDb.Models.FileNamePart", null) + .WithMany() + .HasForeignKey("FileNamePartsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/DeletionStatus.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/DeletionStatus.cs new file mode 100644 index 0000000..cbcf9fb --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/DeletionStatus.cs @@ -0,0 +1,22 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// Defines dates/times for soft and hard deletion +/// +public class DeletionStatus +{ + /// + /// Gets or sets when the file was 'soft deleted'. I know, shocking... + /// + public DateTimeOffset? SoftDeleted { get; set; } + + /// + /// Gets or sets when the file was marked as 'soft delete pending'. I know, shocking... + /// + public DateTimeOffset? SoftDeletePending { get; set; } + + /// + /// Gets or sets when the file was marked as 'hard delete pending'. I know, shocking... + /// + public DateTimeOffset? HardDeletePending { get; set; } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/DirectoryName.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/DirectoryName.cs new file mode 100644 index 0000000..3d5af52 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/DirectoryName.cs @@ -0,0 +1,6 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +/// +public readonly record struct DirectoryName(string Value); \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/DuplicateDetail.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/DuplicateDetail.cs new file mode 100644 index 0000000..050fa83 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/DuplicateDetail.cs @@ -0,0 +1,82 @@ +using System.ComponentModel.DataAnnotations; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// The class defines the fields that will be mapped from the vw_DuplicateDetails in the database +/// +public class DuplicateDetail +{ + /// + /// Gets or sets the File Name + /// + [MaxLength(256)] + public required string FileName { get; set; } + + /// + /// Gets or sets the Directory Name + /// + [MaxLength(256)] + public required string DirectoryName { get; set; } + + /// + /// Gets or sets the File Height + /// + public int ImageHeight { get; set; } + + /// + /// Gets or sets the File Width + /// + public int ImageWidth { get; set; } + + /// + /// Gets or sets the File Size + /// + public long FileSize { get; set; } + + /// + /// Gets or sets the File Handle + /// + [MaxLength(256)] + public required string FileHandle { get; set; } + + /// + /// Gets or sets whether File is an image + /// + public bool IsImage { get; set; } + + /// + /// Gets or sets the Instance count for the duplicate group + /// + public int Instances { get; set; } + + /// + /// Gets or sets the Details Last Updated + /// + public DateTimeOffset UpdatedOn { get; set; } + + /// + /// Gets or sets the Last Viewed date + /// + public DateTimeOffset? FileLastViewed { get; set; } + + /// + /// Gets or sets the Soft Deleted flag + /// + public DateTimeOffset? SoftDeleted { get; set; } + + /// + /// Gets or sets the SoftDeletePending flag + /// + public DateTimeOffset? SoftDeletePending { get; set; } + + /// + /// Gets or sets the Move Required flag + /// + public bool MoveRequired { get; set; } + + /// + /// Gets or sets the Hard Delete Pending flag + /// + public DateTimeOffset? HardDeletePending { get; set; } +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/Event.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/Event.cs new file mode 100644 index 0000000..fea1e1e --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/Event.cs @@ -0,0 +1,57 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +#pragma warning disable CA1716 +public class Event +#pragma warning restore CA1716 +{ + /// + /// + public int Id { get; set; } + + /// + /// + public EventType Type { get; set; } = EventType.Update; + + /// + /// + public DateTimeOffset EventOccurredAt { get; set; } + + /// + /// + public string FileName { get; set; } = string.Empty; + + /// + /// + public string DirectoryName { get; set; } = string.Empty; + + /// + /// + public string Handle { get; set; } = string.Empty; + + /// + /// + public int? Width { get; set; } + + /// + /// + public int? Height { get; set; } + + /// + /// + public long FileSize { get; set; } + + /// + /// + public DateTimeOffset FileCreated { get; set; } + + /// + /// + public DateTimeOffset FileLastModified { get; set; } + + /// + /// Gets or sets the Updated By property to track who made the change + /// + public string UpdatedBy { get; set; } = "Jay Barden"; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/EventType.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/EventType.cs new file mode 100644 index 0000000..a64c947 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/EventType.cs @@ -0,0 +1,100 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// Represents a sealed class for defining distinct event types such as Add, Update, and Delete. +/// This class ensures that only predefined instances of event types can be used, +/// providing type safety and preventing the creation of arbitrary states. +/// +public sealed class EventType : IEquatable +{ + /// + /// Private constructor to prevent external instantiation. + /// This ensures that only the static readonly instances above can be created. + /// + /// The integer value representing the event type. + /// The string name of the event type. + private EventType(int value, string name) + { + Value = value; + Name = name; + } + + /// + /// Represents an 'Add' event type, typically used for new record creation. + /// + public static EventType Add => new(1, "Add"); + + /// + /// Represents an 'Update' event type, typically used for modifying existing records. + /// + public static EventType Update => new(2, "Update"); + + /// + /// Represents a 'SoftDelete' event type, typically used for 'soft' removing records. + /// + public static EventType SoftDelete => new(3, "SoftDelete"); + + /// + /// Represents a 'HardDelete' event type, typically used for permanently removing records. + /// + public static EventType HardDelete => new(4, "HardDelete"); + + /// + /// Gets the integer value associated with the event type. + /// + public int Value { get; } + + /// + /// Gets the string name of the event type. + /// + public string Name { get; } + + /// + public bool Equals(EventType? other) + { + if(other is null) + { + return false; + } + +#pragma warning disable IDE0046 + if(ReferenceEquals(this, other)) +#pragma warning restore IDE0046 + { + return true; + } + + return Value == other.Value && Name == other.Name; + } + + /// + public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (obj is EventType other && Equals(other)); + + /// + /// Returns the string name of the event type, useful for debugging and display. + /// + /// The name of the event type. + public override string ToString() => Name; + + /// + public override int GetHashCode() => HashCode.Combine(Value, Name); + + /// + /// Overloads the equality operator to compare two objects. + /// + /// The first to compare. + /// The second to compare. + /// true if the two objects are equal; otherwise, false. + public static bool operator ==(EventType left, EventType right) +#pragma warning disable IDE0041 + => left?.Equals(right) ?? ReferenceEquals(right, null); +#pragma warning restore IDE0041 + + /// + /// Overloads the inequality operator to compare two objects. + /// + /// The first to compare. + /// The second to compare. + /// true if the two objects are not equal; otherwise, false. + public static bool operator !=(EventType left, EventType right) => !(left == right); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileClassification.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileClassification.cs new file mode 100644 index 0000000..3ea40ee --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileClassification.cs @@ -0,0 +1,26 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +public class FileClassification +{ + /// + /// + public int Id { get; set; } + + /// + /// + public string Name { get; set; } = string.Empty; + + /// + /// + public ICollection FileDetails { get; set; } = []; + + /// + /// + public bool Celebrity { get; set; } + + /// + /// + public ICollection FileNameParts { get; set; } = []; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileDetail.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileDetail.cs new file mode 100644 index 0000000..39a1d90 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileDetail.cs @@ -0,0 +1,104 @@ +using System.IO.Abstractions; +using AStar.Dev.Infrastructure.Data; +using AStar.Dev.Utilities; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// The FileDetail class containing the current properties +/// +public sealed class FileDetail : AuditableEntity +{ + /// + /// The default constructor required by EF Core etc + /// + public FileDetail() + { + } + + /// + /// The copy constructor that allows for passing an instance of FileInfo to this class, simplifying consumer code + /// + /// + /// The instance of FileInfo to map + /// + public FileDetail(IFileInfo fileInfo) + { + FileName = new(fileInfo.Name); + DirectoryName = new(fileInfo.DirectoryName!); + FileSize = fileInfo.Length; + } + + /// + /// + public ICollection FileClassifications { get; set; } = []; + + /// + /// Gets or sets the ID of the . I know, shocking... + /// + public FileId Id { get; set; } + + /// + /// + public ImageDetail ImageDetail { get; set; } = new(null, null); + + /// + /// Gets or sets the file name. I know, shocking... + /// + public required FileName FileName { get; set; } + + /// + /// Gets or sets the name of the directory containing the file detail. I know, shocking... + /// + public required DirectoryName DirectoryName { get; set; } + + /// + /// Gets the full name of the file with the path combined + /// + public string FullNameWithPath => Path.Combine(DirectoryName.Value, FileName.Value ?? ""); + + /// + /// Gets or sets the file size. I know, shocking... + /// + public long FileSize { get; set; } + + /// + /// Gets or sets whether the file is of a supported image type + /// + public bool IsImage { get; set; } + + /// + /// Gets or sets the file handle. I know, shocking... + /// + public FileHandle FileHandle { get; set; } + + /// + /// + public DateTimeOffset FileCreated { get; set; } + + /// + /// + public DateTimeOffset FileLastModified { get; set; } + + /// + /// + public DateTimeOffset? FileLastViewed { get; set; } + + /// + /// Gets or sets whether the file has been marked as 'needs to move'. I know, shocking... + /// + public bool MoveRequired { get; set; } + + /// + /// Gets or sets the file deletion status. I know, shocking... + /// + public DeletionStatus DeletionStatus { get; set; } = new(); + + /// + /// Returns this object in JSON format + /// + /// + /// This object serialized as a JSON object. + /// + public override string ToString() => this.ToJson(); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileHandle.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileHandle.cs new file mode 100644 index 0000000..e800552 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileHandle.cs @@ -0,0 +1,19 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +/// +public readonly record struct FileHandle(string Value) +{ + /// + /// + /// + /// + public static FileHandle Create(string value) => string.IsNullOrWhiteSpace(value) ? throw new ArgumentException("Value cannot be null or whitespace.", nameof(value)) : new FileHandle(value); + + /// + /// + /// + /// + public static implicit operator string(FileHandle d) => d.Value; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileId.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileId.cs new file mode 100644 index 0000000..752c33f --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileId.cs @@ -0,0 +1,7 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// Defines the FileId +/// +/// The value of the File Id +public readonly record struct FileId(int Value); \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileName.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileName.cs new file mode 100644 index 0000000..b6947c7 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileName.cs @@ -0,0 +1,15 @@ +using Microsoft.EntityFrameworkCore; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +/// +[Index(nameof(Value))] +public record FileName(string Value) +{ + /// + /// + /// + public override string ToString() => Value; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileNamePart.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileNamePart.cs new file mode 100644 index 0000000..e95a32a --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileNamePart.cs @@ -0,0 +1,18 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +public class FileNamePart +{ + /// + /// + public int Id { get; set; } + + /// + /// + public string Text { get; set; } = string.Empty; + + /// + /// + public virtual ICollection FileClassifications { get; set; } = []; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSize.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSize.cs new file mode 100644 index 0000000..62cdd0f --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSize.cs @@ -0,0 +1,55 @@ +using AStar.Dev.Utilities; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +public sealed class FileSize +{ + private FileSize(long fileLength, int height, int width) + { + FileLength = fileLength; + Height = height; + Width = width; + } + + /// + /// Gets the file length property + /// + public long FileLength { get; } + + /// + /// Gets the file height property + /// + public int Height { get; } + + /// + /// Gets the file width property + /// + public int Width { get; } + + /// + /// The Create method will return a populated instance of the class + /// + /// + /// The length of the file + /// + /// + /// The height of the file if an image + /// + /// + /// The width of the file if an image + /// + /// + /// A populated instance of . + /// + public static FileSize Create(long fileLength, int height, int width) => new(fileLength, height, width); + + /// + /// Returns this object in JSON format + /// + /// + /// This object serialized as a JSON object + /// + public override string ToString() => this.ToJson(); +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSizeEqualityComparer.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSizeEqualityComparer.cs new file mode 100644 index 0000000..2d97fc9 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/FileSizeEqualityComparer.cs @@ -0,0 +1,44 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// The class that defines how the file sizes are deemed to be equal +/// +public sealed class FileSizeEqualityComparer : IEqualityComparer +{ + /// + /// The Equals method has been overridden to perform the equality check currently required. The equality check is for + /// Height, Width and Length - making this more of an ImageComparer... + /// + /// + /// An instance of the class to compare + /// + /// + /// The other instance of the class to compare + /// + /// + /// true if the files are deemed to be the same size, false otherwise + /// + public bool Equals(FileSize? leftFileSize, FileSize? rightFileSize) + => (rightFileSize == null && leftFileSize == null) + || CompareFileSizes(leftFileSize, rightFileSize); + + /// + /// The GetHashCode has been overridden to return the hash-codes as per the fields compared in the overridden Equals + /// method + /// + /// + /// The to calculate the appropriate hash-code for + /// + /// + /// The hash-code, combined from the relevant properties own hash-codes + /// + public int GetHashCode(FileSize fileSize) + => HashCode.Combine(fileSize.Height, fileSize.Width, fileSize.FileLength); + + private static bool CompareFileSizes(FileSize? leftFileSize, FileSize? rightFileSize) + => leftFileSize != null + && rightFileSize != null + && leftFileSize.Height == rightFileSize.Height + && leftFileSize.FileLength == rightFileSize.FileLength + && leftFileSize.Width == rightFileSize.Width; +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/IFileDetail.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/IFileDetail.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/ImageDetail.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/ImageDetail.cs new file mode 100644 index 0000000..4ba1d24 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/ImageDetail.cs @@ -0,0 +1,8 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// +[ComplexType] +public record ImageDetail(int? Width, int? Height); \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/SearchType.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/SearchType.cs new file mode 100644 index 0000000..57e1452 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/SearchType.cs @@ -0,0 +1,27 @@ +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// The enumeration defining the available search types +/// +public enum SearchType +{ + /// + /// Search for images only + /// + Images, + + /// + /// Search for all file types + /// + All, + + /// + /// Search for duplicates - file type is ignored + /// + Duplicates, + + /// + /// Search for duplicate images + /// + DuplicateImages +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Models/SortOrder.cs b/src/AStar.Dev.Infrastructure.FilesDb/Models/SortOrder.cs new file mode 100644 index 0000000..dedb20b --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Models/SortOrder.cs @@ -0,0 +1,30 @@ +using AStar.Dev.Technical.Debt.Reporting; + +namespace AStar.Dev.Infrastructure.FilesDb.Models; + +/// +/// The currently supported SortOrders +/// +[Refactor(1, 1, "I think this is now duplicated too")] +public enum SortOrder +{ + /// + /// Order by the size descending + /// + SizeDescending, + + /// + /// Order by the size ascending + /// + SizeAscending, + + /// + /// Order by the name descending + /// + NameDescending, + + /// + /// Order by the name ascending + /// + NameAscending +} \ No newline at end of file diff --git a/src/AStar.Dev.Infrastructure.FilesDb/Readme.md b/src/AStar.Dev.Infrastructure.FilesDb/Readme.md new file mode 100644 index 0000000..bbfca68 --- /dev/null +++ b/src/AStar.Dev.Infrastructure.FilesDb/Readme.md @@ -0,0 +1,7 @@ +# Infrastructure - FilesDb Notes + +# Run from Infrastructure FilesDb directory + +dotnet ef migrations add "InitialCreation" --startup-project "../../apis/AStar.Dev.Files.Api/AStar.Dev.Files.Api.csproj" + +To apply, simply run the solution - migrations are automatically applied via the migrations project :-) diff --git a/src/AStar.Dev.Infrastructure.FilesDb/astar.ico b/src/AStar.Dev.Infrastructure.FilesDb/astar.ico new file mode 100644 index 0000000000000000000000000000000000000000..38b6709a751659db6d84ef77d794c46015e49f91 GIT binary patch literal 16958 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 literal 0 HcmV?d00001 diff --git a/test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/AStar.Dev.Infrastructure.FilesDb.Tests.Unit.csproj b/test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/AStar.Dev.Infrastructure.FilesDb.Tests.Unit.csproj new file mode 100644 index 0000000..e23157b --- /dev/null +++ b/test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/AStar.Dev.Infrastructure.FilesDb.Tests.Unit.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + diff --git a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs b/test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/UnitTest1.cs similarity index 55% rename from test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs rename to test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/UnitTest1.cs index 3928e91..7e520c3 100644 --- a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/UnitTest1.cs +++ b/test/AStar.Dev.Infrastructure.FilesDb.Tests.Unit/UnitTest1.cs @@ -1,10 +1,9 @@ -namespace AStar.Dev.Example.ClassLib.Tests.Unit; +namespace AStar.Dev.Infrastructure.FilesDb.Tests.Unit; public class UnitTest1 { [Fact] public void Test1() { - } -} +} \ No newline at end of file diff --git a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj b/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj deleted file mode 100644 index 6fbda4a..0000000 --- a/test/unit/AStar.Dev.Example.ClassLib.Tests.Unit/AStar.Dev.Example.ClassLib.Tests.Unit.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - net9.0 - enable - enable - false - - - - - - - - - - - - - - - - - -