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 0000000..38b6709
Binary files /dev/null and b/astar.ico differ
diff --git a/astar.png b/astar.png
new file mode 100644
index 0000000..74b197e
Binary files /dev/null and b/astar.png differ
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