From 64ac46007346441df35a8aa622b088216d03424d Mon Sep 17 00:00:00 2001 From: Paul Irwin Date: Thu, 11 Jan 2024 15:12:54 -0700 Subject: [PATCH] .NET 8 upgrade and convert to primary ctors (#9) * .NET 8 upgrade and convert to primary ctors * Use .NET 8 in build pipeline --- .github/workflows/dotnet.yml | 2 +- .../AzureSearchEmulator.csproj | 8 ++--- .../Controllers/DocumentIndexingController.cs | 27 ++++++---------- .../DocumentSearchingController.cs | 31 +++++++------------ .../Controllers/IndexesController.cs | 29 +++++++---------- AzureSearchEmulator/EmulatorOptions.cs | 4 +-- .../Indexing/DeleteIndexDocumentAction.cs | 9 ++---- .../Indexing/DocumentNotFoundException.cs | 8 +---- .../Indexing/IndexDocumentAction.cs | 11 ++----- .../Indexing/IndexingContext.cs | 24 +++++--------- .../Indexing/IndexingResult.cs | 24 +++++--------- .../Indexing/LuceneNetSearchIndexer.cs | 20 +++++------- .../Indexing/MergeIndexDocumentAction.cs | 12 ++----- .../MergeOrUploadIndexDocumentAction.cs | 13 ++------ .../Indexing/UploadIndexDocumentAction.cs | 13 ++------ .../Indexing/UpsertIndexDocumentActionBase.cs | 11 ++----- AzureSearchEmulator/Models/SearchField.cs | 22 ++++++------- AzureSearchEmulator/Models/SearchIndex.cs | 23 ++++++-------- .../Models/SearchIndexExistsException.cs | 8 +---- .../Repositories/FileSearchIndexRepository.cs | 24 ++++++-------- .../Repositories/ISearchIndexRepository.cs | 4 +-- .../SearchData/AnalyzerHelper.cs | 4 +-- .../LuceneDirectoryReaderFactory.cs | 13 ++------ .../SearchData/SimpleFSDirectoryFactory.cs | 11 ++----- .../Searching/HighlightField.cs | 2 +- .../Searching/IIndexSearcher.cs | 6 ++-- .../Searching/LuceneNetIndexSearcher.cs | 15 +++------ .../Searching/ODataQueryVisitor.cs | 20 +++++++----- AzureSearchEmulator/Startup.cs | 11 ++----- Dockerfile | 4 +-- 30 files changed, 144 insertions(+), 269 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 61bf576..7d3ca05 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Restore dependencies run: dotnet restore - name: Build diff --git a/AzureSearchEmulator/AzureSearchEmulator.csproj b/AzureSearchEmulator/AzureSearchEmulator.csproj index 818420e..5807116 100644 --- a/AzureSearchEmulator/AzureSearchEmulator.csproj +++ b/AzureSearchEmulator/AzureSearchEmulator.csproj @@ -1,9 +1,8 @@  - net6.0 + net8.0 6751dc28-24d4-4572-8f44-e652593dd678 - Linux enable enable 0.0.1 @@ -16,8 +15,7 @@ - - + @@ -30,4 +28,4 @@ - \ No newline at end of file + diff --git a/AzureSearchEmulator/Controllers/DocumentIndexingController.cs b/AzureSearchEmulator/Controllers/DocumentIndexingController.cs index c6fa05c..fee1931 100644 --- a/AzureSearchEmulator/Controllers/DocumentIndexingController.cs +++ b/AzureSearchEmulator/Controllers/DocumentIndexingController.cs @@ -7,27 +7,18 @@ namespace AzureSearchEmulator.Controllers; -public class DocumentIndexingController : ODataController +public class DocumentIndexingController( + JsonSerializerOptions jsonSerializerOptions, + ISearchIndexRepository searchIndexRepository, + ISearchIndexer searchIndexer) + : ODataController { - private readonly JsonSerializerOptions _jsonSerializerOptions; - private readonly ISearchIndexRepository _searchIndexRepository; - private readonly ISearchIndexer _searchIndexer; - - public DocumentIndexingController(JsonSerializerOptions jsonSerializerOptions, - ISearchIndexRepository searchIndexRepository, - ISearchIndexer searchIndexer) - { - _jsonSerializerOptions = jsonSerializerOptions; - _searchIndexRepository = searchIndexRepository; - _searchIndexer = searchIndexer; - } - [HttpPost] [Route("indexes('{indexKey}')/docs/search.index")] [Route("indexes/{indexKey}/docs/search.index")] public async Task IndexDocuments(string indexKey) { - var index = await _searchIndexRepository.Get(indexKey); + var index = await searchIndexRepository.Get(indexKey); if (index == null) { @@ -36,7 +27,7 @@ public async Task IndexDocuments(string indexKey) using var sr = new StreamReader(Request.Body); var json = await sr.ReadToEndAsync(); - var batch = JsonSerializer.Deserialize(json, _jsonSerializerOptions); + var batch = JsonSerializer.Deserialize(json, jsonSerializerOptions); if (batch == null) { @@ -69,8 +60,8 @@ public async Task IndexDocuments(string indexKey) itemIndex++; } - var result = _searchIndexer.IndexDocuments(index, actions); + var result = searchIndexer.IndexDocuments(index, actions); return StatusCode(result.Value.Any(i => !i.Status) ? 207 : 200, result); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Controllers/DocumentSearchingController.cs b/AzureSearchEmulator/Controllers/DocumentSearchingController.cs index d57da1a..750bac9 100644 --- a/AzureSearchEmulator/Controllers/DocumentSearchingController.cs +++ b/AzureSearchEmulator/Controllers/DocumentSearchingController.cs @@ -7,32 +7,25 @@ namespace AzureSearchEmulator.Controllers; -public class DocumentSearchingController : ODataController +public class DocumentSearchingController( + IIndexSearcher indexSearcher, + ISearchIndexRepository searchIndexRepository) + : ODataController { - private readonly IIndexSearcher _indexSearcher; - private readonly ISearchIndexRepository _searchIndexRepository; - - public DocumentSearchingController(IIndexSearcher indexSearcher, - ISearchIndexRepository searchIndexRepository) - { - _indexSearcher = indexSearcher; - _searchIndexRepository = searchIndexRepository; - } - [HttpGet] [Route("indexes/{indexKey}/docs/$count")] [Route("indexes/({indexKey})/docs/$count")] public async Task GetDocumentCount(string indexKey) { - var index = await _searchIndexRepository.Get(indexKey); + var index = await searchIndexRepository.Get(indexKey); if (index == null) { return NotFound(); } - var count = await _indexSearcher.GetDocCount(index); - + var count = await indexSearcher.GetDocCount(index); + return Ok(count); } @@ -42,14 +35,14 @@ public async Task GetDocumentCount(string indexKey) [EnableQuery] public async Task GetDocument(string indexKey, string key) { - var index = await _searchIndexRepository.Get(indexKey); + var index = await searchIndexRepository.Get(indexKey); if (index == null) { return NotFound(); } - var doc = await _indexSearcher.GetDoc(index, key); + var doc = await indexSearcher.GetDoc(index, key); if (doc == null) { @@ -120,14 +113,14 @@ public async Task SearchPost(string indexKey, [FromBody] SearchRe return BadRequest(ModelState); } - var index = await _searchIndexRepository.Get(indexKey); + var index = await searchIndexRepository.Get(indexKey); if (index == null) { return NotFound(); } - var response = await _indexSearcher.Search(index, request); + var response = await indexSearcher.Search(index, request); var oDataResponse = new JsonObject(); @@ -140,4 +133,4 @@ public async Task SearchPost(string indexKey, [FromBody] SearchRe return Ok(oDataResponse); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Controllers/IndexesController.cs b/AzureSearchEmulator/Controllers/IndexesController.cs index 69757bd..3e1c319 100644 --- a/AzureSearchEmulator/Controllers/IndexesController.cs +++ b/AzureSearchEmulator/Controllers/IndexesController.cs @@ -7,24 +7,17 @@ namespace AzureSearchEmulator.Controllers; -public class IndexesController : ODataController +public class IndexesController( + JsonSerializerOptions jsonSerializerOptions, + ISearchIndexRepository searchIndexRepository) + : ODataController { - private readonly JsonSerializerOptions _jsonSerializerOptions; - private readonly ISearchIndexRepository _searchIndexRepository; - - public IndexesController(JsonSerializerOptions jsonSerializerOptions, - ISearchIndexRepository searchIndexRepository) - { - _jsonSerializerOptions = jsonSerializerOptions; - _searchIndexRepository = searchIndexRepository; - } - [HttpGet] [EnableQuery] [Route("indexes")] public IAsyncEnumerable Get() { - return _searchIndexRepository.GetAll(); + return searchIndexRepository.GetAll(); } [HttpGet] @@ -32,7 +25,7 @@ public IAsyncEnumerable Get() [Route("indexes/{key}")] public async Task Get(string key) { - var index = await _searchIndexRepository.Get(key); + var index = await searchIndexRepository.Get(key); if (index == null) { @@ -49,7 +42,7 @@ public async Task Post() //([FromBody] SearchIndex? index) // HACK.PI: For some reason, having this as a parameter with [FromBody] fails to deserialize properly. using var sr = new StreamReader(Request.Body); var indexJson = await sr.ReadToEndAsync(); - var index = JsonSerializer.Deserialize(indexJson, _jsonSerializerOptions); + var index = JsonSerializer.Deserialize(indexJson, jsonSerializerOptions); if (index == null || !ModelState.IsValid) { @@ -58,7 +51,7 @@ public async Task Post() //([FromBody] SearchIndex? index) try { - await _searchIndexRepository.Create(index); + await searchIndexRepository.Create(index); } catch (SearchIndexExistsException) { @@ -73,15 +66,15 @@ public async Task Post() //([FromBody] SearchIndex? index) [Route("indexes/{key}")] public async Task Delete(string key) { - var index = await _searchIndexRepository.Get(key); + var index = await searchIndexRepository.Get(key); if (index == null) { return NotFound(); } - await _searchIndexRepository.Delete(index); + await searchIndexRepository.Delete(index); return NoContent(); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/EmulatorOptions.cs b/AzureSearchEmulator/EmulatorOptions.cs index d05e826..6c08855 100644 --- a/AzureSearchEmulator/EmulatorOptions.cs +++ b/AzureSearchEmulator/EmulatorOptions.cs @@ -2,5 +2,5 @@ public class EmulatorOptions { - public string IndexesDirectory { get; set; } = ""; -} \ No newline at end of file + public string IndexesDirectory { get; init; } = ""; +} diff --git a/AzureSearchEmulator/Indexing/DeleteIndexDocumentAction.cs b/AzureSearchEmulator/Indexing/DeleteIndexDocumentAction.cs index 5c77bb9..dda1de6 100644 --- a/AzureSearchEmulator/Indexing/DeleteIndexDocumentAction.cs +++ b/AzureSearchEmulator/Indexing/DeleteIndexDocumentAction.cs @@ -2,13 +2,8 @@ namespace AzureSearchEmulator.Indexing; -public class DeleteIndexDocumentAction : IndexDocumentAction +public class DeleteIndexDocumentAction(JsonObject item) : IndexDocumentAction(item) { - public DeleteIndexDocumentAction(JsonObject item) - : base(item) - { - } - public override IndexingResult PerformIndexingAsync(IndexingContext context) { var keyTerm = GetKeyTerm(context.Key); @@ -17,4 +12,4 @@ public override IndexingResult PerformIndexingAsync(IndexingContext context) return new IndexingResult(keyTerm.Text, true, 200); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Indexing/DocumentNotFoundException.cs b/AzureSearchEmulator/Indexing/DocumentNotFoundException.cs index 3a59447..70a9656 100644 --- a/AzureSearchEmulator/Indexing/DocumentNotFoundException.cs +++ b/AzureSearchEmulator/Indexing/DocumentNotFoundException.cs @@ -1,9 +1,3 @@ namespace AzureSearchEmulator.Indexing; -public class DocumentNotFoundException : Exception -{ - public DocumentNotFoundException() - : base("The specified document was not found") - { - } -} \ No newline at end of file +public class DocumentNotFoundException() : Exception("The specified document was not found"); diff --git a/AzureSearchEmulator/Indexing/IndexDocumentAction.cs b/AzureSearchEmulator/Indexing/IndexDocumentAction.cs index 1af9904..43c429c 100644 --- a/AzureSearchEmulator/Indexing/IndexDocumentAction.cs +++ b/AzureSearchEmulator/Indexing/IndexDocumentAction.cs @@ -4,14 +4,9 @@ namespace AzureSearchEmulator.Indexing; -public abstract class IndexDocumentAction +public abstract class IndexDocumentAction(JsonObject item) { - protected IndexDocumentAction(JsonObject item) - { - Item = item; - } - - public JsonObject Item { get; } + public JsonObject Item { get; } = item; protected Term GetKeyTerm(SearchField key) { @@ -26,4 +21,4 @@ protected Term GetKeyTerm(SearchField key) } public abstract IndexingResult PerformIndexingAsync(IndexingContext context); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Indexing/IndexingContext.cs b/AzureSearchEmulator/Indexing/IndexingContext.cs index ffed0e7..d210549 100644 --- a/AzureSearchEmulator/Indexing/IndexingContext.cs +++ b/AzureSearchEmulator/Indexing/IndexingContext.cs @@ -3,21 +3,13 @@ namespace AzureSearchEmulator.Indexing; -public class IndexingContext +public class IndexingContext(SearchIndex index, SearchField key, IndexWriter writer, Lazy reader) { - public IndexingContext(SearchIndex index, SearchField key, IndexWriter writer, Lazy reader) - { - Index = index; - Key = key; - Writer = writer; - Reader = reader; - } + public SearchIndex Index { get; } = index; - public SearchIndex Index { get; } - - public SearchField Key { get; } - - public IndexWriter Writer { get; } - - public Lazy Reader { get; } -} \ No newline at end of file + public SearchField Key { get; } = key; + + public IndexWriter Writer { get; } = writer; + + public Lazy Reader { get; } = reader; +} diff --git a/AzureSearchEmulator/Indexing/IndexingResult.cs b/AzureSearchEmulator/Indexing/IndexingResult.cs index 628a56b..58bb85b 100644 --- a/AzureSearchEmulator/Indexing/IndexingResult.cs +++ b/AzureSearchEmulator/Indexing/IndexingResult.cs @@ -1,27 +1,17 @@ namespace AzureSearchEmulator.Indexing; -public class IndexingResult +public class IndexingResult(string key, string? errorMessage, bool status, int statusCode) { public IndexingResult(string key, bool status, int statusCode) + : this(key, null, status, statusCode) { - Key = key; - Status = status; - StatusCode = statusCode; } - public IndexingResult(string key, string? errorMessage, bool status, int statusCode) - { - Key = key; - ErrorMessage = errorMessage; - Status = status; - StatusCode = statusCode; - } - - public string Key { get; } + public string Key { get; } = key; - public string? ErrorMessage { get; } + public string? ErrorMessage { get; } = errorMessage; - public bool Status { get; } + public bool Status { get; } = status; - public int StatusCode { get; } -} \ No newline at end of file + public int StatusCode { get; } = statusCode; +} diff --git a/AzureSearchEmulator/Indexing/LuceneNetSearchIndexer.cs b/AzureSearchEmulator/Indexing/LuceneNetSearchIndexer.cs index 844cd29..24c515e 100644 --- a/AzureSearchEmulator/Indexing/LuceneNetSearchIndexer.cs +++ b/AzureSearchEmulator/Indexing/LuceneNetSearchIndexer.cs @@ -5,24 +5,18 @@ namespace AzureSearchEmulator.Indexing; -public class LuceneNetSearchIndexer : ISearchIndexer +public class LuceneNetSearchIndexer( + ILuceneDirectoryFactory luceneDirectoryFactory, + ILuceneIndexReaderFactory luceneIndexReaderFactory) + : ISearchIndexer { - private readonly ILuceneDirectoryFactory _luceneDirectoryFactory; - private readonly ILuceneIndexReaderFactory _luceneIndexReaderFactory; - - public LuceneNetSearchIndexer(ILuceneDirectoryFactory luceneDirectoryFactory, ILuceneIndexReaderFactory luceneIndexReaderFactory) - { - _luceneDirectoryFactory = luceneDirectoryFactory; - _luceneIndexReaderFactory = luceneIndexReaderFactory; - } - public IndexDocumentsResult IndexDocuments(SearchIndex index, IList actions) { var analyzer = AnalyzerHelper.GetPerFieldIndexAnalyzer(index.Fields); var config = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer); - var directory = _luceneDirectoryFactory.GetDirectory(index.Name); + var directory = luceneDirectoryFactory.GetDirectory(index.Name); using var writer = new IndexWriter(directory, config); var key = index.GetKeyField(); @@ -49,8 +43,8 @@ public IndexDocumentsResult IndexDocuments(SearchIndex index, IList docFields) - { - MergeDocument(context, keyTerm, docFields, false); - } -} \ No newline at end of file + => MergeDocument(context, keyTerm, docFields, false); +} diff --git a/AzureSearchEmulator/Indexing/MergeOrUploadIndexDocumentAction.cs b/AzureSearchEmulator/Indexing/MergeOrUploadIndexDocumentAction.cs index 9ab45a4..48ca556 100644 --- a/AzureSearchEmulator/Indexing/MergeOrUploadIndexDocumentAction.cs +++ b/AzureSearchEmulator/Indexing/MergeOrUploadIndexDocumentAction.cs @@ -3,15 +3,8 @@ namespace AzureSearchEmulator.Indexing; -public class MergeOrUploadIndexDocumentAction : UpsertIndexDocumentActionBase +public class MergeOrUploadIndexDocumentAction(JsonObject item) : UpsertIndexDocumentActionBase(item) { - public MergeOrUploadIndexDocumentAction(JsonObject item) - : base(item) - { - } - protected override void IndexDocument(IndexingContext context, Term keyTerm, IEnumerable docFields) - { - MergeDocument(context, keyTerm, docFields, true); - } -} \ No newline at end of file + => MergeDocument(context, keyTerm, docFields, true); +} diff --git a/AzureSearchEmulator/Indexing/UploadIndexDocumentAction.cs b/AzureSearchEmulator/Indexing/UploadIndexDocumentAction.cs index c495cb8..21da125 100644 --- a/AzureSearchEmulator/Indexing/UploadIndexDocumentAction.cs +++ b/AzureSearchEmulator/Indexing/UploadIndexDocumentAction.cs @@ -3,15 +3,8 @@ namespace AzureSearchEmulator.Indexing; -public class UploadIndexDocumentAction : UpsertIndexDocumentActionBase +public class UploadIndexDocumentAction(JsonObject item) : UpsertIndexDocumentActionBase(item) { - public UploadIndexDocumentAction(JsonObject item) - : base(item) - { - } - protected override void IndexDocument(IndexingContext context, Term keyTerm, IEnumerable docFields) - { - context.Writer.UpdateDocument(keyTerm, docFields); - } -} \ No newline at end of file + => context.Writer.UpdateDocument(keyTerm, docFields); +} diff --git a/AzureSearchEmulator/Indexing/UpsertIndexDocumentActionBase.cs b/AzureSearchEmulator/Indexing/UpsertIndexDocumentActionBase.cs index c26c487..87ef2ae 100644 --- a/AzureSearchEmulator/Indexing/UpsertIndexDocumentActionBase.cs +++ b/AzureSearchEmulator/Indexing/UpsertIndexDocumentActionBase.cs @@ -6,13 +6,8 @@ namespace AzureSearchEmulator.Indexing; -public abstract class UpsertIndexDocumentActionBase : IndexDocumentAction +public abstract class UpsertIndexDocumentActionBase(JsonObject item) : IndexDocumentAction(item) { - protected UpsertIndexDocumentActionBase(JsonObject item) - : base(item) - { - } - public override IndexingResult PerformIndexingAsync(IndexingContext context) { var keyTerm = GetKeyTerm(context.Key); @@ -41,7 +36,7 @@ join v in Item on f.Name equals v.Key select f.CreateField(v.Value); } - protected void MergeDocument(IndexingContext context, Term keyTerm, IEnumerable docFields, bool uploadIfMissing) + protected static void MergeDocument(IndexingContext context, Term keyTerm, IEnumerable docFields, bool uploadIfMissing) { var reader = context.Reader.Value; var searcher = new IndexSearcher(reader); @@ -71,4 +66,4 @@ protected void MergeDocument(IndexingContext context, Term keyTerm, IEnumerable< } protected abstract void IndexDocument(IndexingContext context, Term keyTerm, IEnumerable docFields); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Models/SearchField.cs b/AzureSearchEmulator/Models/SearchField.cs index 633a4ff..6282750 100644 --- a/AzureSearchEmulator/Models/SearchField.cs +++ b/AzureSearchEmulator/Models/SearchField.cs @@ -6,10 +6,10 @@ public class SearchField { [Required] public string Name { get; set; } = ""; - + [Required] public string Type { get; set; } = ""; - + public bool? Searchable { get; set; } public bool Filterable { get; set; } = true; @@ -21,20 +21,20 @@ public bool Hidden } public bool Retrievable { get; set; } = true; - + public bool? Sortable { get; set; } - + public bool? Facetable { get; set; } - + public bool? Key { get; set; } - + public string? Analyzer { get; set; } - + public string? SearchAnalyzer { get; set; } - + public string? IndexAnalyzer { get; set; } - + public IList SynonymMaps { get; set; } = new List(); - + public IList Fields { get; } = new List(); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Models/SearchIndex.cs b/AzureSearchEmulator/Models/SearchIndex.cs index 7bb1777..772b00f 100644 --- a/AzureSearchEmulator/Models/SearchIndex.cs +++ b/AzureSearchEmulator/Models/SearchIndex.cs @@ -2,24 +2,19 @@ public class SearchIndex { - public string Name { get; set; } = ""; - - public IList Fields { get; set; } = new List(); + public string Name { get; init; } = ""; + + public IList Fields { get; init; } = new List(); public SearchField GetKeyField() { var keys = Fields.Where(i => i.Key.GetValueOrDefault()).ToList(); - if (keys.Count == 0) - { - throw new InvalidOperationException("Index does not have a configured key"); - } - - if (keys.Count > 1) + return keys.Count switch { - throw new InvalidOperationException("Index has more than one configured key"); - } - - return keys[0]; + 0 => throw new InvalidOperationException("Index does not have a configured key"), + > 1 => throw new InvalidOperationException("Index has more than one configured key"), + _ => keys[0] + }; } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Models/SearchIndexExistsException.cs b/AzureSearchEmulator/Models/SearchIndexExistsException.cs index 2a1ebb9..a8c4fdc 100644 --- a/AzureSearchEmulator/Models/SearchIndexExistsException.cs +++ b/AzureSearchEmulator/Models/SearchIndexExistsException.cs @@ -1,9 +1,3 @@ namespace AzureSearchEmulator.Models; -public class SearchIndexExistsException : Exception -{ - public SearchIndexExistsException(string indexKey) - : base($"Index with key {indexKey} already exists") - { - } -} \ No newline at end of file +public class SearchIndexExistsException(string indexKey) : Exception($"Index with key {indexKey} already exists"); diff --git a/AzureSearchEmulator/Repositories/FileSearchIndexRepository.cs b/AzureSearchEmulator/Repositories/FileSearchIndexRepository.cs index e0b6a26..29a7899 100644 --- a/AzureSearchEmulator/Repositories/FileSearchIndexRepository.cs +++ b/AzureSearchEmulator/Repositories/FileSearchIndexRepository.cs @@ -5,16 +5,10 @@ namespace AzureSearchEmulator.Repositories; -public class FileSearchIndexRepository : ISearchIndexRepository +public class FileSearchIndexRepository(JsonSerializerOptions jsonSerializerOptions, IOptions options) + : ISearchIndexRepository { - private readonly JsonSerializerOptions _jsonSerializerOptions; - private readonly EmulatorOptions _options; - - public FileSearchIndexRepository(JsonSerializerOptions jsonSerializerOptions, IOptions options) - { - _jsonSerializerOptions = jsonSerializerOptions; - _options = options.Value; - } + private readonly EmulatorOptions _options = options.Value; public async IAsyncEnumerable GetAll() { @@ -27,7 +21,7 @@ public async IAsyncEnumerable GetAll() foreach (var file in files) { - yield return JsonSerializer.Deserialize(await ReadAllTextAsync(file), _jsonSerializerOptions) + yield return JsonSerializer.Deserialize(await ReadAllTextAsync(file), jsonSerializerOptions) ?? throw new InvalidOperationException($"Invalid search index definition file: {file}"); } } @@ -46,10 +40,10 @@ public async IAsyncEnumerable GetAll() return null; } - return JsonSerializer.Deserialize(await ReadAllTextAsync(file), _jsonSerializerOptions); + return JsonSerializer.Deserialize(await ReadAllTextAsync(file), jsonSerializerOptions); } - public async Task Create(SearchIndex index) + public Task Create(SearchIndex index) { if (!Directory.Exists(_options.IndexesDirectory)) { @@ -63,9 +57,9 @@ public async Task Create(SearchIndex index) throw new SearchIndexExistsException(index.Name); } - string json = JsonSerializer.Serialize(index, _jsonSerializerOptions); + string json = JsonSerializer.Serialize(index, jsonSerializerOptions); - await WriteAllTextAsync(file, json); + return WriteAllTextAsync(file, json); } public Task Delete(SearchIndex index) @@ -105,4 +99,4 @@ private string GetIndexFileName(string key) } private string GetIndexFolderName(string key) => Path.Combine(_options.IndexesDirectory, key.ToLowerInvariant()); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Repositories/ISearchIndexRepository.cs b/AzureSearchEmulator/Repositories/ISearchIndexRepository.cs index 5fee104..20b2c6f 100644 --- a/AzureSearchEmulator/Repositories/ISearchIndexRepository.cs +++ b/AzureSearchEmulator/Repositories/ISearchIndexRepository.cs @@ -9,6 +9,6 @@ public interface ISearchIndexRepository Task Get(string key); Task Create(SearchIndex index); - + Task Delete(SearchIndex index); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/SearchData/AnalyzerHelper.cs b/AzureSearchEmulator/SearchData/AnalyzerHelper.cs index 0724323..002cb64 100644 --- a/AzureSearchEmulator/SearchData/AnalyzerHelper.cs +++ b/AzureSearchEmulator/SearchData/AnalyzerHelper.cs @@ -88,7 +88,7 @@ public static Analyzer GetPerFieldSearchAnalyzer(IList fields) .Select(i => (i.Name, Analyzer: i.SearchAnalyzer ?? i.Analyzer)) .Where(i => i.Analyzer != null) .ToDictionary(i => i.Name, i => GetAnalyzer(i.Analyzer)); - + return new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version), analyzers); } @@ -101,4 +101,4 @@ public static Analyzer GetPerFieldIndexAnalyzer(IList fields) return new PerFieldAnalyzerWrapper(new StandardAnalyzer(Version), analyzers); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/SearchData/LuceneDirectoryReaderFactory.cs b/AzureSearchEmulator/SearchData/LuceneDirectoryReaderFactory.cs index 7a29a3b..0771fbe 100644 --- a/AzureSearchEmulator/SearchData/LuceneDirectoryReaderFactory.cs +++ b/AzureSearchEmulator/SearchData/LuceneDirectoryReaderFactory.cs @@ -3,17 +3,10 @@ namespace AzureSearchEmulator.SearchData; -public class LuceneDirectoryReaderFactory : ILuceneIndexReaderFactory +public class LuceneDirectoryReaderFactory(ILuceneDirectoryFactory luceneDirectoryFactory) : ILuceneIndexReaderFactory { - private readonly ILuceneDirectoryFactory _luceneDirectoryFactory; - private readonly IDictionary _indexReaders = new ConcurrentDictionary(); - public LuceneDirectoryReaderFactory(ILuceneDirectoryFactory luceneDirectoryFactory) - { - _luceneDirectoryFactory = luceneDirectoryFactory; - } - public IndexReader GetIndexReader(string indexName) { indexName = indexName.ToLowerInvariant(); @@ -30,7 +23,7 @@ public IndexReader GetIndexReader(string indexName) public IndexReader RefreshReader(string indexName) { - var directory = _luceneDirectoryFactory.GetDirectory(indexName); + var directory = luceneDirectoryFactory.GetDirectory(indexName); var reader = DirectoryReader.Open(directory); @@ -38,4 +31,4 @@ public IndexReader RefreshReader(string indexName) return reader; } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/SearchData/SimpleFSDirectoryFactory.cs b/AzureSearchEmulator/SearchData/SimpleFSDirectoryFactory.cs index b9879ec..bc8e057 100644 --- a/AzureSearchEmulator/SearchData/SimpleFSDirectoryFactory.cs +++ b/AzureSearchEmulator/SearchData/SimpleFSDirectoryFactory.cs @@ -5,17 +5,12 @@ namespace AzureSearchEmulator.SearchData; -public class SimpleFSDirectoryFactory : ILuceneDirectoryFactory +public class SimpleFSDirectoryFactory(IOptions options) : ILuceneDirectoryFactory { - private readonly EmulatorOptions _options; + private readonly EmulatorOptions _options = options.Value; private readonly IDictionary _directories = new ConcurrentDictionary(); - public SimpleFSDirectoryFactory(IOptions options) - { - _options = options.Value; - } - public Directory GetDirectory(string indexName) { indexName = indexName.ToLowerInvariant(); @@ -33,4 +28,4 @@ public Directory GetDirectory(string indexName) return directory; } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Searching/HighlightField.cs b/AzureSearchEmulator/Searching/HighlightField.cs index 9fb1c9f..6a85eb6 100644 --- a/AzureSearchEmulator/Searching/HighlightField.cs +++ b/AzureSearchEmulator/Searching/HighlightField.cs @@ -2,4 +2,4 @@ namespace AzureSearchEmulator.Searching; -public record HighlightField(SearchField Field, int MaxHighlights); \ No newline at end of file +public record HighlightField(SearchField Field, int MaxHighlights); diff --git a/AzureSearchEmulator/Searching/IIndexSearcher.cs b/AzureSearchEmulator/Searching/IIndexSearcher.cs index 7a41f9a..0153e7c 100644 --- a/AzureSearchEmulator/Searching/IIndexSearcher.cs +++ b/AzureSearchEmulator/Searching/IIndexSearcher.cs @@ -6,8 +6,8 @@ namespace AzureSearchEmulator.Searching; public interface IIndexSearcher { Task GetDoc(SearchIndex index, string docKey); - + Task GetDocCount(SearchIndex index); - + Task Search(SearchIndex index, SearchRequest request); -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Searching/LuceneNetIndexSearcher.cs b/AzureSearchEmulator/Searching/LuceneNetIndexSearcher.cs index 7ed1f23..e8d30ed 100644 --- a/AzureSearchEmulator/Searching/LuceneNetIndexSearcher.cs +++ b/AzureSearchEmulator/Searching/LuceneNetIndexSearcher.cs @@ -12,15 +12,8 @@ namespace AzureSearchEmulator.Searching; -public class LuceneNetIndexSearcher : IIndexSearcher +public class LuceneNetIndexSearcher(ILuceneIndexReaderFactory indexReaderFactory) : IIndexSearcher { - private readonly ILuceneIndexReaderFactory _indexReaderFactory; - - public LuceneNetIndexSearcher(ILuceneIndexReaderFactory indexReaderFactory) - { - _indexReaderFactory = indexReaderFactory; - } - public Task GetDoc(SearchIndex index, string key) { var searcher = GetSearcher(index); @@ -43,7 +36,7 @@ public LuceneNetIndexSearcher(ILuceneIndexReaderFactory indexReaderFactory) public Task GetDocCount(SearchIndex index) { - var reader = _indexReaderFactory.GetIndexReader(index.Name); + var reader = indexReaderFactory.GetIndexReader(index.Name); return Task.FromResult(reader.NumDocs); } @@ -354,8 +347,8 @@ private static JsonObject ConvertSearchDoc(SearchIndex index, Lucene.Net.Documen private IndexSearcher GetSearcher(SearchIndex index) { - var reader = _indexReaderFactory.GetIndexReader(index.Name); + var reader = indexReaderFactory.GetIndexReader(index.Name); return new IndexSearcher(reader); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Searching/ODataQueryVisitor.cs b/AzureSearchEmulator/Searching/ODataQueryVisitor.cs index 4e31596..d521fc2 100644 --- a/AzureSearchEmulator/Searching/ODataQueryVisitor.cs +++ b/AzureSearchEmulator/Searching/ODataQueryVisitor.cs @@ -35,9 +35,12 @@ public Query Visit(BinaryOperatorToken tokenIn) }; } - if (tokenIn.Left is EndPathToken { Identifier: string path } - && tokenIn.OperatorKind == BinaryOperatorKind.Equal - && tokenIn.Right is LiteralToken literalToken) + if (tokenIn is + { + Left: EndPathToken { Identifier: string path }, + OperatorKind: BinaryOperatorKind.Equal, + Right: LiteralToken literalToken + }) { return literalToken.Value switch { @@ -71,8 +74,11 @@ public Query Visit(CountSegmentToken tokenIn) public Query Visit(InToken tokenIn) { - if (tokenIn.Left is EndPathToken { Identifier: string path } - && tokenIn.Right is LiteralToken { Value: string valueString }) + if (tokenIn is + { + Left: EndPathToken { Identifier: string path }, + Right: LiteralToken { Value: string valueString } + }) { valueString = valueString.TrimStart('(').TrimEnd(')'); @@ -123,7 +129,7 @@ public Query Visit(FunctionCallToken tokenIn) throw new NotImplementedException($"Function {tokenIn.Name} not implemented"); } - private static Query VisitSearchIn(FunctionCallToken tokenIn) + private static BooleanQuery VisitSearchIn(FunctionCallToken tokenIn) { var args = tokenIn.Arguments.ToList(); @@ -245,4 +251,4 @@ public Query Visit(GroupByToken tokenIn) { throw new NotImplementedException(); } -} \ No newline at end of file +} diff --git a/AzureSearchEmulator/Startup.cs b/AzureSearchEmulator/Startup.cs index 9f57e95..b1212a2 100644 --- a/AzureSearchEmulator/Startup.cs +++ b/AzureSearchEmulator/Startup.cs @@ -13,14 +13,9 @@ namespace AzureSearchEmulator; -public class Startup +public class Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } = configuration; // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 @@ -95,4 +90,4 @@ private static IEdmModel GetEdmModel() return builder.GetEdmModel(); } -} \ No newline at end of file +} diff --git a/Dockerfile b/Dockerfile index f51b692..8d73c56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["AzureSearchEmulator/AzureSearchEmulator.csproj", "AzureSearchEmulator/"] RUN dotnet restore "AzureSearchEmulator/AzureSearchEmulator.csproj"