├── .gitattributes ├── .github ├── release-drafter-config.yml └── workflows │ ├── dotnet-core.yml │ ├── nuget-release.yml │ └── release-drafter.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Redis.OM.sln ├── docker ├── cluster │ ├── dockerfile │ ├── redis.conf │ ├── startup.sh │ └── startup_cluster.sh ├── docker-compose.yaml ├── dotnet │ └── dockerfile └── sentinel │ ├── dockerfile │ ├── sentinel.conf │ └── startup.sh ├── dockerfile ├── docs ├── README.md └── faq.md ├── examples ├── Redis.OM.BasicMatchingQueries │ ├── Helpers │ │ └── RedisHelper.cs │ ├── Models │ │ ├── Address.cs │ │ ├── Customer.cs │ │ └── CustomerRelation.cs │ ├── Program.cs │ └── Redis.OM.BasicMatchingQueries.csproj ├── Redis.OM.CreateIndexStore │ ├── Redis.OM.CreateIndexStore.sln │ └── Redis.OM.CreateIndexStore │ │ ├── Helpers │ │ └── SeedDataHelpers.cs │ │ ├── Models │ │ ├── Address.cs │ │ ├── Customer.cs │ │ ├── Employee.cs │ │ └── Store.cs │ │ ├── Program.cs │ │ └── Redis.OM.CreateIndexStore.csproj ├── Redis.OM.DeleteDocument │ └── Redis.OM.DeleteDocument │ │ ├── Redis.OM.DeleteDocument.sln │ │ └── Redis.OM.DeleteDocument │ │ ├── Customer.cs │ │ ├── Person.cs │ │ ├── Program.cs │ │ └── Redis.OM.DeleteDocument.csproj ├── Redis.OM.FullTextSearch │ ├── Models │ │ ├── Awards.cs │ │ ├── Genre.cs │ │ └── Movie.cs │ ├── Program.cs │ ├── Redis.OM.FullTextSearch.csproj │ ├── Redis.OM.FullTextSearch.sln │ └── RedisHelper │ │ └── RedisHelper.cs ├── Redis.OM.LowLevelSearchIndex │ ├── Helpers │ │ └── RedisHelper.cs │ ├── Models │ │ └── Customer.cs │ ├── Program.cs │ └── Redis.OM.LowLevelSearchIndex.csproj ├── Redis.OM.QueryingStringsWithinArrays │ ├── Experience.cs │ ├── Helpers.cs │ ├── Program.cs │ ├── Redis.OM.QueryingStringsWithinArrays.csproj │ └── Redis.OM.QueryingStringsWithinArrays.sln ├── Redis.OM.RawQueryExample │ ├── Program.cs │ └── Redis.OM.RawQueryExample.csproj └── Redis.OM.UpdatingDocuments │ ├── Models │ └── Product.cs │ ├── Program.cs │ └── Redis.OM.UpdatingDocuments.csproj ├── fetch-models.sh ├── global.json ├── images ├── icon-square.png ├── icon.png └── logo.svg ├── src ├── Redis.OM.Analyzer │ ├── Redis.OM.Analyzer.csproj │ ├── RedisCommandsAnalyzer.cs │ └── commands.json ├── Redis.OM.AspNetCore │ ├── Redis.OM.AspNetCore.csproj │ └── ServiceCollectionExtensions.cs ├── Redis.OM.POC │ ├── Enumorators │ │ ├── CursorEnumeratorBase.cs │ │ ├── FastListEnumorator.cs │ │ ├── RedisEnumoratorBase.cs │ │ ├── RedisHashEnumorator.cs │ │ ├── RedisHashKeyEnumorator.cs │ │ ├── RedisHashValueEnumorator.cs │ │ ├── RedisSetEnumorator.cs │ │ ├── SortedSetEnumorator.cs │ │ └── StreamEnumorator.cs │ ├── Generators │ │ └── RedisHashableGenerator.cs │ ├── IRedisStreamPublisher.cs │ ├── ObjectModeling │ │ └── ListTypeAttribute.cs │ ├── PendingConsumer.cs │ ├── Redis.OM.POC.csproj │ ├── RedisClientException.cs │ ├── RedisCommands.cs │ ├── RedisConnection.cs │ ├── RedisConnectionExtensions.cs │ ├── RedisFastList.cs │ ├── RedisHash.cs │ ├── RedisHashScanner.cs │ ├── RedisList.cs │ ├── RedisSet.cs │ ├── RedisStream.cs │ ├── RedisStreamProducer.cs │ ├── RespHelper.cs │ ├── SortedSetEntry.cs │ ├── StreamConsumerInfo.cs │ ├── StreamGroupInfo.cs │ ├── StreamInfoBasic.cs │ ├── StreamInfoFull.cs │ ├── XAutoClaimResponse.cs │ ├── XPendingMessage.cs │ ├── XPendingReply.cs │ └── XRangeResponse.cs ├── Redis.OM.Vectorizers.AllMiniLML6V2 │ ├── AllMiniLML6V2Tokenizer.cs │ ├── LICENSE │ ├── Redis.OM.Vectorizers.AllMiniLML6V2.csproj │ ├── RedisConnectionProviderExtensions.cs │ ├── SentenceVectorizer.cs │ ├── SentenceVectorizerAttribute.cs │ └── Tokenizers │ │ ├── CasedTokenizer.cs │ │ ├── StringExtensions.cs │ │ ├── TokenizerBase.cs │ │ ├── Tokens.cs │ │ └── UncasedTokenizer.cs ├── Redis.OM.Vectorizers.Resnet18 │ ├── DnnImageModelSelectorExtensions.cs │ ├── ImageModelObjects.cs │ ├── ImageVectorizer.cs │ ├── ImageVectorizerAttribute.cs │ ├── Redis.OM.Vectorizers.Resnet18.csproj │ └── Redis.OM.Vectorizers.Resnet18.props ├── Redis.OM.Vectorizers │ ├── AzureOpenAIVectorizer.cs │ ├── AzureOpenAIVectorizerAttribute.cs │ ├── Configuration.cs │ ├── HuggingFaceVectorizer.cs │ ├── HuggingFaceVectorizerAttribute.cs │ ├── OpenAIVectorizer.cs │ ├── OpenAIVectorizerAttribute.cs │ ├── Redis.OM.Vectorizers.csproj │ ├── RedisConnectionProviderExtensions.cs │ └── RedisOMHttpUtil.cs └── Redis.OM │ ├── Aggregation │ ├── AggregationEnumerator.cs │ ├── AggregationPredicates │ │ ├── AggregateSortBy.cs │ │ ├── Apply.cs │ │ ├── ApplyFunctions.cs │ │ ├── FilterOperand.cs │ │ ├── FilterOperandType.cs │ │ ├── FilterPredicate.cs │ │ ├── FirstValueReduction.cs │ │ ├── GroupBy.cs │ │ ├── IAggregationPredicate.cs │ │ ├── LimitPredicate.cs │ │ ├── Load.cs │ │ ├── LoadAll.cs │ │ ├── MultiSort.cs │ │ ├── QueryPredicate.cs │ │ ├── ReduceFunction.cs │ │ ├── Reduction.cs │ │ ├── SingleArgumentReduction.cs │ │ ├── TwoArgumentReduction.cs │ │ └── ZeroArgumentReduction.cs │ ├── AggregationResult.cs │ ├── GroupedAggregationSet.cs │ ├── IAggregationResult.cs │ ├── RedisAggregation.cs │ └── RedisAggregationSet.cs │ ├── Common │ ├── BooleanExpression.cs │ ├── ExpressionParserUtilities.cs │ └── ExpressionTranslator.cs │ ├── Contracts │ ├── IRedisConnection.cs │ ├── IRedisConnectionProvider.cs │ ├── IRedisHydrateable.cs │ ├── ISemanticCache.cs │ └── IVectorizer.cs │ ├── Extensions │ ├── StringExtension.cs │ └── TimespanExtensions.cs │ ├── GeoLoc.cs │ ├── GeoLocDistanceUnit.cs │ ├── IIdGenerationStrategy.cs │ ├── Modeling │ ├── DateTimeJsonConvertNewtonsoft.cs │ ├── DateTimeJsonConverter.cs │ ├── DelDiff.cs │ ├── DocumentAttribute.cs │ ├── DocumentAttributeExtensions.cs │ ├── GeoLocJsonConverter.cs │ ├── HashDiff.cs │ ├── IObjectDiff.cs │ ├── IndexedAttribute.cs │ ├── JsonDiff.cs │ ├── RedisCollectionStateManager.cs │ ├── RedisFieldAttribute.cs │ ├── RedisIdFieldAttribute.cs │ ├── RedisIndex.cs │ ├── RedisIndexingException.cs │ ├── RedisSchemaField.cs │ ├── SearchFieldAttribute.cs │ ├── SearchFieldType.cs │ ├── SearchableAttribute.cs │ ├── StorageType.cs │ ├── TypeDeterminationUtilities.cs │ └── Vectors │ │ ├── DistanceMetric.cs │ │ ├── DoubleVectorizer.cs │ │ ├── DoubleVectorizerAttribute.cs │ │ ├── FloatVectorizer.cs │ │ ├── FloatVectorizerAttribute.cs │ │ ├── JsonScoreConverter.cs │ │ ├── VectorAlgorithm.cs │ │ ├── VectorJsonConverter.cs │ │ ├── VectorResult.cs │ │ ├── VectorScoreField.cs │ │ ├── VectorScores.cs │ │ ├── VectorType.cs │ │ ├── VectorUtils.cs │ │ └── VectorizerAttribute.cs │ ├── PredicateBuilder.cs │ ├── RediSearchCommands.cs │ ├── Redis.OM.csproj │ ├── RedisCommands.cs │ ├── RedisConnection.cs │ ├── RedisConnectionConfiguration.cs │ ├── RedisConnectionProvider.cs │ ├── RedisIndexInfo.cs │ ├── RedisObjectHandler.cs │ ├── RedisReply.cs │ ├── RedisSerializationSettings.cs │ ├── RedisUriParser.cs │ ├── Scripts.cs │ ├── SearchExtensions.cs │ ├── Searching │ ├── IRedisCollection.cs │ ├── Query │ │ ├── NearestNeighbors.cs │ │ ├── QueryFlags.cs │ │ ├── QueryOption.cs │ │ ├── RedisFilter.cs │ │ ├── RedisGeoFilter.cs │ │ ├── RedisQuery.cs │ │ ├── RedisSortBy.cs │ │ ├── ReturnField.cs │ │ ├── ReturnFields.cs │ │ └── SearchLimit.cs │ ├── RedisCollection.cs │ ├── RedisCollectionEnumerator.cs │ ├── RedisQueryProvider.cs │ ├── SearchResponse.cs │ └── SortDirection.cs │ ├── SemanticCache.cs │ ├── SemanticCacheResponse.cs │ ├── UlidGenerationStrategy.cs │ ├── Uuid4IdGenerationStrategy.cs │ ├── Vector.cs │ ├── Vectors.cs │ ├── WhenKey.cs │ ├── stylecop.json │ └── stylecop.ruleset └── test ├── Redis.OM.Test.AspDotnetCore ├── Controllers │ └── WeatherForecastController.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Redis.OM.Test.AspDotnetCore.csproj ├── Startup.cs ├── WeatherForecast.cs ├── appsettings.Development.json └── appsettings.json ├── Redis.OM.Test.ConsoleApp ├── Program.cs └── Redis.OM.Test.ConsoleApp.csproj ├── Redis.OM.Unit.Tests ├── Address.cs ├── BasicTypeWithGeoLoc.cs ├── ConfigurationTests.cs ├── ConnectionTests.cs ├── CoreTests.cs ├── CustomerFilterDto.cs ├── GeoLocTests.cs ├── Helper.cs ├── RediSearchTests │ ├── AggregationFunctionalTests.cs │ ├── AggregationSetTests.cs │ ├── AnEnum.cs │ ├── ApplyFunctionTests.cs │ ├── BulkOperationsTests.cs │ ├── ClassForEmptyRedisCollection.cs │ ├── EnumFlags.cs │ ├── FilterPredicateTest.cs │ ├── GroupByTests.cs │ ├── HashPerson.cs │ ├── ObjectWIthMultipleDateTimes.cs │ ├── ObjectWithByteArray.cs │ ├── ObjectWithDateTime.cs │ ├── ObjectWithEmbeddedArrayOfObjects.cs │ ├── ObjectWithMultipleSearchableAttributes.cs │ ├── ObjectWithNullableStrings.cs │ ├── ObjectWithStringLikeValueTypes.cs │ ├── Person.cs │ ├── PersonNoName.cs │ ├── RawQueryTests.cs │ ├── RedisIndexTests.cs │ ├── ReducerTests.cs │ ├── SearchFunctionalTests.cs │ ├── SearchTests.cs │ └── VectorTests │ │ ├── AzureOpenAIVectors.cs │ │ ├── HuggingFaceVectors.cs │ │ ├── ObjectWithVector.cs │ │ ├── OpenAICompletionResponse.cs │ │ ├── OpenAIVectors.cs │ │ ├── SemanticCachingTests.cs │ │ ├── SimpleVectorizerAttribute.cs │ │ ├── VectorFunctionalTests.cs │ │ └── VectorTests.cs ├── Redis.OM.Unit.Tests.csproj ├── RedisSetupCollection.cs ├── SearchJsonTests │ ├── RedisJsonIndexTests.cs │ └── RedisJsonNestedComposeValueTest.cs ├── Serialization │ ├── BasicHashObject.cs │ ├── BasicJsonObject.cs │ ├── ComplexObjectWithCascadeAndJsonPath.cs │ ├── DateTimeSerializationTest.cs │ ├── HashObjectWithTwoPropertiesWithMatchingPrefixes.cs │ ├── HashTypeWithPrimitiveArray.cs │ ├── JsonObjectWithDateTime.cs │ ├── ObjectWithATimestamp.cs │ ├── ObjectWithCustomIdGenerationStrategy.cs │ ├── ObjectWithDateTimeOffset.cs │ ├── ObjectWithGuidId.cs │ ├── ObjectWithIntegerId.cs │ ├── ObjectWithMultipleSearchableFields.cs │ ├── ObjectWithNumerics.cs │ ├── ObjectWithPropertyNamesDefined.cs │ ├── ObjectWithStandardId.cs │ ├── ObjectWithTwoStopwords.cs │ ├── ObjectWithUlidId.cs │ ├── ObjectWithUserDefinedId.cs │ ├── ObjectWithZeroStopwords.cs │ ├── SelectTestObject.cs │ ├── SerializationTests.cs │ └── StaticIncrementStrategey.cs └── SkipIfMissingEnvVarAttribute.cs └── Redis.OM.Vectorizer.Tests ├── DocWithVectors.cs ├── GlobalUsings.cs ├── Redis.OM.Vectorizer.Tests.csproj ├── VectorizerFunctionalTests.cs └── hal.jpg /.gitattributes: -------------------------------------------------------------------------------- 1 | *.onnx filter=lfs diff=lfs merge=lfs -text 2 | src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources/vocab.txt filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/release-drafter-config.yml: -------------------------------------------------------------------------------- 1 | name-template: 'Version $NEXT_PATCH_VERSION' 2 | tag-template: 'v$NEXT_PATCH_VERSION' 3 | autolabeler: 4 | - label: 'maintenance' 5 | files: 6 | - '*.md' 7 | - '.github/*' 8 | - label: 'bug' 9 | branch: 10 | - '/bug-.+' 11 | - label: 'maintenance' 12 | branch: 13 | - '/maintenance-.+' 14 | - label: 'feature' 15 | branch: 16 | - '/feature-.+' 17 | categories: 18 | - title: '🔥 Breaking Changes' 19 | labels: 20 | - 'breakingchange' 21 | - title: '🚀 New Features' 22 | labels: 23 | - 'feature' 24 | - 'enhancement' 25 | - title: '🐛 Bug Fixes' 26 | labels: 27 | - 'fix' 28 | - 'bugfix' 29 | - 'bug' 30 | - title: '🧰 Maintenance' 31 | label: 'maintenance' 32 | change-template: '- $TITLE (#$NUMBER)' 33 | exclude-labels: 34 | - 'skip-changelog' 35 | template: | 36 | ## Changes 37 | 38 | $CHANGES 39 | 40 | ## Contributors 41 | We'd like to thank all the contributors who worked on this release! 42 | 43 | $CONTRIBUTORS 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: fetch-models 15 | run: sh fetch-models.sh 16 | - name: execute 17 | run: docker compose -f ./docker/docker-compose.yaml run dotnet -------------------------------------------------------------------------------- /.github/workflows/nuget-release.yml: -------------------------------------------------------------------------------- 1 | name: Nuget Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: Release version. 8 | required: true 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: fetch-models 16 | run: sh fetch-models.sh 17 | - name: Build 18 | run : dotnet build -c Release 19 | - name: Pack 20 | run: dotnet pack -c Release --output . 21 | - name: Set up .NET 22 | uses: actions/setup-dotnet@v3 23 | with: 24 | dotnet-version: | 25 | 8 26 | 7 27 | 6 28 | - name: Publish 29 | uses: alirezanet/publish-nuget@v3.1.0 30 | with: 31 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 32 | PROJECT_FILE_PATH: src/Redis.OM/Redis.OM.csproj 33 | PACKAGE_NAME: Redis.OM 34 | TAG_COMMIT: false 35 | - name: Publish 36 | uses: alirezanet/publish-nuget@v3.1.0 37 | with: 38 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 39 | PROJECT_FILE_PATH: src/Redis.OM.Vectorizers/Redis.OM.Vectorizers.csproj 40 | PACKAGE_NAME: Redis.OM.Vectorizers 41 | TAG_COMMIT: false 42 | - name: Publish 43 | uses: alirezanet/publish-nuget@v3.1.0 44 | with: 45 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 46 | PROJECT_FILE_PATH: src/Redis.OM.Vectorizers.AllMiniLML6V2/Redis.OM.Vectorizers.AllMiniLML6V2.csproj 47 | PACKAGE_NAME: Redis.OM.Vectorizers.AllMiniLML6V2 48 | TAG_COMMIT: false 49 | - name: Publish 50 | uses: alirezanet/publish-nuget@v3.1.0 51 | with: 52 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 53 | PROJECT_FILE_PATH: src/Redis.OM.Vectorizers.Resnet18/Redis.OM.Vectorizers.Resnet18.csproj 54 | PACKAGE_NAME: Redis.OM.Vectorizers.Resnet18 55 | TAG_COMMIT: false -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - main 8 | 9 | jobs: 10 | update_release_draft: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # Drafts your next Release notes as Pull Requests are merged into "main" 14 | - uses: release-drafter/release-drafter@v5 15 | with: 16 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 17 | config-name: release-drafter-config.yml 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 Redis Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docker/cluster/dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis/redis-stack-server 2 | 3 | RUN mkdir -p /redis 4 | 5 | WORKDIR /redis 6 | 7 | COPY redis.conf . 8 | COPY startup.sh /usr/local/bin/ 9 | COPY startup_cluster.sh /usr/local/bin/ 10 | 11 | RUN useradd redis 12 | RUN chown redis:redis /redis/* 13 | RUN chmod +x /usr/local/bin/startup.sh 14 | RUN chmod +x /usr/local/bin/startup_cluster.sh 15 | 16 | EXPOSE 6379 17 | 18 | ENTRYPOINT [ "/usr/local/bin/startup.sh" ] -------------------------------------------------------------------------------- /docker/cluster/redis.conf: -------------------------------------------------------------------------------- 1 | port 6379 2 | 3 | protected-mode no 4 | cluster-enabled yes 5 | cluster-config-file nodes.conf 6 | cluster-node-timeout 5000 7 | daemonize yes 8 | 9 | loadmodule /opt/redis-stack/lib/redisearch.so 10 | loadmodule /opt/redis-stack/lib/redistimeseries.so 11 | loadmodule /opt/redis-stack/lib/rejson.so 12 | loadmodule /opt/redis-stack/lib/redisbloom.so -------------------------------------------------------------------------------- /docker/cluster/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /opt/redis-stack/bin/redis-server /redis/redis.conf 4 | sleep infinity -------------------------------------------------------------------------------- /docker/cluster/startup_cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /opt/redis-stack/bin/redis-server /redis/redis.conf 4 | sleep 5 5 | echo yes | redis-cli --cluster create 192.168.57.10:6379 192.168.57.11:6379 192.168.57.12:6379 192.168.57.13:6379 192.168.57.14:6379 192.168.57.15:6379 6 | sleep infinity -------------------------------------------------------------------------------- /docker/dotnet/dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:6.0 2 | 3 | WORKDIR /app 4 | ADD . /app 5 | 6 | RUN ls /app 7 | RUN dotnet restore /app/Redis.OM.sln 8 | 9 | ENTRYPOINT ["dotnet","test"] -------------------------------------------------------------------------------- /docker/sentinel/dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis/redis-stack-server 2 | 3 | ENV SENTINEL_QUORUM 2 4 | ENV SENTINEL_DOWN_AFTER 1000 5 | ENV SENTINEL_FAILOVER 1000 6 | 7 | RUN mkdir -p /redis 8 | 9 | WORKDIR /redis 10 | 11 | COPY sentinel.conf . 12 | COPY startup.sh /usr/local/bin/ 13 | 14 | RUN useradd redis 15 | RUN chown redis:redis /redis/* 16 | RUN chmod +x /usr/local/bin/startup.sh 17 | 18 | EXPOSE 26379 19 | EXPOSE 6379 20 | ENTRYPOINT [ "/usr/local/bin/startup.sh" ] -------------------------------------------------------------------------------- /docker/sentinel/sentinel.conf: -------------------------------------------------------------------------------- 1 | port 26379 2 | 3 | dir /tmp 4 | 5 | sentinel resolve-hostnames yes 6 | sentinel monitor redismaster redis-master 6379 5 7 | sentinel down-after-milliseconds redismaster 1000 8 | sentinel parallel-syncs redismaster 1 9 | sentinel failover-timeout redismaster 1000 -------------------------------------------------------------------------------- /docker/sentinel/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /opt/redis-stack/bin/redis-server /redis/sentinel.conf --sentinel -------------------------------------------------------------------------------- /dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:7.0 2 | 3 | WORKDIR /app 4 | ADD . /app 5 | 6 | RUN ls /app 7 | RUN dotnet restore /app/Redis.OM.sln 8 | 9 | ENTRYPOINT ["dotnet", "test", "--framework", "net7.0" ] -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | ## FAQ 2 | 3 | * **Does Apply support String interpolation?** Not yet; rather than using string interpolation, you'll need to use `string.Format` 4 | * **Do bitwise operations work for apply?** No - the Bitwise XOR operator `^` indicates an exponential relationship between the operands 5 | * **When the Aggregation materializes, there's nothing in the `RecordShell` object. What gives?** The `RecordShell` item is used to preserve the original index through the aggregation pipeline and should only be used for operations within the pipeline. It will never materialize when the pipeline is enumerated 6 | * **Why Do some Reductive aggregations condense down to a single number while others condense down to an IEnumerable?** When you build your pipeline, if you have a reductive aggregation not associated with a group, the aggregation is run immediately. The result of that reduction is furnished to you immediately for use. 7 | * **Is the `RedisCollection` thread safe?** - The `RedisCollection` is only thread safe when initalized with the `saveState` option set to false. e.g. `var collection = provider.RedisCollection(false);` 8 | * **What is the difference between an `Indexed` and a `Searchable`field?** - `Indexed` should be the default for virtually all use-cases, they allow for exact matches, prefix, postfix, and infix searches on strings, as well as providing indexing for geolocations, numbers, guids, enumes and other scalar values. `Searchable` is appropriate only if you want to perform a full-text search on a given field 9 | * **Should I set `StorageType` to `Json` or `Hash`** Generally we would recommend using `Json` if you are storing anything other than numbers and strings. -------------------------------------------------------------------------------- /examples/Redis.OM.BasicMatchingQueries/Models/Address.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.BasicMatchingQueries.Models; 2 | 3 | using Redis.OM.Modeling; 4 | 5 | [Document(IndexName = "address-idx", StorageType = StorageType.Json)] 6 | public partial class Address 7 | { 8 | public string StreetName { get; set; } 9 | public string ZipCode { get; set; } 10 | [Indexed] public string City { get; set; } 11 | [Indexed] public string State { get; set; } 12 | [Indexed(CascadeDepth = 1)] public Address ForwardingAddress { get; set; } 13 | [Indexed] public GeoLoc Location { get; set; } 14 | [Indexed] public int HouseNumber { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /examples/Redis.OM.BasicMatchingQueries/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.BasicMatchingQueries.Models; 2 | 3 | using Redis.OM.Modeling; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class Customer 7 | { 8 | [Indexed] public string FirstName { get; set; } 9 | [Indexed] public string LastName { get; set; } 10 | [Indexed] public string Email { get; set; } 11 | [Indexed(Sortable = true)] public int Age { get; set; } 12 | [Indexed] public bool IsActive { get; set; } 13 | [Indexed] public Gender Gender { get; set; } 14 | [Indexed(CascadeDepth = 2)] 15 | public Address Address {get; set;} 16 | } 17 | -------------------------------------------------------------------------------- /examples/Redis.OM.BasicMatchingQueries/Models/CustomerRelation.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.BasicMatchingQueries.Models; 2 | 3 | public enum Gender 4 | { 5 | Male, 6 | Female, 7 | Other 8 | } 9 | -------------------------------------------------------------------------------- /examples/Redis.OM.BasicMatchingQueries/Redis.OM.BasicMatchingQueries.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32602.215 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.CreateIndexStore", "Redis.OM.CreateIndexStore\Redis.OM.CreateIndexStore.csproj", "{78B8EF87-5067-45D1-A864-37BC2931FF38}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {78B8EF87-5067-45D1-A864-37BC2931FF38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {78B8EF87-5067-45D1-A864-37BC2931FF38}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {78B8EF87-5067-45D1-A864-37BC2931FF38}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {78B8EF87-5067-45D1-A864-37BC2931FF38}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {41CDF499-8994-409A-8C71-2278EAB55B83} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Models/Address.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM.CreateIndexStore.Models 8 | { 9 | public class Address 10 | { 11 | public string? AddressLine1 { get; set; } 12 | 13 | public string? AddressLine2 { get; set; } 14 | public string? City { get; set; } 15 | 16 | public Address(string addressLine1, string? city) 17 | { 18 | AddressLine1 = addressLine1; 19 | City = city; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.CreateIndexStore.Models 4 | { 5 | [Document(StorageType = StorageType.Json)] 6 | public class Customer 7 | { 8 | [RedisIdField][Indexed] public Guid Id { get; set; } 9 | 10 | [Indexed] public string FullName { get; set; } = null!; 11 | [Indexed] public string Email { get; set; } = null!; 12 | 13 | [Indexed] public string[] Publications { get; set; } = null!; 14 | 15 | [Indexed] public Address? Address { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Models/Employee.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.CreateIndexStore.Models 4 | { 5 | [Document(StorageType = StorageType.Json, Prefixes = new[] { "CANADA.STORE.TORONTO" }, IndexName = "Store1-idx")] 6 | public class Employee 7 | { 8 | [RedisIdField][Indexed] public string Id { get; set; } = null!; 9 | 10 | [Indexed] public string FullName { get; set; } = null!; 11 | 12 | [Indexed] public int Age { get; set; } 13 | 14 | [Indexed] public EmploymentType EmploymentType { get; set; } 15 | } 16 | 17 | public enum EmploymentType 18 | { 19 | FullTime, 20 | PartTime 21 | } 22 | } -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Models/Store.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Redis.OM.CreateIndexStore.Models 9 | { 10 | [Document(StorageType = StorageType.Hash)] 11 | public record Store 12 | { 13 | [RedisIdField][Indexed] public int Id { get; set; } 14 | 15 | [Indexed] public string FullAddress { get; set; } = null!; 16 | [Indexed] public string Name { get; set; } = null!; 17 | } 18 | } -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Program.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM; 2 | using Redis.OM.CreateIndexStore; 3 | using Redis.OM.CreateIndexStore.Models; 4 | 5 | var provider = new RedisConnectionProvider("redis://localhost:6379"); 6 | 7 | provider.Connection.CreateIndex(typeof(Customer)); 8 | provider.Connection.CreateIndex(typeof(Employee)); 9 | provider.Connection.CreateIndex(typeof(Store)); 10 | 11 | var customers = provider.RedisCollection(); 12 | var employee = provider.RedisCollection(); 13 | var stores = provider.RedisCollection(); 14 | 15 | await SeedDataHelpers.SeedEmployess(employee); 16 | await SeedDataHelpers.SeedCustomers(customers); 17 | await SeedDataHelpers.SeedStore(stores); 18 | 19 | //retrieve all the contents 20 | var allStores = await stores.ToListAsync(); 21 | var allEmployees = await employee.ToListAsync(); 22 | var allCustomers = await customers.ToListAsync(); 23 | 24 | //Filter by diffenrent properties 25 | var store = await stores.Where(x => x.Id == 600).FirstOrDefaultAsync(); 26 | var newton = await customers.Where(x => x.FullName == "Albert Einstein").FirstOrDefaultAsync(); 27 | var fulltimeEmployees = await employee.Where(x => x.EmploymentType == EmploymentType.FullTime).ToListAsync(); 28 | 29 | //Drop the index 30 | await provider.Connection.DropIndexAsync(typeof(Employee)); 31 | await provider.Connection.DropIndexAsync(typeof(Customer)); 32 | await provider.Connection.DropIndexAsync(typeof(Store)); -------------------------------------------------------------------------------- /examples/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore/Redis.OM.CreateIndexStore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32526.322 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.DeleteDocument", "Redis.OM.DeleteDocument\Redis.OM.DeleteDocument.csproj", "{01AAAF54-6E92-4559-9064-EE5210E56CFE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {01AAAF54-6E92-4559-9064-EE5210E56CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {01AAAF54-6E92-4559-9064-EE5210E56CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {01AAAF54-6E92-4559-9064-EE5210E56CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {01AAAF54-6E92-4559-9064-EE5210E56CFE}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {837FFB76-86D7-4EA9-A872-BF85F6AC3D6C} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Customer.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.DeleteDocument 4 | { 5 | [Document(StorageType = StorageType.Json)] 6 | internal class Customer 7 | { 8 | [RedisIdField][Indexed] public string? Id { get; set; } 9 | [Indexed] public string FirstName { get; set; } 10 | [Indexed] public string LastName { get; set; } 11 | [Indexed] public string Email { get; set; } 12 | [Indexed(Aggregatable = true)] public int Age { get; set; } 13 | [Indexed(Aggregatable = true)] public GeoLoc Home { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Person.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.DeleteDocument 4 | { 5 | [Document(StorageType = StorageType.Json, Prefixes = new[] { "Person" })] 6 | internal class Person 7 | { 8 | [RedisIdField][Indexed] public string? Id { get; set; } 9 | 10 | [Indexed] public string? FirstName { get; set; } 11 | 12 | [Indexed] public string? LastName { get; set; } 13 | 14 | [Indexed] public int Age { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument/Redis.OM.DeleteDocument.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.FullTextSearch/Models/Awards.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using Redis.OM.Modeling; 4 | 5 | namespace Redis.OM.FullTextSearch.Models 6 | { 7 | [Document(IndexName = "awards-idx", StorageType = StorageType.Json)] 8 | public class Awards 9 | { 10 | [Indexed(Sortable = true)] 11 | public int Wins { get; set; } 12 | [Indexed(Sortable = true)] 13 | public int Nominations { get; set; } 14 | [Searchable] 15 | public string? Text { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/Redis.OM.FullTextSearch/Models/Genre.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM.FullTextSearch.Models 8 | { 9 | public enum Genres 10 | { 11 | Scifi, 12 | Drama, 13 | Action, 14 | Fantasy, 15 | Romance, 16 | Sports, 17 | History, 18 | Crime, 19 | Adventure 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/Redis.OM.FullTextSearch/Models/Movie.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Redis.OM.FullTextSearch.Models 5 | { 6 | [Document(StorageType = StorageType.Json, IndexName = "movie-idx")] 7 | public class Movie 8 | { 9 | [Searchable] 10 | public string Title { get; set; } 11 | [Indexed(Sortable = true)] 12 | public long Year { get; set; } 13 | [Indexed] 14 | public string? Plot { get; set; } 15 | [Indexed] 16 | public List Languages { get; set; } 17 | [Indexed(Sortable = true)] 18 | public DateTime Released { get; set; } 19 | [Indexed] 20 | public List Cast { get; set; } 21 | [Indexed] 22 | public List Directors { get; set; } 23 | [Indexed] 24 | public List Writers { get; set; } 25 | [Indexed(Sortable = true)] 26 | public int Runtime { get; set; } 27 | [Indexed] 28 | public List Genres { get; set; } 29 | [Indexed(CascadeDepth = 2)] 30 | public Awards Awards { get; set; } 31 | [Indexed(Sortable = true)] 32 | public double? ImdbRating { get; set; } 33 | [Indexed] 34 | public Country Country { get; set; } 35 | 36 | } 37 | public enum Country 38 | { 39 | UK, 40 | USA, 41 | IND, 42 | KR 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/Redis.OM.FullTextSearch/Redis.OM.FullTextSearch.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | Redis.OM.Full_Text_Search_within_an_Index 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.FullTextSearch/Redis.OM.FullTextSearch.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32901.215 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redis.OM.FullTextSearch", "Redis.OM.FullTextSearch.csproj", "{5F2B8BBC-EB2D-40AC-928E-20DEB3EF873E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5F2B8BBC-EB2D-40AC-928E-20DEB3EF873E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5F2B8BBC-EB2D-40AC-928E-20DEB3EF873E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5F2B8BBC-EB2D-40AC-928E-20DEB3EF873E}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5F2B8BBC-EB2D-40AC-928E-20DEB3EF873E}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {85C9F500-C5A0-4E74-84F5-C9BA9EFF20D9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/Redis.OM.LowLevelSearchIndex/Helpers/RedisHelper.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.BasicMatchingQueries.Models; 2 | using Redis.OM.Searching; 3 | 4 | namespace Redis.OM.LowLevelSearchIndex.Helpers; 5 | 6 | public class RedisHelper 7 | { 8 | private readonly IRedisCollection _customerCollection; 9 | 10 | public RedisHelper(RedisConnectionProvider provider) 11 | { 12 | _customerCollection = provider.RedisCollection(); 13 | } 14 | 15 | public void InitializeCustomers() 16 | { 17 | var count = _customerCollection.Count(); 18 | if (count > 0) 19 | { 20 | // not re-add when already initialize 21 | return; 22 | } 23 | 24 | Console.WriteLine("Initialize Customer Data..."); 25 | 26 | _customerCollection.Insert(new Customer() 27 | { 28 | FirstName = "Customer", 29 | LastName = "2", 30 | Age = 20, 31 | IsActive = true, 32 | Email = "test@test.com", 33 | }); 34 | 35 | _customerCollection.Insert(new Customer() 36 | { 37 | FirstName = "Customer", 38 | LastName = "3", 39 | Age = 25, 40 | IsActive = false, 41 | Email = "test-3@test.com", 42 | }); 43 | 44 | _customerCollection.Insert(new Customer() 45 | { 46 | FirstName = "Testable", 47 | LastName = "Customer 2", 48 | Age = 99, 49 | IsActive = true, 50 | Email = "test-55@test.com", 51 | }); 52 | 53 | _customerCollection.Insert(new Customer() 54 | { 55 | FirstName = "Sharon", 56 | LastName = "Lim", 57 | Age = 25, 58 | IsActive = true, 59 | Email = "test-111@test.com", 60 | }); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /examples/Redis.OM.LowLevelSearchIndex/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.BasicMatchingQueries.Models; 2 | 3 | using Redis.OM.Modeling; 4 | 5 | [Document(StorageType = StorageType.Json, IndexName = "customer-idx")] 6 | public class Customer 7 | { 8 | [Searchable] public string FirstName { get; set; } 9 | [Searchable] public string LastName { get; set; } 10 | [Searchable] public string Email { get; set; } 11 | [Indexed(Sortable = true)] public int Age { get; set; } 12 | [Indexed] public bool IsActive { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /examples/Redis.OM.LowLevelSearchIndex/Program.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM; 2 | using Redis.OM.BasicMatchingQueries.Models; 3 | using Redis.OM.LowLevelSearchIndex.Helpers; 4 | using Redis.OM.Searching; 5 | using System.Reflection; 6 | 7 | static void ShowCustomers(string type, List customers) 8 | { 9 | Console.WriteLine($"Customer {type}: {string.Join(", ", customers.Select(x => $"{x.FirstName} {x.LastName}"))}, total: {customers.Count}."); 10 | } 11 | 12 | var provider = new RedisConnectionProvider("redis://localhost:6379"); 13 | provider.Connection.CreateIndex(typeof(Customer)); 14 | 15 | var redisHelper = new RedisHelper(provider); 16 | redisHelper.InitializeCustomers(); 17 | 18 | var connection = provider.Connection; 19 | 20 | var result = connection.Execute("FT.SEARCH", "customer-idx", "@IsActive:{true} @FirstName|LastName:customer"); 21 | var response = new SearchResponse(result); 22 | 23 | ShowCustomers("Active & First or Last Name have \"customer\"", response.Documents.Values.ToList()); 24 | 25 | result = connection.Execute("FT.SEARCH", "customer-idx", "(@FirstName|LastName:customer) | (@LastName:customer) => { $weight: 5.0; }"); 26 | response = new SearchResponse(result); 27 | 28 | ShowCustomers("First or Last Name have \"customer\" but prioritize lastname", response.Documents.Values.ToList()); 29 | 30 | result = connection.Execute("FT.SEARCH", "customer-idx", "customer"); 31 | response = new SearchResponse(result); 32 | 33 | ShowCustomers("All customers with fields text that match with \"customer\"", response.Documents.Values.ToList()); -------------------------------------------------------------------------------- /examples/Redis.OM.LowLevelSearchIndex/Redis.OM.LowLevelSearchIndex.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.QueryingStringsWithinArrays/Experience.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.QueryingStringsWithinArrays; 4 | 5 | [Document(StorageType =StorageType.Json)] 6 | public class Experience 7 | { 8 | [RedisIdField] 9 | [Indexed] 10 | public string Id { get; set; } = default!; 11 | 12 | [Indexed] 13 | public string[] Skills { get; set; } = default!; 14 | 15 | public override string ToString() 16 | { 17 | return string.Join(" ", Skills); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/Redis.OM.QueryingStringsWithinArrays/Helpers.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Searching; 2 | 3 | namespace Redis.OM.QueryingStringsWithinArrays; 4 | 5 | public class Helpers 6 | { 7 | public static async Task AddDummyExperiences(IRedisCollection collection) 8 | { 9 | List experiences = new() 10 | { 11 | new Experience { Skills = new string[] { "C#", ".NET", "ASP.NET Core" } }, 12 | new Experience { Skills = new string[] { "C#", "Android", "MAUI" } }, 13 | new Experience { Skills = new string[] { "Java", "JVM", "Spring Boot" } }, 14 | new Experience { Skills = new string[] { "Java", "Kotlin", "Android" } }, 15 | new Experience { Skills = new string[] { "Dart", "Flutter", "Android" } } 16 | }; 17 | foreach (var item in experiences) 18 | { 19 | await collection.InsertAsync(item); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/Redis.OM.QueryingStringsWithinArrays/Program.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM; 2 | using Redis.OM.QueryingStringsWithinArrays; 3 | 4 | var provider = new RedisConnectionProvider("redis://localhost:6379"); 5 | provider.Connection.CreateIndex(typeof(Experience)); 6 | var experiences = provider.RedisCollection(); 7 | 8 | await Helpers.AddDummyExperiences(experiences); 9 | 10 | //Contains usage 11 | var filteredExperiences = await experiences.Where(x=>x.Skills.Contains("C#")).ToListAsync(); 12 | 13 | foreach (var item in filteredExperiences) 14 | { 15 | Console.WriteLine(item.ToString()); 16 | } -------------------------------------------------------------------------------- /examples/Redis.OM.QueryingStringsWithinArrays/Redis.OM.QueryingStringsWithinArrays.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.QueryingStringsWithinArrays/Redis.OM.QueryingStringsWithinArrays.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32505.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Redis.OM.QueryingStringsWithinArrays", "Redis.OM.QueryingStringsWithinArrays.csproj", "{EA6FAC79-A169-4736-8C24-38F74A2D5E44}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EA6FAC79-A169-4736-8C24-38F74A2D5E44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EA6FAC79-A169-4736-8C24-38F74A2D5E44}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EA6FAC79-A169-4736-8C24-38F74A2D5E44}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EA6FAC79-A169-4736-8C24-38F74A2D5E44}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {80C3C0CF-C83B-4288-8541-981C3025FE75} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/Redis.OM.RawQueryExample/Redis.OM.RawQueryExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/Redis.OM.UpdatingDocuments/Models/Product.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.UpdatingDocuments.Models; 2 | 3 | using Redis.OM.Modeling; 4 | 5 | [Document(IndexName = "products-idx", StorageType = StorageType.Json)] 6 | public class Product 7 | { 8 | [RedisIdField] 9 | [Indexed] 10 | public Ulid Id { get; set; } 11 | 12 | [Indexed] 13 | public string? Name { get; set; } 14 | 15 | public string? Description { get; set; } 16 | 17 | [Indexed(Sortable = true)] 18 | public double Price { get; set; } 19 | 20 | public DateTime DateAdded { get; set; } 21 | 22 | [Indexed] 23 | public bool InStock { get; set; } 24 | } -------------------------------------------------------------------------------- /examples/Redis.OM.UpdatingDocuments/Redis.OM.UpdatingDocuments.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /fetch-models.sh: -------------------------------------------------------------------------------- 1 | mkdir -p ./src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources && \ 2 | curl -o ./src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources/model.onnx https://storage.googleapis.com/slorello/model.onnx 3 | 4 | mkdir -p ./src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources && \ 5 | curl -o ./src/Redis.OM.Vectorizers.AllMiniLML6V2/Resources/vocab.txt https://storage.googleapis.com/slorello/vocab.txt 6 | 7 | mkdir -p ./src/Redis.OM.Vectorizers.Resnet18/Resources/ResNet18Onnx && \ 8 | curl -o ./src/Redis.OM.Vectorizers.Resnet18/Resources/ResNet18Onnx/ResNet18.onnx https://storage.googleapis.com/slorello/ResNet18.onnx 9 | 10 | mkdir -p ./src/Redis.OM.Vectorizers.Resnet18/Resources/ResNetPrepOnnx && \ 11 | curl -o ./src/Redis.OM.Vectorizers.Resnet18/Resources/ResNetPrepOnnx/ResNetPreprocess.onnx https://storage.googleapis.com/slorello/ResNetPreprocess.onnx 12 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "5.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": false 6 | } 7 | } -------------------------------------------------------------------------------- /images/icon-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redis/redis-om-dotnet/d04d0959cf02d011e9344aa281e061722c6211f1/images/icon-square.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redis/redis-om-dotnet/d04d0959cf02d011e9344aa281e061722c6211f1/images/icon.png -------------------------------------------------------------------------------- /src/Redis.OM.Analyzer/Redis.OM.Analyzer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | library 6 | latest 7 | enable 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Redis.OM.AspNetCore/Redis.OM.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | Redis.Developer.AspDotnetCore 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Redis.OM.AspNetCore/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.Configuration; 3 | using Redis.OM; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Redis.OM.Contracts; 6 | 7 | namespace Redis.OM.AspNetCore 8 | { 9 | public static class ServiceCollectionExtensions 10 | { 11 | public static IServiceCollection AddRedis(this IServiceCollection services, 12 | string connectionString) 13 | { 14 | var provider = new RedisConnectionProvider(connectionString); 15 | return services.AddSingleton(provider); 16 | } 17 | 18 | public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration) 19 | { 20 | var connectionString = configuration["REDIS_CONNECTION_STRING"]; 21 | return services.AddSingleton(new RedisConnectionProvider(connectionString)); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/CursorEnumeratorBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Redis.OM.Contracts; 7 | 8 | namespace Redis.OM 9 | { 10 | public abstract class CursorEnumeratorBase : RedisEnumoratorBase 11 | where T : notnull 12 | { 13 | public CursorEnumeratorBase(IRedisConnection connection, string keyName, uint chunkSize = 100) : base(connection, keyName, chunkSize) { } 14 | 15 | public override bool MoveNext() 16 | { 17 | if(_chunkIndex == -1) 18 | { 19 | GetNextChunk(); 20 | return _chunkIndex < _chunk.Length; 21 | } 22 | _chunkIndex++; 23 | if(_chunkIndex < _chunk.Length) 24 | { 25 | return true; 26 | } 27 | else if (_cursor != 0) 28 | { 29 | GetNextChunk(); 30 | return _chunkIndex < _chunk.Length; 31 | } 32 | else 33 | { 34 | return false; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/FastListEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Redis.OM.Contracts; 7 | 8 | namespace Redis.OM 9 | { 10 | public class FastListEnumorator : CursorEnumeratorBase 11 | { 12 | public FastListEnumorator(IRedisConnection connection, string keyName, uint chunkSize = 100) : 13 | base(connection, keyName, chunkSize) 14 | { 15 | } 16 | 17 | protected override void GetNextChunk() 18 | { 19 | _chunk = _connection.ZScan(_keyName, ref _cursor, count: _chunkSize).Select(m => m.Member).ToArray(); 20 | //.Select(s=>s?.Member?.Substring(0,s.Member.Length-(s.Member.Length-s.Member.LastIndexOf('-')))).ToArray(); 21 | _chunkIndex = 0; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/RedisEnumoratorBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using Redis.OM.Contracts; 4 | 5 | namespace Redis.OM 6 | { 7 | public abstract class RedisEnumoratorBase : IEnumerator 8 | where T : notnull 9 | { 10 | protected T[] _chunk; 11 | protected int _chunkIndex = -1; 12 | protected int _cursor = 0; 13 | protected int _offset = 0; 14 | protected readonly uint _chunkSize = 100; 15 | protected IRedisConnection _connection; 16 | protected readonly string _keyName; 17 | 18 | public RedisEnumoratorBase(IRedisConnection connection, string keyName, uint chunkSize = 100) 19 | { 20 | _connection = connection; 21 | _keyName = keyName; 22 | _chunkSize = chunkSize; 23 | _chunk = new T[0]; 24 | } 25 | 26 | protected abstract void GetNextChunk(); 27 | 28 | public T Current => _chunk[_chunkIndex]; 29 | 30 | object IEnumerator.Current => _chunk[_chunkIndex]; 31 | 32 | public void Dispose() 33 | { 34 | //do nothing 35 | } 36 | 37 | public virtual bool MoveNext() 38 | { 39 | if (_chunkIndex == -1 || _chunkIndex + 1 >= _chunk.Length) 40 | { 41 | GetNextChunk(); 42 | return _chunkIndex < _chunk.Length; 43 | } 44 | _chunkIndex++; 45 | return _chunkIndex < _chunk.Length; 46 | } 47 | 48 | public void Reset() 49 | { 50 | _cursor = 0; 51 | _offset = 0; 52 | GetNextChunk(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/RedisHashEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Redis.OM.Contracts; 3 | 4 | namespace Redis.OM 5 | { 6 | public class RedisHashEnumorator : RedisEnumoratorBase> 7 | { 8 | public RedisHashEnumorator(IRedisConnection connection, string keyName, uint chunkSize = 100) : 9 | base(connection, keyName, chunkSize) 10 | { 11 | } 12 | 13 | protected override void GetNextChunk() 14 | { 15 | _chunk = _connection.HScan(_keyName, ref _cursor, count: _chunkSize).ToArray(); 16 | _chunkIndex = -1; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/RedisHashKeyEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Redis.OM.Contracts; 3 | 4 | namespace Redis.OM 5 | { 6 | public class RedisHashKeyEnumorator : CursorEnumeratorBase 7 | { 8 | public RedisHashKeyEnumorator(IRedisConnection connection, string keyName, uint chunkSize = 100) : 9 | base(connection, keyName, chunkSize) 10 | { 11 | } 12 | 13 | protected override void GetNextChunk() 14 | { 15 | _chunk = _connection.HScan(_keyName, ref _cursor, count: _chunkSize).Select(kvp => kvp.Key).ToArray(); 16 | _chunkIndex = 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/RedisHashValueEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Redis.OM.Contracts; 3 | 4 | namespace Redis.OM 5 | { 6 | public class RedisHashValueEnumorator : CursorEnumeratorBase 7 | { 8 | public RedisHashValueEnumorator( 9 | IRedisConnection connection, 10 | string keyName, 11 | uint chunkSize = 100) : base(connection, keyName, chunkSize) 12 | { 13 | } 14 | 15 | protected override void GetNextChunk() 16 | { 17 | _chunk = _connection.HScan(_keyName, ref _cursor, count: _chunkSize).Select(kvp => kvp.Key).ToArray(); 18 | _chunkIndex = 0; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/RedisSetEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Redis.OM.Contracts; 7 | 8 | namespace Redis.OM 9 | { 10 | public class RedisSetEnumorator : CursorEnumeratorBase 11 | { 12 | public RedisSetEnumorator(IRedisConnection connection, string keyName, uint chunkSize = 100) : 13 | base(connection, keyName, chunkSize) 14 | { 15 | } 16 | protected override void GetNextChunk() 17 | { 18 | _chunk = _connection.SScan(_keyName, ref _cursor, count: _chunkSize).ToArray(); 19 | _chunkIndex = 0; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Enumorators/SortedSetEnumorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Redis.OM.Contracts; 7 | 8 | namespace Redis.OM.Enumorators 9 | { 10 | public class SortedSetEnumorator : CursorEnumeratorBase 11 | { 12 | public SortedSetEnumorator(IRedisConnection connection, string keyName, uint chunkSize) 13 | : base(connection, keyName, chunkSize) { } 14 | protected override void GetNextChunk() 15 | { 16 | _connection.ZScan(_keyName, ref _cursor, count: _chunkSize); 17 | _chunkIndex = 0; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/IRedisStreamPublisher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM 8 | { 9 | public interface IRedisStreamPublisher 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/ObjectModeling/ListTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Redis.OM 6 | { 7 | public class ListTypeAttribute : Attribute 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/PendingConsumer.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Redis.OM; 8 | 9 | namespace Redis.OM 10 | { 11 | public class PendingConsumer 12 | { 13 | public string ConsumerName { get; set; } 14 | public int NumPendingMessages { get; set; } 15 | 16 | public PendingConsumer(RedisReply value) 17 | { 18 | var vals = value.ToArray(); 19 | ConsumerName = vals[0]; 20 | NumPendingMessages = (int)vals[1]; 21 | } 22 | 23 | internal PendingConsumer(StreamConsumer consumer) 24 | { 25 | ConsumerName = consumer.Name; 26 | NumPendingMessages = consumer.PendingMessageCount; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/Redis.OM.POC.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 9.0 6 | Redis.OM 7 | enable 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/RedisClientException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM 8 | { 9 | public class RedisClientException : Exception 10 | { 11 | public RedisClientException(string message) : base(message) { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/RedisConnectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Contracts; 2 | using StackExchange.Redis; 3 | 4 | namespace Redis.OM 5 | { 6 | public static class RedisConnectionExtensions 7 | { 8 | public static IRedisConnection Connect(this RedisConnectionConfiguration conf) 9 | { 10 | return new RedisConnection(conf.Host); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Redis.OM.POC/RedisStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Redis.OM.Contracts; 9 | 10 | namespace Redis.OM 11 | { 12 | public class RedisStream : IAsyncEnumerable 13 | where T : notnull, new() 14 | { 15 | private string _streamKeyName; 16 | private IRedisConnection _connection; 17 | internal string CurrentId { get; set; } 18 | private int _chunkSize; 19 | private string _groupName; 20 | private string _consumerName; 21 | public RedisStream(string keyName, IRedisConnection connection, string currentId = "$", int chunkSize = 100, string groupName="", string consumerName="") 22 | { 23 | _streamKeyName = keyName; 24 | _connection = connection; 25 | CurrentId = currentId; 26 | _chunkSize = chunkSize; 27 | _groupName = groupName; 28 | _consumerName = consumerName; 29 | 30 | } 31 | 32 | public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) 33 | { 34 | return new StreamEnumorator(this, _connection, _streamKeyName, _groupName, cancellationToken, _consumerName); 35 | } 36 | 37 | public async Task Add(T obj) 38 | { 39 | return await _connection.XAddAsync(_streamKeyName, obj); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/RedisStreamProducer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM 8 | { 9 | public class RedisStreamProducer 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/SortedSetEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM 8 | { 9 | public class SortedSetEntry 10 | { 11 | public double Score { get; set; } 12 | public string Member { get; set; } = string.Empty; 13 | 14 | public static implicit operator string[](SortedSetEntry e)=>new string[] { e.Score.ToString(), e.Member }; 15 | public static string[] BuildRequestArray(SortedSetEntry[] e) 16 | { 17 | var ret = new List(); 18 | foreach(var entry in e) 19 | { 20 | ret.AddRange((string[])entry); 21 | } 22 | return ret.ToArray(); 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/StreamConsumerInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using StackExchange.Redis; 7 | namespace Redis.OM 8 | { 9 | public class StreamConsumerInfo 10 | { 11 | public string Name { get; private set; } 12 | public int Pending { get; private set; } 13 | public long Idle { get; private set; } 14 | 15 | public StreamConsumerInfo(StackExchange.Redis.StreamConsumerInfo consumer) 16 | { 17 | Name = consumer.Name; 18 | Pending = consumer.PendingMessageCount; 19 | Idle = consumer.IdleTimeInMilliseconds; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/StreamGroupInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json.Serialization; 6 | using System.Threading.Tasks; 7 | using Redis.OM.Modeling; 8 | 9 | namespace Redis.OM 10 | { 11 | public class StreamGroupInfo 12 | { 13 | [RedisField(PropertyName = "name")] 14 | public string Name { get; set; } 15 | [RedisField(PropertyName = "consumers")] 16 | public int Consumers { get; set; } 17 | [RedisField(PropertyName = "pending")] 18 | public int Pending { get; set; } 19 | [RedisField(PropertyName = "last-delivered-id")] 20 | [JsonPropertyName("last-delivered-id")] 21 | public string LastDeliveredId { get; set; } 22 | 23 | internal StreamGroupInfo(StackExchange.Redis.StreamGroupInfo info) 24 | { 25 | Name = info.Name; 26 | Consumers = info.ConsumerCount; 27 | Pending = info.PendingMessageCount; 28 | LastDeliveredId = info.LastDeliveredId; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/StreamInfoBasic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM 8 | { 9 | public class StreamInfoBasic 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/StreamInfoFull.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using StackExchange.Redis; 7 | 8 | namespace Redis.OM 9 | { 10 | public class StreamInfoFull 11 | { 12 | public KeyValuePair> FirstEntry {get; private set;} 13 | public KeyValuePair> LastEntry {get; private set;} 14 | public long RadixTreeNodes { get; private set; } 15 | public long RadixTreeKeys { get; private set; } 16 | public long Length { get; private set; } 17 | 18 | public StreamInfoFull(StreamInfo info) 19 | { 20 | Length = info.Length; 21 | RadixTreeKeys = info.RadixTreeKeys; 22 | RadixTreeNodes = info.RadixTreeNodes; 23 | FirstEntry = new KeyValuePair>( 24 | info.FirstEntry.Id, 25 | info.FirstEntry.Values.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString())); 26 | LastEntry = new KeyValuePair>( 27 | info.LastEntry.Id, 28 | info.LastEntry.Values.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString())); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/XAutoClaimResponse.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Redis.OM; 8 | 9 | 10 | namespace Redis.OM 11 | { 12 | public class XAutoClaimResponse : XRangeResponse 13 | where T : notnull 14 | { 15 | public string NextId { get; set; } 16 | //public IDictionary Messages { get; set; } 17 | public XAutoClaimResponse(RedisReply[] vals, string id) : base(vals.Skip(1).ToArray(), id) 18 | { 19 | NextId = vals[0]; 20 | } 21 | 22 | public XAutoClaimResponse(RedisResult[] vals, string id) : base(vals.Skip(1).ToArray(), id) 23 | { 24 | NextId = ((string)vals[0]); 25 | } 26 | } 27 | 28 | public class XAutoClaimResponse : XRangeResponse 29 | { 30 | public string NextId { get; set; } 31 | public XAutoClaimResponse(RedisReply[] vals) :base(vals.Skip(1).ToArray()) 32 | { 33 | NextId = vals[0]; 34 | } 35 | 36 | public XAutoClaimResponse(RedisResult[] vals) : base(vals.Skip(1).ToArray()) 37 | { 38 | NextId = vals[0].ToString(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/XPendingMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Redis.OM; 7 | using StackExchange.Redis; 8 | 9 | namespace Redis.OM 10 | { 11 | public class XPendingMessage 12 | { 13 | public string MessageId { get; set; } 14 | public string ConsumerName { get; set; } 15 | public long MillisecondsSinceLastDelivery { get; set; } 16 | public int NumberOfDeliveries { get; set; } 17 | public XPendingMessage(RedisReply[] values) 18 | { 19 | MessageId = values[0]; 20 | ConsumerName = values[1]; 21 | MillisecondsSinceLastDelivery = (int)values[2]; 22 | NumberOfDeliveries = (int)values[3]; 23 | } 24 | 25 | public XPendingMessage(StreamPendingMessageInfo info) 26 | { 27 | MessageId = info.MessageId; 28 | ConsumerName = info.ConsumerName; 29 | MillisecondsSinceLastDelivery = info.IdleTimeInMilliseconds; 30 | NumberOfDeliveries = info.DeliveryCount; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Redis.OM.POC/XPendingReply.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Redis.OM; 8 | 9 | namespace Redis.OM 10 | { 11 | public class XPendingReply 12 | { 13 | public int NumPendingMessages { get; private set; } 14 | public string SmallestPendingId { get; private set; } 15 | public string LargestPendingId { get; private set; } 16 | public IList PendingConsumers { get; private set; } 17 | 18 | public XPendingReply(RedisReply value) 19 | { 20 | var vals = value.ToArray(); 21 | NumPendingMessages = (int)vals[0]; 22 | SmallestPendingId = vals[1]; 23 | LargestPendingId = vals[2]; 24 | PendingConsumers = new List(); 25 | foreach(var val in vals.Skip(3).ToArray()) 26 | { 27 | PendingConsumers.Add(new PendingConsumer(val)); 28 | } 29 | } 30 | 31 | internal XPendingReply(StreamPendingInfo info) 32 | { 33 | LargestPendingId = info.HighestPendingMessageId; 34 | SmallestPendingId = info.LowestPendingMessageId; 35 | NumPendingMessages = info.PendingMessageCount; 36 | PendingConsumers = new List(); 37 | foreach(var consumer in info.Consumers) 38 | { 39 | PendingConsumers.Add(new PendingConsumer(consumer)); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/AllMiniLML6V2Tokenizer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Redis.OM.Vectorizers.AllMiniLML6V2.Tokenizers; 3 | 4 | namespace Redis.OM.Vectorizers.AllMiniLML6V2; 5 | 6 | internal class AllMiniLML6V2Tokenizer : UncasedTokenizer 7 | { 8 | private AllMiniLML6V2Tokenizer(string[] vocabulary) : base(vocabulary) 9 | { 10 | } 11 | 12 | internal static AllMiniLML6V2Tokenizer Create() 13 | { 14 | var assembly = Assembly.GetExecutingAssembly(); 15 | const string fileName = "Redis.OM.Vectorizers.AllMiniLML6V2.Resources.vocab.txt"; 16 | using var stream = assembly.GetManifestResourceStream(fileName); 17 | if (stream is null) 18 | { 19 | throw new FileNotFoundException("Could not find embedded resource file Resources.vocab.txt"); 20 | } 21 | using var reader = new StreamReader(stream); 22 | 23 | if (stream is null) 24 | { 25 | throw new Exception("Could not open stream reader."); 26 | } 27 | 28 | var vocab = new List(); 29 | string? line; 30 | while ((line = reader.ReadLine()) is not null) 31 | { 32 | vocab.Add(line); 33 | } 34 | 35 | return new AllMiniLML6V2Tokenizer(vocab.ToArray()); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Redis Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | =============================================== 25 | 26 | Third Party Licenses: 27 | 28 | The BERT tokenization code heavily influenced by the BertTokenizers 29 | Project: https://github.com/NMZivkovic/BertTokenizers which is 30 | licensed under an MIT license: 31 | https://github.com/NMZivkovic/BertTokenizers/blob/master/LICENSE.txt 32 | 33 | Some parts of the pre/post processing pipeline were adapted 34 | from Curiosity AI's MiniLM project, which uses an MIT license: 35 | https://github.com/curiosity-ai/MiniLM/blob/4a7c629c223b6244cb8a394f17920ea1de363dce/MiniLM/MiniLM.csproj#L13 -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/Redis.OM.Vectorizers.AllMiniLML6V2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net7.0 5 | enable 6 | enable 7 | Redis.OM.Vectorizers.AllMiniLML6V2 8 | 1.0.0 9 | 1.0.0 10 | https://github.com/redis/redis-om-dotnet/releases/tag/v1.0.0 11 | Sentence Vectorizer for Redis OM .NET using all-MiniLM-L6-v2 12 | Redis OM all-MiniLM-L6-v2 Vectorizers 13 | Steve Lorello 14 | Redis Inc 15 | https://github.com/redis/redis-om-dotnet 16 | https://github.com/redis/redis-om-dotnet 17 | Github 18 | redis redisearch AI Vectors 19 | icon-square.png 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/RedisConnectionProviderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Contracts; 2 | 3 | namespace Redis.OM.Vectorizers.AllMiniLML6V2; 4 | 5 | /// 6 | /// Static extensions for The RedisConnectionProvider. 7 | /// 8 | public static class RedisConnectionProviderExtensions 9 | { 10 | /// 11 | /// Creates a Semantic Cache using the All-MiniLM-L6-v2 Vectorizer 12 | /// 13 | /// The connection provider. 14 | /// The Index that the cache will be stored in. 15 | /// The threshold that will be considered a match 16 | /// The Prefix. 17 | /// The Time to Live for a record stored in Redis. 18 | /// 19 | public static ISemanticCache AllMiniLML6V2SemanticCache(this IRedisConnectionProvider provider, string indexName="AllMiniLML6V2SemanticCache", double threshold = .15, string? prefix = null, long? ttl = null) 20 | { 21 | var vectorizer = new SentenceVectorizer(); 22 | var connection = provider.Connection; 23 | var info = connection.GetIndexInfo(indexName); 24 | var cache = new SemanticCache(indexName, prefix ?? indexName, threshold, ttl, vectorizer, connection); 25 | if (info is null) 26 | { 27 | cache.CreateIndex(); 28 | } 29 | 30 | return cache; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/SentenceVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Contracts; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Vectorizers.AllMiniLML6V2; 5 | 6 | /// 7 | /// 8 | /// 9 | public class SentenceVectorizerAttribute : VectorizerAttribute 10 | { 11 | /// 12 | public override VectorType VectorType => Vectorizer.VectorType; 13 | 14 | /// 15 | public override int Dim => Vectorizer.Dim; 16 | 17 | /// 18 | public override byte[] Vectorize(object obj) => Vectorizer.Vectorize((string)obj); 19 | 20 | /// 21 | public override IVectorizer Vectorizer => new SentenceVectorizer(); 22 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/Tokenizers/CasedTokenizer.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Vectorizers.AllMiniLML6V2.Tokenizers; 2 | 3 | internal abstract class CasedTokenizer : TokenizerBase 4 | { 5 | protected CasedTokenizer(string[] vocabulary) : base(vocabulary) 6 | { 7 | } 8 | 9 | protected override IEnumerable TokenizeSentence(string text) 10 | { 11 | return text.Split(new [] { " ", " ", "\r\n" }, StringSplitOptions.None) 12 | .SelectMany(o => o.SplitAndKeep(".,;:\\/?!#$%()=+-*\"'–_`<>&^@{}[]|~'".ToArray())); 13 | } 14 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/Tokenizers/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Vectorizers.AllMiniLML6V2.Tokenizers; 2 | 3 | internal static class StringExtension 4 | { 5 | public static IEnumerable SplitAndKeep( 6 | this string inputString, params char[] delimiters) 7 | { 8 | int start = 0, index; 9 | 10 | while ((index = inputString.IndexOfAny(delimiters, start)) != -1) 11 | { 12 | if (index - start > 0) 13 | yield return inputString.Substring(start, index - start); 14 | 15 | yield return inputString.Substring(index, 1); 16 | 17 | start = index + 1; 18 | } 19 | 20 | if (start < inputString.Length) 21 | { 22 | yield return inputString.Substring(start); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/Tokenizers/Tokens.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Vectorizers.AllMiniLML6V2.Tokenizers; 2 | 3 | internal class Tokens 4 | { 5 | public const string Padding = ""; 6 | public const string Unknown = "[UNK]"; 7 | public const string Classification = "[CLS]"; 8 | public const string Separation = "[SEP]"; 9 | public const string Mask = "[MASK]"; 10 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.AllMiniLML6V2/Tokenizers/UncasedTokenizer.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Vectorizers.AllMiniLML6V2.Tokenizers; 2 | 3 | internal abstract class UncasedTokenizer : TokenizerBase 4 | { 5 | public UncasedTokenizer(string[] vocabulary) : base(vocabulary) 6 | { 7 | } 8 | 9 | protected override IEnumerable TokenizeSentence(string text) 10 | { 11 | return text.Split(new [] { " ", " ", "\r\n" }, StringSplitOptions.None) 12 | .SelectMany(o => o.SplitAndKeep(".,;:\\/?!#$%()=+-*\"'–_`<>&^@{}[]|~'".ToArray())) 13 | .Select(o => o.ToLower()); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.Resnet18/ImageModelObjects.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ML.Data; 2 | using Microsoft.ML.Transforms.Image; 3 | 4 | namespace Redis.OM.Vectorizers.Resnet18; 5 | 6 | internal class ImageInput 7 | { 8 | [ColumnName(@"ImageSource")] 9 | public string ImageSource { get; set; } 10 | 11 | public ImageInput(string imageSource) 12 | { 13 | ImageSource = imageSource; 14 | } 15 | } 16 | 17 | internal class InMemoryImageData 18 | { 19 | [ImageType(224,224)] 20 | public MLImage Image; 21 | 22 | public InMemoryImageData(MLImage image) 23 | { 24 | Image = image; 25 | } 26 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.Resnet18/ImageVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Contracts; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Vectorizers.Resnet18; 5 | 6 | /// 7 | /// A Vectorizer Attribute for encoding images 8 | /// 9 | public class ImageVectorizerAttribute : VectorizerAttribute 10 | { 11 | /// 12 | public override VectorType VectorType => Vectorizer.VectorType; 13 | 14 | /// 15 | public override int Dim => Vectorizer.Dim; 16 | 17 | /// 18 | public override byte[] Vectorize(object obj) => Vectorizer.Vectorize((string)obj); 19 | 20 | /// 21 | public override IVectorizer Vectorizer { get; } = new ImageVectorizer(); 22 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers.Resnet18/Redis.OM.Vectorizers.Resnet18.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Resources\%(RecursiveDir)%(Filename)%(Extension) 5 | PreserveNewest 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers/AzureOpenAIVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using Azure.Core; 2 | using Azure.Identity; 3 | using Redis.OM.Contracts; 4 | using Redis.OM.Modeling; 5 | 6 | namespace Redis.OM.Vectorizers; 7 | 8 | /// 9 | public class AzureOpenAIVectorizerAttribute : VectorizerAttribute 10 | { 11 | private readonly string? _apikey; 12 | private readonly TokenCredential? _tokenCredential; 13 | 14 | /// 15 | public AzureOpenAIVectorizerAttribute(string deploymentName, string resourceName, int dim) 16 | { 17 | DeploymentName = deploymentName; 18 | ResourceName = resourceName; 19 | Dim = dim; 20 | _apikey = Configuration.Instance.AzureOpenAIApiKey; 21 | _tokenCredential = new DefaultAzureCredential(); 22 | Vectorizer = string.IsNullOrEmpty(Configuration.Instance.AzureOpenAIApiKey) ? new AzureOpenAIVectorizer(resourceName, deploymentName, dim) : new AzureOpenAIVectorizer(Configuration.Instance.AzureOpenAIApiKey, ResourceName, DeploymentName, dim); 23 | 24 | } 25 | 26 | /// 27 | /// Gets the DeploymentName. 28 | /// 29 | public string DeploymentName { get; } 30 | 31 | /// 32 | /// Gets the resource name. 33 | /// 34 | public string ResourceName { get; } 35 | 36 | /// 37 | public override IVectorizer Vectorizer { get; } 38 | 39 | /// 40 | public override VectorType VectorType => VectorType.FLOAT32; 41 | 42 | /// 43 | public override int Dim { get; } 44 | 45 | /// 46 | public override byte[] Vectorize(object obj) 47 | { 48 | if (obj is not string s) 49 | { 50 | throw new ArgumentException("Object must be a string to be embedded", nameof(obj)); 51 | } 52 | 53 | var floats = AzureOpenAIVectorizer.GetFloats(s, ResourceName, DeploymentName, _apikey, _tokenCredential); 54 | return floats.SelectMany(BitConverter.GetBytes).ToArray(); 55 | } 56 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers/OpenAIVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Contracts; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Vectorizers; 5 | 6 | /// 7 | /// An OpenAI Sentence Vectorizer. 8 | /// 9 | public class OpenAIVectorizerAttribute : VectorizerAttribute 10 | { 11 | private const string DefaultModel = "text-embedding-ada-002"; 12 | 13 | /// 14 | /// The ModelId. 15 | /// 16 | public string ModelId { get; } = DefaultModel; 17 | 18 | /// 19 | public override VectorType VectorType => VectorType.FLOAT32; 20 | 21 | /// 22 | public override int Dim => ModelId == DefaultModel ? 1536 : GetFloats("Probing model dimensions").Length; 23 | 24 | private IVectorizer? _vectorizer; 25 | 26 | /// 27 | public override IVectorizer Vectorizer 28 | { 29 | get 30 | { 31 | return _vectorizer ??= new OpenAIVectorizer(Configuration.Instance.OpenAiAuthorizationToken, ModelId, Dim); 32 | } 33 | } 34 | 35 | /// 36 | public override byte[] Vectorize(object obj) 37 | { 38 | var s = (string)obj; 39 | var floats = GetFloats(s); 40 | return floats.SelectMany(BitConverter.GetBytes).ToArray(); 41 | } 42 | 43 | internal float[] GetFloats(string s) 44 | { 45 | return OpenAIVectorizer.GetFloats(s, ModelId, Configuration.Instance.OpenAiAuthorizationToken); 46 | } 47 | } -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers/Redis.OM.Vectorizers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net7.0 5 | enable 6 | enable 7 | Redis.OM 8 | 1.0.0 9 | 1.0.0 10 | https://github.com/redis/redis-om-dotnet/releases/tag/v1.0.0 11 | Core Vectorizers for Redis OM .NET. 12 | Redis OM Vectorizers 13 | Steve Lorello 14 | Redis Inc 15 | https://github.com/redis/redis-om-dotnet 16 | icon-square.png 17 | MIT 18 | https://github.com/redis/redis-om-dotnet 19 | Github 20 | redis redisearch indexing databases 21 | true 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Redis.OM.Vectorizers/RedisOMHttpUtil.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM; 2 | 3 | internal static class RedisOMHttpUtil 4 | { 5 | public static string ReadJsonSync(HttpResponseMessage msg) 6 | { 7 | return new StreamReader(msg.Content.ReadAsStream()).ReadToEnd(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/AggregateSortBy.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Globalization; 3 | using Redis.OM.Searching; 4 | 5 | namespace Redis.OM.Aggregation.AggregationPredicates 6 | { 7 | /// 8 | /// Sort by predicate for an aggregation. 9 | /// 10 | public class AggregateSortBy : IAggregationPredicate 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// property to sort by. 16 | /// direction to sort by. 17 | /// maximum number of records to pull. 18 | public AggregateSortBy(string property, SortDirection direction, int? max = null) 19 | { 20 | Property = property; 21 | Direction = direction; 22 | Max = max; 23 | } 24 | 25 | /// 26 | /// Gets or sets property to sort by. 27 | /// 28 | public string Property { get; set; } 29 | 30 | /// 31 | /// Gets or sets direction to sort. 32 | /// 33 | public SortDirection Direction { get; set; } 34 | 35 | /// 36 | /// Gets or sets maximum number of elements. 37 | /// 38 | public int? Max { get; set; } 39 | 40 | /// 41 | /// gets the number of arguments of this predicate. 42 | /// 43 | internal static int NumArgs => 2; 44 | 45 | /// 46 | public IEnumerable Serialize() 47 | { 48 | var ret = new List { "SORTBY", NumArgs.ToString(CultureInfo.InvariantCulture), $"@{Property}", Direction == SortDirection.Ascending ? "ASC" : "DESC" }; 49 | 50 | if (Max.HasValue) 51 | { 52 | ret.Add("MAX"); 53 | ret.Add(Max.ToString()); 54 | } 55 | 56 | return ret.ToArray(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/Apply.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | using Redis.OM.Common; 4 | 5 | namespace Redis.OM.Aggregation.AggregationPredicates 6 | { 7 | /// 8 | /// A predicate building a function to apply to items in the aggregation pipeline. 9 | /// 10 | public class Apply : IAggregationPredicate 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// the expression. 16 | /// The alias. 17 | public Apply(Expression expression, string alias) 18 | { 19 | Expression = expression; 20 | Alias = alias; 21 | } 22 | 23 | /// 24 | /// Gets or sets the alias. 25 | /// 26 | public string Alias { get; set; } 27 | 28 | /// 29 | /// gets the expression. 30 | /// 31 | protected Expression Expression { get; } 32 | 33 | /// 34 | public IEnumerable Serialize() 35 | { 36 | var list = new List(); 37 | list.Add("APPLY"); 38 | switch (Expression) 39 | { 40 | case BinaryExpression rootBinExpression: 41 | list.Add(ExpressionParserUtilities.ParseBinaryExpression(rootBinExpression)); 42 | break; 43 | case MethodCallExpression method: 44 | list.Add(ExpressionParserUtilities.GetOperandString(method)); 45 | break; 46 | default: 47 | list.Add(ExpressionParserUtilities.GetOperandString(Expression)); 48 | break; 49 | } 50 | 51 | list.Add("AS"); 52 | list.Add(Alias); 53 | return list.ToArray(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/FilterOperand.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Aggregation.AggregationPredicates 2 | { 3 | /// 4 | /// A representation of a filter operand. 5 | /// 6 | internal class FilterOperand 7 | { 8 | private readonly string _text; 9 | private readonly FilterOperandType _operandType; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// the text. 15 | /// the operand type. 16 | internal FilterOperand(string text, FilterOperandType operandType) 17 | { 18 | _text = text; 19 | _operandType = operandType; 20 | } 21 | 22 | /// 23 | /// Sends the operand to a string. 24 | /// 25 | /// String representation of the operand. 26 | public override string ToString() 27 | { 28 | return _operandType switch 29 | { 30 | FilterOperandType.Identifier => $"@{_text}", 31 | FilterOperandType.Numeric => _text, 32 | FilterOperandType.String => $"'{_text}'", 33 | _ => string.Empty 34 | }; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/FilterOperandType.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Aggregation.AggregationPredicates 2 | { 3 | /// 4 | /// The type of operand you are looking at when parsing expressions. 5 | /// 6 | internal enum FilterOperandType 7 | { 8 | /// 9 | /// The item is an identifier. 10 | /// 11 | Identifier = 0, 12 | 13 | /// 14 | /// The item is a literal numeric. 15 | /// 16 | Numeric = 1, 17 | 18 | /// 19 | /// The item is a string literal. 20 | /// 21 | String = 2, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/FilterPredicate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | using Redis.OM.Common; 4 | 5 | namespace Redis.OM.Aggregation.AggregationPredicates 6 | { 7 | /// 8 | /// predicate for filtering results from an aggregation. 9 | /// 10 | public class FilterPredicate : Apply, IAggregationPredicate 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The expression to use for filtering. 16 | public FilterPredicate(Expression expression) 17 | : base(expression, string.Empty) 18 | { 19 | } 20 | 21 | /// 22 | public new IEnumerable Serialize() 23 | { 24 | var list = new List { "FILTER" }; 25 | switch (Expression) 26 | { 27 | case BinaryExpression rootBinExpression: 28 | list.Add(ExpressionParserUtilities.ParseBinaryExpression(rootBinExpression, true)); 29 | break; 30 | case MethodCallExpression method: 31 | list.Add(ExpressionParserUtilities.GetOperandString(method)); 32 | break; 33 | default: 34 | list.Add(ExpressionParserUtilities.GetOperandString(Expression)); 35 | break; 36 | } 37 | 38 | return list.ToArray(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/GroupBy.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Redis.OM.Aggregation.AggregationPredicates 5 | { 6 | /// 7 | /// A predicate indicating that you want to group like objects together. 8 | /// 9 | public class GroupBy : IAggregationPredicate 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// the properties to group. 15 | public GroupBy(string[] properties) 16 | { 17 | Properties = properties; 18 | } 19 | 20 | /// 21 | /// Gets or sets the properties to group. 22 | /// 23 | public string[] Properties { get; set; } 24 | 25 | /// 26 | public IEnumerable Serialize() 27 | { 28 | var ret = new List 29 | { 30 | "GROUPBY", 31 | Properties.Length.ToString(), 32 | }; 33 | ret.AddRange(Properties.Select(property => $"@{property}")); 34 | return ret.ToArray(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/IAggregationPredicate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// A predicate in an aggregation pipeline. 7 | /// 8 | public interface IAggregationPredicate 9 | { 10 | /// 11 | /// Serializes the predicate. 12 | /// 13 | /// An array of string arguments for an aggregation. 14 | IEnumerable Serialize(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/LimitPredicate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// A predicate for limiting results of an aggregation. 7 | /// 8 | public class LimitPredicate : IAggregationPredicate 9 | { 10 | /// 11 | /// Gets or sets the offset to use to step into the results. 12 | /// 13 | public long Offset { get; set; } 14 | 15 | /// 16 | /// Gets or sets the number of items to return. 17 | /// 18 | public long Count { get; set; } = 100; 19 | 20 | /// 21 | public IEnumerable Serialize() 22 | { 23 | return new[] { "LIMIT", Offset.ToString(), Count.ToString() }; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/Load.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Redis.OM.Aggregation.AggregationPredicates 5 | { 6 | /// 7 | /// Represents a Load aggregation predicate. 8 | /// 9 | public class Load : IAggregationPredicate 10 | { 11 | private const string LoadString = "LOAD"; 12 | private IEnumerable _properties; 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// The properties to load. 18 | public Load(IEnumerable properties) 19 | { 20 | _properties = properties; 21 | } 22 | 23 | /// 24 | public IEnumerable Serialize() 25 | { 26 | yield return LoadString; 27 | yield return _properties.Count().ToString(); 28 | foreach (var property in _properties) 29 | { 30 | yield return property; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/LoadAll.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// Represents an aggregation predicate to load all properties of a model. 7 | /// 8 | public class LoadAll : IAggregationPredicate 9 | { 10 | private const string LoadString = "LOAD"; 11 | private const string Star = "*"; 12 | 13 | /// 14 | public IEnumerable Serialize() 15 | { 16 | yield return LoadString; 17 | yield return Star; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/MultiSort.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Redis.OM.Searching; 4 | 5 | namespace Redis.OM.Aggregation.AggregationPredicates 6 | { 7 | /// 8 | /// Allows a grouping together of multiple sortby predicates. 9 | /// 10 | public class MultiSort : IAggregationPredicate 11 | { 12 | private readonly Stack _subPredicates = new Stack(); 13 | 14 | /// 15 | /// Inserts a predicate into the multi-sort. 16 | /// 17 | /// The sortby predicate. 18 | public void InsertPredicate(AggregateSortBy sb) 19 | { 20 | _subPredicates.Push(sb); 21 | } 22 | 23 | /// 24 | public IEnumerable Serialize() 25 | { 26 | var numArgs = _subPredicates.Sum(x => AggregateSortBy.NumArgs); 27 | var max = _subPredicates.FirstOrDefault(x => x.Max.HasValue)?.Max; 28 | var args = new List(numArgs) { "SORTBY", numArgs.ToString() }; 29 | foreach (var predicate in _subPredicates) 30 | { 31 | args.Add($"@{predicate.Property}"); 32 | args.Add(predicate.Direction == SortDirection.Ascending ? "ASC" : "DESC"); 33 | } 34 | 35 | if (max.HasValue) 36 | { 37 | args.Add("MAX"); 38 | args.Add(max.ToString()); 39 | } 40 | 41 | return args; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/ReduceFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Aggregation.AggregationPredicates 2 | { 3 | /// 4 | /// the name of a reduction function. 5 | /// 6 | public enum ReduceFunction 7 | { 8 | /// 9 | /// count. 10 | /// 11 | COUNT = 0, 12 | 13 | /// 14 | /// distinct count. 15 | /// 16 | COUNT_DISTINCT = 1, 17 | 18 | /// 19 | /// An approximate count of distinct occurrences of a field. 20 | /// 21 | COUNT_DISTINCTISH = 2, 22 | 23 | /// 24 | /// The sum. 25 | /// 26 | SUM = 3, 27 | 28 | /// 29 | /// Min. 30 | /// 31 | MIN = 4, 32 | 33 | /// 34 | /// Max. 35 | /// 36 | MAX = 5, 37 | 38 | /// 39 | /// Average. 40 | /// 41 | AVG = 6, 42 | 43 | /// 44 | /// Standard deviation 45 | /// 46 | STDDEV = 7, 47 | 48 | /// 49 | /// Quantile. 50 | /// 51 | QUANTILE = 8, 52 | 53 | /// 54 | /// Sends distinct elements to a list. 55 | /// 56 | TOLIST = 9, 57 | 58 | /// 59 | /// retrieves the first value matching the pattern. 60 | /// 61 | FIRST_VALUE = 10, 62 | 63 | /// 64 | /// Gets a random sample. 65 | /// 66 | RANDOM_SAMPLE = 11, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/Reduction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// A reduction. 7 | /// 8 | public abstract class Reduction : IAggregationPredicate 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The function to reduce to. 14 | protected Reduction(ReduceFunction function) 15 | { 16 | Function = function; 17 | } 18 | 19 | /// 20 | /// Gets the alias of the result name when the reduction completes. 21 | /// 22 | public abstract string ResultName { get; } 23 | 24 | /// 25 | /// Gets The function to use for reduction. 26 | /// 27 | protected ReduceFunction Function { get; } 28 | 29 | /// 30 | public abstract IEnumerable Serialize(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/SingleArgumentReduction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// A reduction with one argument. 7 | /// 8 | public class SingleArgumentReduction : Reduction 9 | { 10 | private readonly string _arg; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The reduction function. 16 | /// The name of the argument. 17 | public SingleArgumentReduction(ReduceFunction function, string arg) 18 | : base(function) 19 | { 20 | _arg = arg; 21 | } 22 | 23 | /// 24 | /// Gets the name of the result. 25 | /// 26 | public override string ResultName => $"{_arg}_{Function}"; 27 | 28 | /// 29 | public override IEnumerable Serialize() 30 | { 31 | var ret = new List(); 32 | ret.Add("REDUCE"); 33 | ret.Add(Function.ToString()); 34 | ret.Add("1"); 35 | ret.Add($"@{_arg}"); 36 | ret.Add("AS"); 37 | ret.Add(ResultName); 38 | return ret.ToArray(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/TwoArgumentReduction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | using Redis.OM.Common; 4 | 5 | namespace Redis.OM.Aggregation.AggregationPredicates 6 | { 7 | /// 8 | /// A reduction with two arguments. 9 | /// 10 | public class TwoArgumentReduction : Reduction 11 | { 12 | private readonly string _arg1; 13 | private readonly string _arg2; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The reduction function. 19 | /// The expression. 20 | public TwoArgumentReduction(ReduceFunction func, MethodCallExpression expression) 21 | : base(func) 22 | { 23 | _arg1 = ExpressionParserUtilities.GetOperandString(expression.Arguments[1]); 24 | _arg2 = ExpressionParserUtilities.GetOperandString(expression.Arguments[2]); 25 | } 26 | 27 | /// 28 | /// Gets the name of the result. 29 | /// 30 | public override string ResultName => $"{_arg1.Substring(1)}_{Function}_{_arg2}"; 31 | 32 | /// 33 | /// Sends the reduction to an array of strings for redis. 34 | /// 35 | /// an array of strings. 36 | public override IEnumerable Serialize() 37 | { 38 | var ret = new List(); 39 | ret.Add("REDUCE"); 40 | ret.Add(Function.ToString()); 41 | ret.Add("2"); 42 | ret.Add(_arg1); 43 | ret.Add(_arg2); 44 | ret.Add("AS"); 45 | ret.Add(ResultName); 46 | return ret.ToArray(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/AggregationPredicates/ZeroArgumentReduction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Aggregation.AggregationPredicates 4 | { 5 | /// 6 | /// A reduction that takes no arguments. 7 | /// 8 | public class ZeroArgumentReduction : Reduction 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// the reduction function. 14 | public ZeroArgumentReduction(ReduceFunction function) 15 | : base(function) 16 | { 17 | } 18 | 19 | /// 20 | public override string ResultName => $"{Function}"; 21 | 22 | /// 23 | public override IEnumerable Serialize() 24 | { 25 | var ret = new List(); 26 | ret.Add("REDUCE"); 27 | ret.Add(Function.ToString()); 28 | ret.Add("0"); 29 | ret.Add("AS"); 30 | ret.Add(ResultName); 31 | return ret.ToArray(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/GroupedAggregationSet.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Redis.OM.Aggregation 4 | { 5 | /// 6 | /// An aggregation set that represents a grouped set of items. 7 | /// 8 | /// The type being aggregated. 9 | public class GroupedAggregationSet : RedisAggregationSet 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The previous aggregation set. 15 | /// the expression. 16 | internal GroupedAggregationSet(RedisAggregationSet source, Expression expression) 17 | : base(source, expression) 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Redis.OM/Aggregation/IAggregationResult.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Aggregation 2 | { 3 | /// 4 | /// An aggregation result. 5 | /// 6 | public interface IAggregationResult 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Redis.OM/Common/BooleanExpression.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | 4 | namespace Redis.OM.Common 5 | { 6 | /// 7 | /// A boolean expression. 8 | /// 9 | public abstract class BooleanExpression 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// the expression. 15 | internal BooleanExpression(LambdaExpression expression) 16 | { 17 | Expression = expression; 18 | } 19 | 20 | /// 21 | /// Gets or sets the Lambda expression. 22 | /// 23 | protected LambdaExpression Expression { get; set; } 24 | 25 | /// 26 | /// Validates an operand and pushes it onto the stack. 27 | /// 28 | /// the expression. 29 | /// the stack. 30 | protected abstract void ValidateAndPushOperand(Expression expression, Stack stack); 31 | 32 | /// 33 | /// Splits the binary expression into a usable query. 34 | /// 35 | /// the expression. 36 | /// the operand stack. 37 | protected abstract void SplitBinaryExpression(BinaryExpression expression, Stack stack); 38 | 39 | /// 40 | /// splits the expression recursively. 41 | /// 42 | /// a stack of predicate strings. 43 | protected Stack SplitExpression() 44 | { 45 | var ret = new Stack(); 46 | if (Expression.Body is BinaryExpression binExpression) 47 | { 48 | SplitBinaryExpression(binExpression, ret); 49 | } 50 | else 51 | { 52 | ValidateAndPushOperand(Expression.Body, ret); 53 | } 54 | 55 | return ret; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Redis.OM/Contracts/IRedisConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Redis.OM.Contracts 5 | { 6 | /// 7 | /// A connection to Redis. 8 | /// 9 | public interface IRedisConnection : IDisposable 10 | { 11 | /// 12 | /// Executes a command. 13 | /// 14 | /// The command name. 15 | /// The arguments. 16 | /// A redis Reply. 17 | RedisReply Execute(string command, params object[] args); 18 | 19 | /// 20 | /// Executes a command. 21 | /// 22 | /// The command name. 23 | /// The arguments. 24 | /// A redis Reply. 25 | Task ExecuteAsync(string command, params object[] args); 26 | 27 | /// 28 | /// Executes the contained commands within the context of a transaction. 29 | /// 30 | /// each tuple represents a command and 31 | /// it's arguments to execute inside a transaction. 32 | /// A redis Reply. 33 | Task ExecuteInTransactionAsync(Tuple[] commandArgsTuples); 34 | 35 | /// 36 | /// Executes the contained commands within the context of a transaction. 37 | /// 38 | /// each tuple represents a command and 39 | /// it's arguments to execute inside a transaction. 40 | /// A redis Reply. 41 | RedisReply[] ExecuteInTransaction(Tuple[] commandArgsTuples); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Redis.OM/Contracts/IRedisConnectionProvider.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Aggregation; 2 | using Redis.OM.Searching; 3 | 4 | namespace Redis.OM.Contracts 5 | { 6 | /// 7 | /// Provides a connection to redis. 8 | /// 9 | public interface IRedisConnectionProvider 10 | { 11 | /// 12 | /// Gets a command level interface to redis. 13 | /// 14 | IRedisConnection Connection { get; } 15 | 16 | /// 17 | /// Gets an aggregation set for redis. 18 | /// 19 | /// The indexed type to run aggregations on. 20 | /// Size of chunks to use during pagination, larger chunks = larger payloads returned but fewer round trips. 21 | /// the aggregation set. 22 | RedisAggregationSet AggregationSet(int chunkSize = 100); 23 | 24 | /// 25 | /// Gets a redis collection. 26 | /// 27 | /// The type the collection will be retrieving. 28 | /// Size of chunks to use during pagination, larger chunks = larger payloads returned but fewer round trips. 29 | /// A RedisCollection. 30 | IRedisCollection RedisCollection(int chunkSize = 100) 31 | where T : notnull; 32 | 33 | /// 34 | /// Gets a redis collection. 35 | /// 36 | /// The type the collection will be retrieving. 37 | /// Whether or not the RedisCollection should maintain the state of documents it enumerates. 38 | /// Size of chunks to use during pagination, larger chunks = larger payloads returned but fewer round trips. 39 | /// A RedisCollection. 40 | IRedisCollection RedisCollection(bool saveState, int chunkSize = 100) 41 | where T : notnull; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Redis.OM/Contracts/IRedisHydrateable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Contracts 4 | { 5 | /// 6 | /// An object that can be hydrated too and from a Redis Hash. 7 | /// 8 | public interface IRedisHydrateable 9 | { 10 | /// 11 | /// Hydrates the object. 12 | /// 13 | /// The dictionary to hydrate from. 14 | void Hydrate(IDictionary dict); 15 | 16 | /// 17 | /// Converts object to dictionary for Redis. 18 | /// 19 | /// A dictionary for Redis. 20 | IDictionary BuildHashSet(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Redis.OM/Contracts/IVectorizer.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Contracts 4 | { 5 | /// 6 | /// Converter of objects into vectors. 7 | /// 8 | /// The type to be vectorized. 9 | public interface IVectorizer 10 | { 11 | /// 12 | /// Gets the vector Type generated by the vectorizer. 13 | /// 14 | VectorType VectorType { get; } 15 | 16 | /// 17 | /// Gets the vector dimension of the vectors generated by the vectorizer. 18 | /// 19 | int Dim { get; } 20 | 21 | /// 22 | /// Converts the provided object to a vector. 23 | /// 24 | /// the object to convert. 25 | /// A byte array containing the vectorized data. 26 | byte[] Vectorize(T obj); 27 | } 28 | } -------------------------------------------------------------------------------- /src/Redis.OM/Extensions/TimespanExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace Redis.OM; 5 | 6 | /// 7 | /// Extension methods for Timespans. 8 | /// 9 | internal static class TimespanExtensions 10 | { 11 | /// 12 | /// Rounds up total milliseconds as an integer. 13 | /// 14 | /// the timespan. 15 | /// the rounded timespan milliseconds. 16 | public static string TotalMillisecondsString(this TimeSpan ts) 17 | { 18 | return Math.Ceiling(ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture); 19 | } 20 | } -------------------------------------------------------------------------------- /src/Redis.OM/GeoLoc.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace Redis.OM.Modeling 5 | { 6 | /// 7 | /// A structure representing a point on the globe by it's longitude and latitude. 8 | /// 9 | public struct GeoLoc 10 | { 11 | /// 12 | /// Initializes a new instance of the struct. 13 | /// 14 | /// The longitude. 15 | /// The latitude. 16 | public GeoLoc(double longitude, double latitude) 17 | { 18 | Longitude = longitude; 19 | Latitude = latitude; 20 | } 21 | 22 | /// 23 | /// Gets or sets the longitude. 24 | /// 25 | public double Longitude { get; set; } 26 | 27 | /// 28 | /// Gets or sets the latitude. 29 | /// 30 | public double Latitude { get; set; } 31 | 32 | /// 33 | /// Parses a Geolocation from a string. 34 | /// 35 | /// the string representation of a geoloc. 36 | /// a geoloc parsed from the string. 37 | /// thrown if the geoloc could not be parsed from the string. 38 | public static GeoLoc Parse(string geolocString) 39 | { 40 | var arr = geolocString.Split(','); 41 | if (arr.Length == 2) 42 | { 43 | if (double.TryParse(arr[0], NumberStyles.Number, CultureInfo.InvariantCulture, out var lon) && 44 | double.TryParse(arr[1], NumberStyles.Number, CultureInfo.InvariantCulture, out var lat)) 45 | { 46 | return new GeoLoc(lon, lat); 47 | } 48 | } 49 | 50 | throw new ArgumentException("GeoLoc string must be a string in the format longitude,latitude"); 51 | } 52 | 53 | /// 54 | public override string ToString() 55 | { 56 | return $"{Longitude.ToString(CultureInfo.InvariantCulture)},{Latitude.ToString(CultureInfo.InvariantCulture)}"; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Redis.OM/GeoLocDistanceUnit.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// A distance unit. 5 | /// 6 | public enum GeoLocDistanceUnit 7 | { 8 | /// 9 | /// meters. 10 | /// 11 | Meters = 0, 12 | 13 | /// 14 | /// kilometers. 15 | /// 16 | Kilometers = 1, 17 | 18 | /// 19 | /// miles. 20 | /// 21 | Miles = 2, 22 | 23 | /// 24 | /// feet. 25 | /// 26 | Feet = 3, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Redis.OM/IIdGenerationStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// The strategy the library will use for generating unique IDs. 5 | /// 6 | public interface IIdGenerationStrategy 7 | { 8 | /// 9 | /// generates a unique id. 10 | /// 11 | /// the id. 12 | string GenerateId(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/DateTimeJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Redis.OM.Modeling 6 | { 7 | /// 8 | /// DateTime converter for JSON serialization. 9 | /// 10 | public class DateTimeJsonConverter : JsonConverter 11 | { 12 | /// 13 | public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 14 | { 15 | long val = reader.TokenType == JsonTokenType.String ? long.Parse(reader.GetString() !) : reader.GetInt64(); 16 | 17 | DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 18 | return TimeZoneInfo.ConvertTimeFromUtc(dateTime.AddMilliseconds(val), RedisSerializationSettings.TimeZone); 19 | } 20 | 21 | /// 22 | public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) 23 | { 24 | writer.WriteNumberValue(new DateTimeOffset(value).ToUnixTimeMilliseconds()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/DelDiff.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// A diff that will delete the property. 7 | /// 8 | internal class DelDiff : IObjectDiff 9 | { 10 | /// 11 | public string Script => nameof(Scripts.Unlink); 12 | 13 | /// 14 | public string[] SerializeScriptArgs() 15 | { 16 | return Array.Empty(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/DocumentAttributeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// utility functions for document attribute class. 7 | /// 8 | internal static class DocumentAttributeExtensions 9 | { 10 | /// 11 | /// Get's the index name for the attribute and type. 12 | /// 13 | /// The document attribute. 14 | /// The type. 15 | /// The index name. 16 | internal static string GetIndexName(this DocumentAttribute attr, Type type) => string.IsNullOrEmpty(attr.IndexName) ? $"{type.Name.ToLower()}-idx" : attr.IndexName!; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/GeoLocJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace Redis.OM.Modeling 7 | { 8 | /// 9 | /// Json Converter for converting to and from JSON. 10 | /// 11 | public class GeoLocJsonConverter : JsonConverter 12 | { 13 | /// 14 | /// Parse JSON into a GeoLoc. 15 | /// 16 | /// the reader. 17 | /// the type to convert. 18 | /// the options. 19 | /// A geoloc parsed from json. 20 | /// thrown if geoloc not in valid format for parsing. 21 | public override GeoLoc Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 22 | { 23 | var str = reader.GetString(); 24 | if (str != null) 25 | { 26 | var split = str.Split(','); 27 | if (split.Length == 2) 28 | { 29 | if (double.TryParse(split[0], NumberStyles.Number, CultureInfo.InvariantCulture, out var lon) && 30 | double.TryParse(split[1], NumberStyles.Number, CultureInfo.InvariantCulture, out var lat)) 31 | { 32 | return new GeoLoc(lon, lat); 33 | } 34 | } 35 | } 36 | 37 | throw new FormatException("GeoLoc was not in a valid format to be parsed"); 38 | } 39 | 40 | /// 41 | /// Writes the to a string for JSON. 42 | /// 43 | /// the writer. 44 | /// the . 45 | /// The options. 46 | public override void Write(Utf8JsonWriter writer, GeoLoc value, JsonSerializerOptions options) 47 | { 48 | writer.WriteStringValue(value.ToString()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/HashDiff.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Redis.OM.Modeling 5 | { 6 | /// 7 | /// A diff for a hash type object. 8 | /// 9 | internal class HashDiff : IObjectDiff 10 | { 11 | private readonly IEnumerable> _setFieldValuePairs; 12 | private readonly IEnumerable _delValues; 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// values to set. 18 | /// values to delete. 19 | public HashDiff(IEnumerable> setSetFieldValuePairs, IEnumerable delValues) 20 | { 21 | _setFieldValuePairs = setSetFieldValuePairs; 22 | _delValues = delValues; 23 | } 24 | 25 | /// 26 | public string Script => nameof(Scripts.HashDiffResolution); 27 | 28 | /// 29 | public string[] SerializeScriptArgs() 30 | { 31 | var ret = new List { _setFieldValuePairs.Count().ToString() }; 32 | foreach (var kvp in _setFieldValuePairs) 33 | { 34 | ret.Add(kvp.Key); 35 | ret.Add(kvp.Value); 36 | } 37 | 38 | ret.AddRange(_delValues); 39 | return ret.ToArray(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/IObjectDiff.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Modeling 2 | { 3 | /// 4 | /// Handles resolving the difference between a snapshot and a current iteration of an object. 5 | /// 6 | internal interface IObjectDiff 7 | { 8 | /// 9 | /// Gets the name of the script to use. 10 | /// 11 | string Script { get; } 12 | 13 | /// 14 | /// Arguments for the script serialized. 15 | /// 16 | /// The args. 17 | string[] SerializeScriptArgs(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/RedisFieldAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// An attribute representing a particular field to be stored in redis. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property)] 9 | public class RedisFieldAttribute : Attribute 10 | { 11 | /// 12 | /// Gets or sets the property's name in redis. 13 | /// 14 | public string PropertyName { get; set; } = string.Empty; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/RedisIdFieldAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// Indicates which is the Id field. 7 | /// 8 | public class RedisIdFieldAttribute : Attribute 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/RedisIndexingException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// An exception thrown when trying to index classes in Redis. 7 | /// 8 | public class RedisIndexingException : Exception 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// the message. 14 | public RedisIndexingException(string message) 15 | : base(message) 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/SearchFieldAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Modeling 5 | { 6 | /// 7 | /// Decorates a field that you want to index. 8 | /// 9 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 10 | public abstract class SearchFieldAttribute : RedisFieldAttribute 11 | { 12 | /// 13 | /// Gets or sets a value indicating whether the field will be sortable. 14 | /// 15 | public bool Sortable { get; set; } 16 | 17 | /// 18 | /// Gets or sets a value indicating whether the field will be aggregatable. 19 | /// 20 | public bool Aggregatable { get; set; } 21 | 22 | /// 23 | /// Gets or sets a value indicating whether text will be normalized when indexed 24 | /// (sent to lower case with no diacritics). Defaults to true. 25 | /// 26 | public bool Normalize { get; set; } = true; 27 | 28 | /// 29 | /// Gets or sets the JSON path to the desired attribute to index. This is used for 30 | /// indexing individual fields within objects. Defaults to ".", which assumes the entire field will be indexed 31 | /// If the indexed field is a scalar, it will only index that field. If that index is an object the index 32 | /// will be recursively built based off the . 33 | /// 34 | public string? JsonPath { get; set; } 35 | 36 | /// 37 | /// Gets or sets the depth into the object graph to automatically generate the index. 38 | /// 39 | public int CascadeDepth { get; set; } 40 | 41 | /// 42 | /// Gets or sets a value indicating whether to index empty and missing values. 43 | /// If this is true (the default) you will be able to query null and empty string values in Redis. 44 | /// 45 | public bool IndexEmptyAndMissing { get; set; } = true; 46 | 47 | /// 48 | /// Gets the type of index. 49 | /// 50 | internal abstract SearchFieldType SearchFieldType { get; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/SearchFieldType.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Modeling 2 | { 3 | /// 4 | /// The search field type. 5 | /// 6 | internal enum SearchFieldType 7 | { 8 | /// 9 | /// A text index field. 10 | /// 11 | TEXT = 0, 12 | 13 | /// 14 | /// A numeric index field. 15 | /// 16 | NUMERIC = 1, 17 | 18 | /// 19 | /// A geo index field. 20 | /// 21 | GEO = 2, 22 | 23 | /// 24 | /// A tag index field. 25 | /// 26 | TAG = 3, 27 | 28 | /// 29 | /// A generically indexed field - the library will figure out how to index. 30 | /// 31 | INDEXED = 4, 32 | 33 | /// 34 | /// A vector index field. 35 | /// 36 | VECTOR = 5, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/SearchableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Modeling 5 | { 6 | /// 7 | /// Marks a field as searchable within a Redis Document. 8 | /// 9 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 10 | public sealed class SearchableAttribute : SearchFieldAttribute 11 | { 12 | /// 13 | /// Gets or sets a value indicating whether whether or not to index with stemming. 14 | /// 15 | public bool NoStem { get; set; } = false; 16 | 17 | /// 18 | /// Gets or sets a value indicting which phonetic matcher to use. 19 | /// 20 | public string PhoneticMatcher { get; set; } = string.Empty; 21 | 22 | /// 23 | /// Gets or sets the weight of a given field. 24 | /// 25 | public double Weight { get; set; } = 1; 26 | 27 | /// 28 | internal override SearchFieldType SearchFieldType => SearchFieldType.TEXT; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/StorageType.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Modeling 2 | { 3 | /// 4 | /// Determine how the item will be stored in Redis. 5 | /// 6 | public enum StorageType 7 | { 8 | /// 9 | /// Store as a hash. 10 | /// 11 | Hash = 0, 12 | 13 | /// 14 | /// Store as JSON. 15 | /// 16 | Json = 1, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/DistanceMetric.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// The Vector distance metric to use. 7 | /// 8 | public enum DistanceMetric 9 | { 10 | /// 11 | /// Euclidean distance. 12 | /// 13 | L2, 14 | 15 | /// 16 | /// Inner Product. 17 | /// 18 | IP, 19 | 20 | /// 21 | /// The Cosine distance. 22 | /// 23 | COSINE, 24 | } 25 | 26 | /// 27 | /// Quality of life extensions for distance metrics. 28 | /// 29 | internal static class DistanceMetricExtensions 30 | { 31 | /// 32 | /// Gets the Distance metric as a Redis usable string. 33 | /// 34 | /// The distance Metric. 35 | /// A Redis Usable string. 36 | /// thrown if illegal ordinal encountered. 37 | internal static string AsRedisString(this DistanceMetric distanceMetric) 38 | { 39 | return distanceMetric switch 40 | { 41 | DistanceMetric.L2 => "L2", 42 | DistanceMetric.IP => "IP", 43 | DistanceMetric.COSINE => "COSINE", 44 | _ => throw new ArgumentOutOfRangeException(nameof(distanceMetric)) 45 | }; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/DoubleVectorizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Redis.OM.Contracts; 4 | 5 | namespace Redis.OM.Modeling.Vectors; 6 | 7 | /// 8 | /// A vectorizer for double arrays. 9 | /// 10 | public class DoubleVectorizer : IVectorizer 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | /// The dimensions. 16 | public DoubleVectorizer(int dim) 17 | { 18 | Dim = dim; 19 | } 20 | 21 | /// 22 | public VectorType VectorType => VectorType.FLOAT64; 23 | 24 | /// 25 | public int Dim { get; } 26 | 27 | /// 28 | public byte[] Vectorize(double[] obj) => obj.SelectMany(BitConverter.GetBytes).ToArray(); 29 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/DoubleVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Contracts; 3 | 4 | namespace Redis.OM.Modeling.Vectors; 5 | 6 | /// 7 | /// A vectorizer attribute for doubles. 8 | /// 9 | public class DoubleVectorizerAttribute : VectorizerAttribute 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// the dimensions. 15 | public DoubleVectorizerAttribute(int dim) 16 | { 17 | Dim = dim; 18 | Vectorizer = new DoubleVectorizer(dim); 19 | } 20 | 21 | /// 22 | public override IVectorizer Vectorizer { get; } 23 | 24 | /// 25 | public override VectorType VectorType => VectorType.FLOAT64; 26 | 27 | /// 28 | public override int Dim { get; } 29 | 30 | /// 31 | public override byte[] Vectorize(object obj) 32 | { 33 | if (obj is not double[] doubles) 34 | { 35 | throw new InvalidOperationException("Provided object for vectorization must be a double[]"); 36 | } 37 | 38 | return Vectorizer.Vectorize(doubles); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/FloatVectorizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Redis.OM.Contracts; 4 | using Redis.OM.Modeling; 5 | 6 | namespace Redis.OM; 7 | 8 | /// 9 | /// A vectorizer for float arrays. 10 | /// 11 | public class FloatVectorizer : IVectorizer 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The dimensions. 17 | public FloatVectorizer(int dim) 18 | { 19 | Dim = dim; 20 | } 21 | 22 | /// 23 | public VectorType VectorType => VectorType.FLOAT32; 24 | 25 | /// 26 | public int Dim { get; } 27 | 28 | /// 29 | public byte[] Vectorize(float[] obj) => obj.SelectMany(BitConverter.GetBytes).ToArray(); 30 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/FloatVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Redis.OM.Contracts; 4 | 5 | namespace Redis.OM.Modeling.Vectors; 6 | 7 | /// 8 | public class FloatVectorizerAttribute : VectorizerAttribute 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The dimensions of the vector. 14 | public FloatVectorizerAttribute(int dim) 15 | { 16 | Dim = dim; 17 | Vectorizer = new FloatVectorizer(dim); 18 | } 19 | 20 | /// 21 | public override VectorType VectorType => VectorType.FLOAT32; 22 | 23 | /// 24 | public override int Dim { get; } 25 | 26 | /// 27 | public override IVectorizer Vectorizer { get; } 28 | 29 | /// 30 | public override byte[] Vectorize(object obj) 31 | { 32 | if (obj is not float[] floats) 33 | { 34 | throw new InvalidOperationException("Must pass in an array of floats"); 35 | } 36 | 37 | return Vectorizer.Vectorize(floats); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/JsonScoreConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Redis.OM.Modeling 6 | { 7 | /// 8 | /// ignores the Json Score field. 9 | /// 10 | internal class JsonScoreConverter : JsonConverter 11 | { 12 | /// 13 | public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(double) || typeToConvert == typeof(double?); 14 | 15 | /// 16 | public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 17 | { 18 | return -1.0; 19 | } 20 | 21 | /// 22 | public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) 23 | { 24 | writer.WriteNumberValue(-1.0); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorAlgorithm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// The Vector Algorithm. 7 | /// 8 | public enum VectorAlgorithm 9 | { 10 | /// 11 | /// Uses a brute force algorithm to find nearest neighbors. 12 | /// 13 | FLAT = 0, 14 | 15 | /// 16 | /// Uses the Hierarchical Small World Algorithm to build an efficient graph structure to 17 | /// retrieve approximate nearest neighbors 18 | /// 19 | HNSW = 1, 20 | } 21 | 22 | /// 23 | /// Quality of life functions for VectorAlgorithm enum. 24 | /// 25 | internal static class VectorAlgorithmExtensions 26 | { 27 | /// 28 | /// Returns the algorithm as a Redis Serialized String. 29 | /// 30 | /// The algorithm to use. 31 | /// The algorithm's name. 32 | /// Thrown if an invalid Algorithm is passed. 33 | internal static string AsRedisString(this VectorAlgorithm algorithm) 34 | { 35 | return algorithm switch 36 | { 37 | VectorAlgorithm.FLAT => "FLAT", 38 | VectorAlgorithm.HNSW => "HNSW", 39 | _ => throw new ArgumentOutOfRangeException(nameof(algorithm)) 40 | }; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorResult.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// Represents a vector result with its score and the document associated with it. 5 | /// 6 | /// the document type. 7 | public class VectorResult 8 | { 9 | /// 10 | /// Initializes a new instance of the class. 11 | /// 12 | /// the document. 13 | /// the score. 14 | internal VectorResult(T document, double score) 15 | { 16 | Score = score; 17 | Document = document; 18 | } 19 | 20 | /// 21 | /// Gets the document. 22 | /// 23 | public T Document { get; } 24 | 25 | /// 26 | /// Gets the score. 27 | /// 28 | public double Score { get; } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorScoreField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Redis.OM.Modeling 5 | { 6 | /// 7 | /// Attribute to decorate vector score field. A field decorated with this will have the sentinel value -1 when 8 | /// the score is not present in the result. 9 | /// 10 | public class KnnVectorScore : JsonConverterAttribute 11 | { 12 | /// 13 | public override JsonConverter? CreateConverter(Type typeToConvert) 14 | { 15 | return new JsonScoreConverter(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorScores.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Redis.OM.Modeling.Vectors 6 | { 7 | /// 8 | /// A collector for vector scores, binding this to your model causes Redis OM to bind all scores resulting from 9 | /// a vector query to it. Otherwise it will be ignored when it is added to Redis. 10 | /// 11 | public class VectorScores 12 | { 13 | /// 14 | /// The Range score suffix. 15 | /// 16 | internal const string RangeScoreSuffix = "_RangeScore"; 17 | 18 | /// 19 | /// The Nearest neighbor score name. 20 | /// 21 | internal const string NearestNeighborScoreName = "KnnNeighborScore"; 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | internal VectorScores() 27 | { 28 | } 29 | 30 | /// 31 | /// Gets the nearest neighbor score. 32 | /// 33 | [JsonIgnore] 34 | public double? NearestNeighborsScore { get; internal set; } 35 | 36 | /// 37 | /// Gets the first score from the vector ranges. 38 | /// 39 | [JsonIgnore] 40 | public double? RangeScore => RangeScores.FirstOrDefault().Value; 41 | 42 | /// 43 | /// Gets or sets the range score dictionary. 44 | /// 45 | [JsonIgnore] 46 | internal Dictionary RangeScores { get; set; } = new (); 47 | } 48 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM.Modeling 4 | { 5 | /// 6 | /// Type of Vector. 7 | /// 8 | public enum VectorType 9 | { 10 | /// 11 | /// Float 32s. 12 | /// 13 | FLOAT32, 14 | 15 | /// 16 | /// Float 64s. 17 | /// 18 | FLOAT64, 19 | } 20 | 21 | /// 22 | /// Extensions for VectorType. 23 | /// 24 | internal static class VectorTypeExtensions 25 | { 26 | /// 27 | /// Gets the Vector type as a Redis usable string. 28 | /// 29 | /// The Vector type. 30 | /// A Redis Usable string. 31 | /// Thrown if illegal value for Vector type is encountered. 32 | internal static string AsRedisString(this VectorType vectorType) 33 | { 34 | return vectorType switch 35 | { 36 | VectorType.FLOAT32 => "FLOAT32", 37 | VectorType.FLOAT64 => "FLOAT64", 38 | _ => throw new ArgumentOutOfRangeException(nameof(vectorType)) 39 | }; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Redis.OM/Modeling/Vectors/VectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | using Redis.OM.Contracts; 4 | 5 | namespace Redis.OM.Modeling 6 | { 7 | /// 8 | /// A vectorizer attribute. 9 | /// 10 | public abstract class VectorizerAttribute : JsonConverterAttribute 11 | { 12 | /// 13 | /// Gets the number of bytes per vector. 14 | /// 15 | public int BytesPerVector => VectorType == VectorType.FLOAT32 ? 4 * Dim : 8 * Dim; 16 | 17 | /// 18 | /// Gets the vector Type generated by the vectorizer. 19 | /// 20 | public abstract VectorType VectorType { get; } 21 | 22 | /// 23 | /// Gets the vector dimension of the vectors generated by the vectorizer. 24 | /// 25 | public abstract int Dim { get; } 26 | 27 | /// 28 | /// Converts the provided object to a vector. 29 | /// 30 | /// the object to convert. 31 | /// A byte array containing the vectorized data. 32 | public abstract byte[] Vectorize(object obj); 33 | } 34 | 35 | /// 36 | /// Method for converting a field into a vector. 37 | /// 38 | /// The type. 39 | #pragma warning disable SA1402 40 | public abstract class VectorizerAttribute : VectorizerAttribute 41 | where T : class 42 | #pragma warning restore SA1402 43 | { 44 | /// 45 | /// Gets the vectorizer for this attribute. 46 | /// 47 | /// The vectorizer. 48 | public abstract IVectorizer Vectorizer { get; } 49 | 50 | /// 51 | /// Creates the json converter fulfilled by this attribute. 52 | /// 53 | /// The type to convert. 54 | /// The Json Converter. 55 | public override JsonConverter? CreateConverter(Type typeToConvert) 56 | { 57 | return new VectorJsonConverter(this); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Redis.OM/RedisConnectionConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// Configuration to use to configure redis. 5 | /// 6 | public class RedisConnectionConfiguration 7 | { 8 | /// 9 | /// Gets or sets the Host name. 10 | /// 11 | public string Host { get; set; } = "localhost"; 12 | 13 | /// 14 | /// Gets or sets the Port. 15 | /// 16 | public int Port { get; set; } = 6379; 17 | 18 | /// 19 | /// Gets or sets the password. 20 | /// 21 | public string? Password { get; set; } 22 | 23 | /// 24 | /// Builds SE connection string. 25 | /// 26 | /// A connection string. 27 | public string ToStackExchangeConnectionString() => $"{Host}:{Port},password={Password}"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Redis.OM/RedisSerializationSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | using Redis.OM.Modeling; 5 | 6 | namespace Redis.OM 7 | { 8 | /// 9 | /// Configurable settings for how serialization and deserialization is handled. 10 | /// 11 | public static class RedisSerializationSettings 12 | { 13 | /// 14 | /// used when serializing. 15 | /// 16 | public static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions() 17 | { 18 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, 19 | }; 20 | 21 | static RedisSerializationSettings() 22 | { 23 | JsonSerializerOptions.Converters.Add(new GeoLocJsonConverter()); 24 | JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter()); 25 | } 26 | 27 | /// 28 | /// Gets default/assumed timezone used by redis when deserializing datetimes. 29 | /// 30 | public static TimeZoneInfo TimeZone { get; private set; } = TimeZoneInfo.Local; 31 | 32 | /// 33 | /// Set the default/assumed for deserialization to instead of . 34 | /// 35 | public static void UseUtcTime() 36 | { 37 | TimeZone = TimeZoneInfo.Utc; 38 | } 39 | 40 | /// 41 | /// Set the default/assumed for deserialization to the default of . 42 | /// 43 | public static void UseLocalTime() 44 | { 45 | TimeZone = TimeZoneInfo.Local; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/NearestNeighbors.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Searching.Query 2 | { 3 | /// 4 | /// Components of a KNN search. 5 | /// 6 | public class NearestNeighbors 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | /// The property name to search on. 12 | /// The number of nearest neighbors. 13 | /// The vector blob. 14 | public NearestNeighbors(string propertyName, int numNeighbors, byte[] vectorBlob) 15 | { 16 | PropertyName = propertyName; 17 | NumNeighbors = numNeighbors; 18 | VectorBlob = vectorBlob; 19 | } 20 | 21 | /// 22 | /// Gets the name of the property to perform the vector search on. 23 | /// 24 | public string PropertyName { get; } 25 | 26 | /// 27 | /// Gets the number of neighbors to find. 28 | /// 29 | public int NumNeighbors { get; } 30 | 31 | /// 32 | /// Gets the Vector blob to search on. 33 | /// 34 | public byte[] VectorBlob { get; } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/QueryFlags.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Searching.Query 2 | { 3 | /// 4 | /// Flags to indicate the options of a query. 5 | /// 6 | public enum QueryFlags 7 | { 8 | /// 9 | /// If it appears after the query, we only return the document ids and not the content. 10 | /// This is useful if RediSearch is only an index on an external document collection. 11 | /// 12 | Nocontent = 1, 13 | 14 | /// 15 | /// if set, we do not try to use stemming for query expansion but search the query terms verbatim. 16 | /// 17 | Verbatim = 2, 18 | 19 | /// 20 | /// If set, we do not filter stop words from the query. 21 | /// 22 | NoStopWords = 4, 23 | 24 | /// 25 | /// If set, we also return the relative internal score of each document. T 26 | /// his can be used to merge results from multiple instances. 27 | /// 28 | WithScores = 8, 29 | 30 | /// 31 | /// If set, we retrieve optional document payloads (see FT.ADD). the payloads follow the document id, 32 | /// and if WITHSCORES was set, follow the scores. 33 | /// 34 | WithPayloads = 16, 35 | 36 | /// 37 | /// Only relevant in conjunction with SORTBY . Returns the value of the sorting key, right after the id and 38 | /// score and /or payload if requested. This is usually not needed by users, 39 | /// and exists for distributed search coordination purposes. 40 | /// 41 | WithSortKeys = 32, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/QueryOption.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Searching.Query 4 | { 5 | /// 6 | /// An option within a query. 7 | /// 8 | public abstract class QueryOption 9 | { 10 | /// 11 | /// Gets a serialized array of strings for a query. 12 | /// 13 | internal abstract IEnumerable SerializeArgs { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/RedisFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Searching.Query 4 | { 5 | /// 6 | /// Filter to use when querying. 7 | /// 8 | public class RedisFilter : QueryOption 9 | { 10 | /// 11 | /// Gets or sets field filter on. 12 | /// 13 | private readonly string _fieldName; 14 | 15 | /// 16 | /// Gets or sets the min. 17 | /// 18 | private readonly int _min; 19 | 20 | /// 21 | /// Gets or sets the max. 22 | /// 23 | private readonly int _max; 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// the field name. 29 | /// the min value. 30 | /// the max value. 31 | public RedisFilter(string fieldName, int min = int.MinValue, int max = int.MaxValue) 32 | { 33 | _fieldName = fieldName; 34 | _min = min; 35 | _max = max; 36 | } 37 | 38 | /// 39 | internal override IEnumerable SerializeArgs 40 | { 41 | get 42 | { 43 | var ret = new List(); 44 | ret.Add("FILTER"); 45 | ret.Add(_fieldName); 46 | ret.Add(_min.ToString()); 47 | ret.Add(_max.ToString()); 48 | return ret.ToArray(); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/RedisGeoFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | 5 | namespace Redis.OM.Searching.Query 6 | { 7 | /// 8 | /// A geographic filter. 9 | /// 10 | public class RedisGeoFilter : QueryOption 11 | { 12 | private readonly string _fieldName; 13 | private readonly double _longitude; 14 | private readonly double _latitude; 15 | private readonly double _radius; 16 | private readonly GeoLocDistanceUnit _unit; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// the field to filter. 22 | /// the longitude. 23 | /// the latitude. 24 | /// radius. 25 | /// the unit. 26 | public RedisGeoFilter(string field, double longitude, double latitude, double radius, GeoLocDistanceUnit unit) 27 | { 28 | _fieldName = field; 29 | _longitude = longitude; 30 | _latitude = latitude; 31 | _radius = radius; 32 | _unit = unit; 33 | } 34 | 35 | /// 36 | internal override IEnumerable SerializeArgs 37 | { 38 | get 39 | { 40 | var unitString = _unit switch 41 | { 42 | GeoLocDistanceUnit.Feet => "ft", 43 | GeoLocDistanceUnit.Kilometers => "km", 44 | GeoLocDistanceUnit.Meters => "m", 45 | GeoLocDistanceUnit.Miles => "mi", 46 | _ => throw new Exception("Invalid unit") 47 | }; 48 | return new[] 49 | { 50 | "GEOFILTER", 51 | _fieldName, 52 | _longitude.ToString(CultureInfo.InvariantCulture), 53 | _latitude.ToString(CultureInfo.InvariantCulture), 54 | _radius.ToString(CultureInfo.InvariantCulture), 55 | unitString, 56 | }; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/RedisSortBy.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Redis.OM; 3 | 4 | namespace Redis.OM.Searching.Query 5 | { 6 | /// 7 | /// a sort-by predicate for a search. 8 | /// 9 | public class RedisSortBy : QueryOption 10 | { 11 | /// 12 | /// gets or sets the field to sort by. 13 | /// 14 | public string Field { get; set; } = string.Empty; 15 | 16 | /// 17 | /// Gets or sets the direction to sort by. 18 | /// 19 | public SortDirection Direction { get; set; } 20 | 21 | /// 22 | internal override IEnumerable SerializeArgs 23 | { 24 | get 25 | { 26 | var dir = Direction == SortDirection.Ascending ? "ASC" : "DESC"; 27 | return new[] 28 | { 29 | "SORTBY", 30 | Field, 31 | dir, 32 | }; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/ReturnField.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Searching.Query 2 | { 3 | /// 4 | /// Represents a return field with a name and an optional alias. 5 | /// 6 | public struct ReturnField 7 | { 8 | /// 9 | /// The name of the return field. 10 | /// 11 | public string Name; 12 | 13 | /// 14 | /// An optional alias for the return field. 15 | /// 16 | public string? Alias; 17 | 18 | /// 19 | /// Initializes a new instance of the struct with the specified name and alias. 20 | /// 21 | /// The name of the return field. 22 | /// An optional alias for the return field. 23 | public ReturnField(string name, string alias) 24 | { 25 | Name = name; 26 | Alias = alias; 27 | } 28 | 29 | /// 30 | /// Initializes a new instance of the struct with the specified name. 31 | /// 32 | /// The name of the return field. 33 | public ReturnField(string name) 34 | { 35 | Name = name; 36 | Alias = null; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/ReturnFields.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Redis.OM.Searching.Query 6 | { 7 | /// 8 | /// Predicate denoting the fields that will be returned from redis. 9 | /// 10 | public class ReturnFields : QueryOption 11 | { 12 | /// 13 | /// The fields to bring back. 14 | /// 15 | private readonly IEnumerable _fields; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// the fields to return. 21 | public ReturnFields(IEnumerable fields) 22 | { 23 | _fields = fields.Select(x => new ReturnField(x)); 24 | } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// the fields to return. 30 | public ReturnFields(IEnumerable fields) 31 | { 32 | _fields = fields; 33 | } 34 | 35 | /// 36 | internal override IEnumerable SerializeArgs 37 | { 38 | get 39 | { 40 | var ret = new List { "RETURN", (_fields.Count() + (_fields.Count(x => x.Alias != null) * 2)).ToString() }; 41 | foreach (var field in _fields) 42 | { 43 | ret.Add($"{field.Name}"); 44 | if (field.Alias != null) 45 | { 46 | ret.Add("AS"); 47 | ret.Add(field.Alias); 48 | } 49 | } 50 | 51 | return ret.ToArray(); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/Query/SearchLimit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Redis.OM.Searching.Query 4 | { 5 | /// 6 | /// Limits the search results. 7 | /// 8 | public class SearchLimit : QueryOption 9 | { 10 | /// 11 | /// Gets or sets the offset into the result to start at. 12 | /// 13 | public int Offset { get; set; } 14 | 15 | /// 16 | /// Gets or sets the number of items to return. 17 | /// 18 | public int Number { get; set; } = 10; 19 | 20 | /// 21 | internal override IEnumerable SerializeArgs 22 | { 23 | get 24 | { 25 | return new[] 26 | { 27 | "LIMIT", 28 | Offset.ToString(), 29 | Number.ToString(), 30 | }; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Redis.OM/Searching/SortDirection.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Searching 2 | { 3 | /// 4 | /// The direction to sort. 5 | /// 6 | public enum SortDirection 7 | { 8 | /// 9 | /// Ascending. 10 | /// 11 | Ascending, 12 | 13 | /// 14 | /// Descending 15 | /// 16 | Descending, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Redis.OM/SemanticCacheResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// A response to a Semantic Cache Query. 5 | /// 6 | public class SemanticCacheResponse 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | /// The key. 12 | /// The string response. 13 | /// The Score. 14 | /// The metadata. 15 | internal SemanticCacheResponse(string key, string response, double score, object? metaData) 16 | { 17 | Key = key; 18 | Response = response; 19 | Score = score; 20 | MetaData = metaData; 21 | } 22 | 23 | /// 24 | /// Gets the key. 25 | /// 26 | public string Key { get; } 27 | 28 | /// 29 | /// Gets the response. 30 | /// 31 | public string Response { get; } 32 | 33 | /// 34 | /// Gets the score. 35 | /// 36 | public double Score { get; } 37 | 38 | /// 39 | /// Gets the metadata. 40 | /// 41 | public object? MetaData { get; } 42 | 43 | /// 44 | /// Converts response to string implicitly. 45 | /// 46 | /// The response. 47 | /// The response string. 48 | public static implicit operator string(SemanticCacheResponse response) => response.Response; 49 | } 50 | } -------------------------------------------------------------------------------- /src/Redis.OM/UlidGenerationStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.OM 4 | { 5 | /// 6 | /// generation strategy that generates a ULID. 7 | /// 8 | public class UlidGenerationStrategy : IIdGenerationStrategy 9 | { 10 | /// 11 | /// Generates a ULID. 12 | /// 13 | /// A Ulid. 14 | public string GenerateId() 15 | { 16 | return Ulid.NewUlid().ToString(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Redis.OM/Uuid4IdGenerationStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Redis.OM 5 | { 6 | /// 7 | /// Generation strategy to creat UUID4 Ids. 8 | /// 9 | public class Uuid4IdGenerationStrategy : IIdGenerationStrategy 10 | { 11 | /// 12 | public string GenerateId() 13 | { 14 | return Guid.NewGuid().ToString(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Redis.OM/WhenKey.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM 2 | { 3 | /// 4 | /// Indicates when this operation should be performed (only some variations are legal in a given context). 5 | /// 6 | public enum WhenKey 7 | { 8 | /// 9 | /// The operation should occur whether or not there is an existing value. 10 | /// 11 | Always, 12 | 13 | /// 14 | /// The operation should only occur when there is an existing value. 15 | /// 16 | Exists, 17 | 18 | /// 19 | /// The operation should only occur when there is not an existing value. 20 | /// 21 | NotExists, 22 | } 23 | } -------------------------------------------------------------------------------- /src/Redis.OM/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "indentation": { 5 | "useTabs": false 6 | }, 7 | "layoutRules": { 8 | "newlineAtEndOfFile": "require" 9 | }, 10 | "orderingRules": { 11 | "blankLinesBetweenUsingGroups": "omit", 12 | "usingDirectivesPlacement": "outsideNamespace" 13 | }, 14 | "namingRules": { 15 | "SX1309": true 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Redis.OM/stylecop.ruleset: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Redis.Developer.Test.AspDotnetCore.Controllers 9 | { 10 | [ApiController] 11 | [Route("[controller]")] 12 | public class WeatherForecastController : ControllerBase 13 | { 14 | private static readonly string[] Summaries = new[] 15 | { 16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 17 | }; 18 | 19 | private readonly ILogger _logger; 20 | 21 | public WeatherForecastController(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | [HttpGet] 27 | public IEnumerable Get() 28 | { 29 | var rng = new Random(); 30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 31 | { 32 | Date = DateTime.Now.AddDays(index), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = Summaries[rng.Next(Summaries.Length)] 35 | }) 36 | .ToArray(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace Redis.Developer.Test.AspDotnetCore 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); 22 | } 23 | } -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:40618", 8 | "sslPort": 44360 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Redis.Developer.Test.AspDotnetCore": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/Redis.OM.Test.AspDotnetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | Redis.Developer.Test.AspDotnetCore 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.HttpsPolicy; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.Extensions.Hosting; 12 | using Microsoft.Extensions.Logging; 13 | using Microsoft.OpenApi.Models; 14 | 15 | namespace Redis.Developer.Test.AspDotnetCore 16 | { 17 | public class Startup 18 | { 19 | public Startup(IConfiguration configuration) 20 | { 21 | Configuration = configuration; 22 | } 23 | 24 | public IConfiguration Configuration { get; } 25 | 26 | // This method gets called by the runtime. Use this method to add services to the container. 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | services.AddControllers(); 30 | services.AddSwaggerGen(c => 31 | { 32 | c.SwaggerDoc("v1", new OpenApiInfo {Title = "Redis.OM.Test.AspDotnetCore", Version = "v1"}); 33 | }); 34 | } 35 | 36 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 37 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 38 | { 39 | if (env.IsDevelopment()) 40 | { 41 | app.UseDeveloperExceptionPage(); 42 | app.UseSwagger(); 43 | app.UseSwaggerUI(c => 44 | c.SwaggerEndpoint("/swagger/v1/swagger.json", "Redis.OM.Test.AspDotnetCore v1")); 45 | } 46 | 47 | app.UseHttpsRedirection(); 48 | 49 | app.UseRouting(); 50 | 51 | app.UseAuthorization(); 52 | 53 | app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Redis.Developer.Test.AspDotnetCore 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Redis.OM.Test.AspDotnetCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /test/Redis.OM.Test.ConsoleApp/Redis.OM.Test.ConsoleApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | Redis.OM.Test.ConsoleApp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Address.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Text.Json.Serialization; 7 | using System.Threading.Tasks; 8 | using Redis.OM.Modeling; 9 | 10 | namespace Redis.OM.Unit.Tests 11 | { 12 | [Document(IndexName = "address-idx", StorageType = StorageType.Json)] 13 | public partial class Address 14 | { 15 | public string StreetName { get; set; } 16 | public string ZipCode { get; set; } 17 | [JsonConverter(typeof(JsonStringEnumConverter))] 18 | [Indexed] 19 | public AddressType? AddressType { get; set; } 20 | [Indexed] public string City { get; set; } 21 | [Indexed] public string State { get; set; } 22 | [Indexed(CascadeDepth = 1)] public Address ForwardingAddress { get; set; } 23 | [Indexed] public GeoLoc? Location { get; set; } 24 | [Indexed] public int? HouseNumber { get; set; } 25 | [Indexed] public bool? Boolean { get; set; } 26 | [Indexed] public Ulid? Ulid { get; set; } 27 | [Indexed] public Guid? Guid { get; set; } 28 | } 29 | 30 | public enum AddressType 31 | { 32 | Home, 33 | Work, 34 | Vacation 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/BasicTypeWithGeoLoc.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document] 6 | public class BasicTypeWithGeoLoc 7 | { 8 | public string Name { get; set; } 9 | public GeoLoc Location { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/CustomerFilterDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Redis.OM.Unit.Tests 8 | { 9 | internal class CustomerFilterDto 10 | { 11 | public string FirstName { get; set; } 12 | public string LastName { get; set; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/GeoLocTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json; 3 | using Redis.OM.Modeling; 4 | using Xunit; 5 | 6 | namespace Redis.OM.Unit.Tests 7 | { 8 | public class GeoLocTests 9 | { 10 | [Fact] 11 | public void TestParsingFromJson() 12 | { 13 | var str = "{\"Name\":\"Foo\", \"Location\":{\"Longitude\":32.5,\"Latitude\":22.4}}"; 14 | var basicType = JsonSerializer.Deserialize(str); 15 | Assert.Equal("Foo", basicType.Name); 16 | Assert.Equal(32.5, basicType.Location.Longitude); 17 | Assert.Equal(22.4, basicType.Location.Latitude); 18 | } 19 | 20 | [Fact] 21 | public void TestParsingFromFormattedHash() 22 | { 23 | var hash = new Dictionary 24 | { 25 | {"Name", "Foo"}, 26 | {"Location", "32.5,22.4"} 27 | }; 28 | 29 | var basicType = RedisObjectHandler.FromHashSet(hash); 30 | Assert.Equal("Foo", basicType.Name); 31 | Assert.Equal(32.5, basicType.Location.Longitude); 32 | Assert.Equal(22.4, basicType.Location.Latitude); 33 | } 34 | 35 | /// 36 | /// This test will pass only if parsing of formatted geoloc string values is culture invariant. 37 | /// 38 | [Fact] 39 | public void TestInvariantCultureParsingFromFormattedHash() 40 | { 41 | Helper.RunTestUnderDifferentCulture("it-IT", x => TestParsingFromFormattedHash()); 42 | } 43 | 44 | [Theory] 45 | [InlineData("en-DE")] 46 | [InlineData("it-IT")] 47 | public void TestToStringInOtherCultures(string lcid) 48 | { 49 | Helper.RunTestUnderDifferentCulture(lcid, o => 50 | { 51 | var geoLoc = new GeoLoc(45.2, 11.9); 52 | var geoLocStr = geoLoc.ToString(); 53 | Assert.Equal("45.2,11.9", geoLocStr); 54 | }); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Xunit; 4 | 5 | namespace Redis.OM.Unit.Tests 6 | { 7 | internal class Helper 8 | { 9 | internal static void RunTestUnderDifferentCulture(string lcid, Action test) 10 | { 11 | if (lcid == null) 12 | throw new ArgumentNullException(nameof(lcid)); 13 | 14 | if (test == null) 15 | throw new ArgumentNullException(nameof(lcid)); 16 | 17 | var differentCulture = new System.Globalization.CultureInfo(lcid); 18 | 19 | Assert.NotEqual(".", differentCulture.NumberFormat.NumberDecimalSeparator); 20 | 21 | // set a different culture for the current thread 22 | Thread.CurrentThread.CurrentCulture = differentCulture; 23 | Thread.CurrentThread.CurrentUICulture = differentCulture; 24 | 25 | test.Invoke(null); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/AnEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Unit.Tests.RediSearchTests 2 | { 3 | public enum AnEnum 4 | { 5 | one=0, 6 | two=1, 7 | three=2 8 | } 9 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ClassForEmptyRedisCollection.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests.RediSearchTests 4 | { 5 | [Document(IndexName = "empty-index")] 6 | public class ClassForEmptyRedisCollection 7 | { 8 | [Indexed] public string TagField { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/EnumFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace Redis.OM.Unit.Tests.RediSearchTests; 5 | 6 | [Flags] 7 | [JsonConverter(typeof(JsonStringEnumConverter))] 8 | public enum EnumFlags 9 | { 10 | None = 0, 11 | One = 1 << 0, 12 | Two = 1 << 1, 13 | Three = 1 << 2 14 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/HashPerson.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests.RediSearchTests 5 | { 6 | [Document(StorageType = StorageType.Hash, IndexName = "hash-person-idx")] 7 | public class HashPerson 8 | { 9 | [RedisIdField] 10 | public string Id { get; set; } 11 | 12 | public HashPerson Mother { get; set; } 13 | 14 | [Searchable(Sortable = true)] 15 | public string Name { get; set; } 16 | 17 | [Indexed] 18 | public GeoLoc? Home { get; set; } 19 | 20 | [Indexed] 21 | public GeoLoc? Work { get; set; } 22 | 23 | public Address Address { get; set; } 24 | 25 | public bool? IsEngineer { get; set; } 26 | 27 | [Indexed(Sortable = true)] 28 | public int? Age { get; set; } 29 | 30 | [Indexed(Sortable = true)] 31 | public double? Height { get; set; } 32 | 33 | [ListType] 34 | public List NickNames { get; set; } 35 | 36 | [Indexed] 37 | public string TagField { get; set; } 38 | 39 | [Indexed(Sortable = true)] 40 | public int? DepartmentNumber { get; set; } 41 | 42 | [Indexed(Sortable = true)] 43 | public double? Sales { get; set; } 44 | 45 | [Indexed(Sortable = true)] 46 | public double? SalesAdjustment { get; set; } 47 | 48 | [Indexed] 49 | public long? LastTimeOnline { get; set; } 50 | 51 | [Searchable] 52 | public string TimeString { get; set; } 53 | [Indexed] 54 | public string Email { get; set; } 55 | } 56 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWIthMultipleDateTimes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests.RediSearchTests; 5 | 6 | [Document(StorageType = StorageType.Json, Prefixes = new []{"obj"})] 7 | public class ObjectWIthMultipleDateTimes 8 | { 9 | [RedisIdField] 10 | [Indexed] 11 | public string Id { get; set; } 12 | public DateTime DateTime1 { get; set; } 13 | public DateTime DateTime2 { get; set; } 14 | } 15 | 16 | [Document(Prefixes = new []{"obj"})] 17 | public class ObjectWIthMultipleDateTimesHash 18 | { 19 | [RedisIdField] 20 | [Indexed] 21 | public string Id { get; set; } 22 | public DateTime DateTime1 { get; set; } 23 | public DateTime DateTime2 { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithByteArray.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests.RediSearchTests; 4 | 5 | [Document(StorageType = StorageType.Json, Prefixes = new []{"obj"})] 6 | public class ObjectWithByteArray 7 | { 8 | [RedisIdField] 9 | [Indexed] 10 | public string Id { get; set; } 11 | 12 | public byte[] Bytes1 { get; set; } 13 | 14 | public byte[] Bytes2 { get; set; } 15 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithDateTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests.RediSearchTests; 5 | 6 | [Document(StorageType = StorageType.Json)] 7 | public class ObjectWithDateTime 8 | { 9 | [RedisField] 10 | public string Id { get; set; } 11 | [Indexed(Sortable = true)] 12 | public DateTime Timestamp { get; set; } 13 | [Indexed(Sortable = true)] 14 | public DateTimeOffset TimestampOffset { get; set; } 15 | [Indexed] 16 | public DateTime? NullableTimestamp { get; set; } 17 | } 18 | 19 | [Document(StorageType = StorageType.Hash)] 20 | public class ObjectWithDateTimeHash 21 | { 22 | [RedisField] 23 | public string Id { get; set; } 24 | 25 | [Indexed] 26 | public DateTime Timestamp { get; set; } 27 | [Indexed] 28 | public DateTime? NullableTimestamp { get; set; } 29 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithEmbeddedArrayOfObjects.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests.RediSearchTests 5 | { 6 | [Document(StorageType = StorageType.Json)] 7 | public class ObjectWithEmbeddedArrayOfObjects 8 | { 9 | [RedisIdField] 10 | public string Id { get; set; } 11 | 12 | [Indexed(JsonPath = "$.City")] 13 | [Indexed(JsonPath = "$.State")] 14 | [Indexed(JsonPath = "$.AddressType")] 15 | [Indexed(JsonPath = "$.Boolean")] 16 | [Indexed(JsonPath = "$.Guid")] 17 | [Indexed(JsonPath = "$.Ulid")] 18 | public Address[] Addresses { get; set; } 19 | 20 | [Indexed(JsonPath = "$.City")] 21 | [Indexed(JsonPath = "$.State")] 22 | public List
AddressList { get; set; } 23 | 24 | [Indexed] 25 | public string Name { get; set; } 26 | 27 | [Indexed] public int Numeric { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithMultipleSearchableAttributes.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests.RediSearchTests; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class ObjectWithMultipleSearchableAttributes 7 | { 8 | [RedisIdField] public string Id { get; set; } 9 | 10 | [Searchable(JsonPath = "$.City")] 11 | [Searchable(JsonPath = "$.State")] 12 | public Address Address { get; set; } 13 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithNullableStrings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text.Json.Serialization; 4 | using Redis.OM.Modeling; 5 | 6 | namespace Redis.OM.Unit.Tests.RediSearchTests; 7 | 8 | [Document(StorageType = StorageType.Json)] 9 | public class ObjectWithNullableStrings 10 | { 11 | [RedisIdField] 12 | [Indexed] 13 | public string Id { get; set; } 14 | 15 | [Indexed] 16 | public string? String1 { get; set; } 17 | 18 | [Searchable] 19 | public string? String2 { get; set; } 20 | 21 | [Indexed] 22 | public Guid? Guid { get; set; } 23 | 24 | [Indexed] 25 | public bool? Bool { get; set; } 26 | 27 | [Indexed] 28 | [JsonConverter(typeof(JsonStringEnumConverter))] 29 | public AnEnum? Enum { get; set; } 30 | } 31 | 32 | [Document] 33 | public class ObjectWithNullableStringsHash 34 | { 35 | [RedisIdField] 36 | [Indexed] 37 | public string Id { get; set; } 38 | 39 | [Indexed] 40 | public string? String1 { get; set; } 41 | 42 | [Searchable] 43 | public string? String2 { get; set; } 44 | 45 | [Indexed] 46 | public Guid? Guid { get; set; } 47 | 48 | [Indexed] 49 | public bool? Bool { get; set; } 50 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/ObjectWithStringLikeValueTypes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json.Serialization; 3 | using Redis.OM.Modeling; 4 | 5 | namespace Redis.OM.Unit.Tests.RediSearchTests 6 | { 7 | [Document(StorageType = StorageType.Json)] 8 | public class ObjectWithStringLikeValueTypes 9 | { 10 | [Indexed] 11 | public Ulid Ulid { get; set; } 12 | 13 | [Indexed] 14 | public bool Boolean { get; set; } 15 | 16 | [Indexed] 17 | public Guid Guid { get; set; } 18 | 19 | [Indexed] 20 | [JsonConverter(typeof(JsonStringEnumConverter))] 21 | public AnEnum AnEnum { get; set; } 22 | 23 | [Indexed] 24 | public AnEnum AnEnumAsInt { get; set; } 25 | 26 | [Indexed] 27 | [JsonConverter(typeof(JsonStringEnumConverter))] 28 | public EnumFlags Flags { get; set; } 29 | } 30 | 31 | [Document] 32 | public class ObjectWithStringLikeValueTypesHash 33 | { 34 | [Indexed] 35 | public Ulid Ulid { get; set; } 36 | 37 | [Indexed] 38 | public bool Boolean { get; set; } 39 | 40 | [Indexed] 41 | public Guid Guid { get; set; } 42 | 43 | [Indexed] 44 | public AnEnum AnEnum { get; set; } 45 | } 46 | 47 | [Document] 48 | public class ObjectWithNullableEnum 49 | { 50 | [Indexed] public AnEnum? AnEnum { get; set; } 51 | [Indexed] 52 | [JsonConverter(typeof(JsonStringEnumConverter))] 53 | public AnEnum? NullableStringEnum { get; set; } 54 | } 55 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/PersonNoName.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests.RediSearchTests 4 | { 5 | [Document] 6 | public class PersonNoName 7 | { 8 | [Indexed] 9 | public int Age { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/AzureOpenAIVectors.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using Redis.OM.Modeling.Vectors; 3 | using Redis.OM.Vectorizers; 4 | 5 | namespace Redis.OM.Unit.Tests; 6 | 7 | [Document(StorageType = StorageType.Json)] 8 | public class AzureOpenAIVectors 9 | { 10 | [RedisIdField] 11 | public string Id { get; set; } 12 | 13 | [Indexed] 14 | [AzureOpenAIVectorizer("redisom-embedding", "redisom-openai", 1536)] 15 | public Vector Sentence { get; set; } 16 | 17 | [Indexed] 18 | public string Name { get; set; } 19 | 20 | [Indexed] 21 | public int Age { get; set; } 22 | 23 | public VectorScores VectorScore { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/HuggingFaceVectors.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Vectorizers; 2 | using Redis.OM.Modeling; 3 | using Redis.OM.Modeling.Vectors; 4 | 5 | namespace Redis.OM.Unit.Tests; 6 | 7 | [Document] 8 | public class HuggingFaceVectors 9 | { 10 | [RedisIdField] 11 | public string Id { get; set; } 12 | 13 | [Indexed] 14 | [HuggingFaceVectorizer(ModelId = "sentence-transformers/all-MiniLM-L6-v2")] 15 | public Vector Sentence { get; set; } 16 | 17 | [Indexed] 18 | public string Name { get; set; } 19 | 20 | [Indexed] 21 | public int Age { get; set; } 22 | 23 | public VectorScores VectorScore { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/ObjectWithVector.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using Redis.OM.Modeling.Vectors; 3 | 4 | namespace Redis.OM.Unit.Tests; 5 | 6 | [Document(StorageType = StorageType.Json)] 7 | public class ObjectWithVector 8 | { 9 | [RedisIdField] 10 | public string Id { get; set; } 11 | 12 | [Indexed] public string Name { get; set; } 13 | 14 | [Indexed] public int Num { get; set; } 15 | 16 | [Indexed(Algorithm = VectorAlgorithm.HNSW)] 17 | [DoubleVectorizer(10)] 18 | public Vector SimpleHnswVector { get; set; } 19 | 20 | [Indexed(Algorithm = VectorAlgorithm.FLAT)] 21 | [SimpleVectorizer] 22 | public Vector SimpleVectorizedVector { get; set; } 23 | 24 | public VectorScores VectorScores { get; set; } 25 | } 26 | 27 | [Document(StorageType = StorageType.Hash)] 28 | public class ObjectWithVectorHash 29 | { 30 | [RedisIdField] 31 | public string Id { get; set; } 32 | 33 | [Indexed] public string Name { get; set; } 34 | 35 | [Indexed] public int Num { get; set; } 36 | 37 | [Indexed(Algorithm = VectorAlgorithm.HNSW)] 38 | [DoubleVectorizer(10)] 39 | public Vector SimpleHnswVector { get; set; } 40 | 41 | [Indexed(Algorithm = VectorAlgorithm.FLAT)] 42 | [SimpleVectorizer] 43 | public Vector SimpleVectorizedVector { get; set; } 44 | 45 | public VectorScores VectorScores { get; set; } 46 | } 47 | 48 | [Document(StorageType = StorageType.Json, Prefixes = new []{"Simple"})] 49 | public class ToyVector 50 | { 51 | [RedisIdField] public string Id { get; set; } 52 | [Indexed][DoubleVectorizer(6)]public Vector SimpleVector { get; set; } 53 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/OpenAICompletionResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | using Redis.OM.Vectorizers; 4 | 5 | namespace Redis.OM.Unit.Tests; 6 | 7 | [Document(StorageType = StorageType.Json)] 8 | public class OpenAICompletionResponse 9 | { 10 | [RedisIdField] 11 | public string Id { get; set; } 12 | 13 | [Indexed(DistanceMetric = DistanceMetric.COSINE, Algorithm = VectorAlgorithm.HNSW, M = 16)] 14 | [OpenAIVectorizer] 15 | public Vector Prompt { get; set; } 16 | 17 | public string Response { get; set; } 18 | 19 | [Indexed] 20 | public string Language { get; set; } 21 | 22 | [Indexed] 23 | public DateTime TimeStamp { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/OpenAIVectors.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using Redis.OM.Modeling.Vectors; 3 | using Redis.OM.Vectorizers; 4 | 5 | namespace Redis.OM.Unit.Tests; 6 | 7 | [Document(StorageType = StorageType.Json)] 8 | public class OpenAIVectors 9 | { 10 | [RedisIdField] 11 | public string Id { get; set; } 12 | 13 | [Indexed] 14 | [OpenAIVectorizer] 15 | public Vector Sentence { get; set; } 16 | 17 | [Indexed] 18 | public string Name { get; set; } 19 | 20 | [Indexed] 21 | public int Age { get; set; } 22 | 23 | public VectorScores VectorScore { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/SimpleVectorizerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Redis.OM.Contracts; 4 | using Redis.OM.Modeling; 5 | 6 | namespace Redis.OM.Unit.Tests; 7 | 8 | public class SimpleVectorizerAttribute : VectorizerAttribute 9 | { 10 | public override VectorType VectorType => VectorType.FLOAT32; 11 | public override int Dim => 30; 12 | 13 | public override IVectorizer Vectorizer => new SimpleVectorizer(); 14 | 15 | public override byte[] Vectorize(object obj) 16 | { 17 | if (obj is not string s) 18 | { 19 | throw new Exception("Could not vectorize non-string"); 20 | } 21 | 22 | return Vectorizer.Vectorize(s); 23 | } 24 | } 25 | 26 | public class SimpleVectorizer : IVectorizer 27 | { 28 | public VectorType VectorType => VectorType.FLOAT32; 29 | public int Dim => 30; 30 | public byte[] Vectorize(string obj) 31 | { 32 | var floats = new float[30]; 33 | for (var i = 0; i < 30; i++) 34 | { 35 | floats[i] = i; 36 | } 37 | 38 | return floats.SelectMany(BitConverter.GetBytes).ToArray(); 39 | } 40 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Redis.OM.Unit.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0;net7.0 4 | 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/BasicHashObject.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Hash)] 6 | public class BasicHashObject 7 | { 8 | [RedisIdField] 9 | public string Id { get; set; } 10 | public string Name { get; set; } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/BasicJsonObject.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class BasicJsonObject 7 | { 8 | [RedisIdField] 9 | public string Id { get; set; } 10 | public string Name { get; set; } 11 | } 12 | 13 | [Document(StorageType = StorageType.Json)] 14 | public class BasicJsonObjectTestSave 15 | { 16 | [RedisIdField] 17 | public string Id { get; set; } 18 | [Indexed]public string Name { get; set; } 19 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ComplexObjectWithCascadeAndJsonPath.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class ComplexObjectWithCascadeAndJsonPath 7 | { 8 | [Indexed(CascadeDepth = 2)] public InnerObject InnerCascade { get; set; } 9 | [Indexed(JsonPath = "$.InnerInnerCascade", CascadeDepth = 2)] public InnerObject InnerJson { get; set; } 10 | } 11 | 12 | public class InnerObject 13 | { 14 | [Indexed(JsonPath = "$.Tag")] public InnerInnerObject InnerInnerJson { get; set; } 15 | [Indexed(CascadeDepth = 1)] public InnerInnerObject InnerInnerCascade { get; set; } 16 | [Indexed(JsonPath = "$.Tag")] public InnerInnerObject[] InnerInnerCollection { get; set; } 17 | } 18 | 19 | public class InnerInnerObject 20 | { 21 | [Indexed] public string Tag { get; set; } 22 | [Indexed] public int Num { get; set; } 23 | [Indexed] public string[] Arr { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/HashObjectWithTwoPropertiesWithMatchingPrefixes.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document(IndexName = "employees_idx", StorageType = StorageType.Hash)] 6 | public class HashObjectWithTwoPropertiesWithMatchingPrefixes 7 | { 8 | [Searchable(Sortable = true)] public string Name { get; set; } 9 | 10 | [Searchable(Aggregatable = true)] public string Location { get; set; } 11 | 12 | [Searchable(Aggregatable = true)] public int? LocationNumber { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/HashTypeWithPrimitiveArray.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests; 5 | 6 | [Document] 7 | public class HashTypeWithPrimitiveArray 8 | { 9 | public string Name { get; set; } 10 | public bool[] Bools { get; set; } 11 | public int[] Ints { get; set; } 12 | public byte[] Bytes { get; set; } 13 | public sbyte[] SBytes { get; set; } 14 | public short[] Shorts { get; set; } 15 | public ushort[] UShorts { get; set; } 16 | public uint[] UInts { get; set; } 17 | public long[] Longs { get; set; } 18 | public ulong[] ULongs { get; set; } 19 | public char[] Chars { get; set; } 20 | public double[] Doubles { get; set; } 21 | public float[] Floats { get; set; } 22 | 23 | public List IntList { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/JsonObjectWithDateTime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests 5 | { 6 | [Document(StorageType = StorageType.Json)] 7 | public class JsonObjectWithDateTime 8 | { 9 | public string Name { get; set; } 10 | public DateTime Time { get; set; } 11 | public DateTime? NullableTime { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithATimestamp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests 5 | { 6 | [Document] 7 | public class ObjectWithATimestamp 8 | { 9 | public string Name { get; set; } 10 | public DateTime Time { get; set; } 11 | public DateTime? NullableTime { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithCustomIdGenerationStrategy.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document(IdGenerationStrategyName = nameof(StaticIncrementStrategy))] 6 | public class ObjectWithCustomIdGenerationStrategy 7 | { 8 | [RedisIdField] public string Id { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithDateTimeOffset.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests 5 | { 6 | [Document] 7 | public class ObjectWithDateTimeOffset 8 | { 9 | public DateTimeOffset Offset { get; set; } 10 | } 11 | 12 | [Document(StorageType = StorageType.Json)] 13 | public class ObjectWithDateTimeOffsetJson 14 | { 15 | [Indexed] 16 | [RedisIdField] 17 | public string Id { get; set; } 18 | 19 | public DateTimeOffset Offset { get; set; } 20 | public DateTime DateTime { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithGuidId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests 5 | { 6 | [Document(IdGenerationStrategyName = nameof(Uuid4IdGenerationStrategy))] 7 | public class ObjectWithGuidId 8 | { 9 | [RedisIdField]public Guid Id { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithIntegerId.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document] 6 | public class ObjectWithIntegerId 7 | { 8 | [RedisIdField] public int Id { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithMultipleSearchableFields.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Hash)] 6 | public class ObjectWithMultipleSearchableFields 7 | { 8 | [RedisIdField] 9 | [Indexed] 10 | public string Id { get; set; } 11 | 12 | [Searchable] 13 | public string FirstName { get; set; } 14 | 15 | [Searchable] 16 | public string LastName { get; set; } 17 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithNumerics.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class ObjectWithNumerics 7 | { 8 | [Indexed] 9 | public int Integer { get; set; } 10 | [Indexed] 11 | public byte Byte { get; set; } 12 | [Indexed] 13 | public sbyte SByte { get; set; } 14 | [Indexed] 15 | public short Short { get; set; } 16 | [Indexed] 17 | public ushort UShort { get; set; } 18 | [Indexed] 19 | public uint UInt { get; set; } 20 | [Indexed] 21 | public long Long { get; set; } 22 | [Indexed] 23 | public ulong ULong { get; set; } 24 | [Indexed] 25 | public double Double { get; set; } 26 | [Indexed] 27 | public float Float { get; set; } 28 | [Indexed] 29 | public decimal Decimal { get; set; } 30 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithPropertyNamesDefined.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests; 5 | 6 | [Document(StorageType = StorageType.Json)] 7 | public class ObjectWithPropertyNamesDefined 8 | { 9 | [JsonPropertyName("notKey")] 10 | [Indexed(PropertyName = "notKey")] 11 | [RedisIdField] 12 | public string Key { get; set; } 13 | 14 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithStandardId.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document] 6 | public class ObjectWithStandardId 7 | { 8 | [RedisIdField] public string Id { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithTwoStopwords.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document(Stopwords = new string[] {"foo", "bar"})] 6 | public class ObjectWithTwoStopwords 7 | { 8 | [Indexed] 9 | public string Name { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithUlidId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Redis.OM.Modeling; 3 | 4 | namespace Redis.OM.Unit.Tests 5 | { 6 | [Document] 7 | public class ObjectWithUlidId 8 | { 9 | [RedisIdField] public Ulid Id { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithUserDefinedId.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests 4 | { 5 | [Document] 6 | public class ObjectWithUserDefinedId 7 | { 8 | [RedisIdField] public string Id { get; set; } 9 | public string Name { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/ObjectWithZeroStopwords.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Redis.OM.Modeling; 4 | 5 | namespace Redis.OM.Unit.Tests 6 | { 7 | [Document(Stopwords = new string[0])] 8 | public class ObjectWithZeroStopwords 9 | { 10 | [Indexed] 11 | public string? Name { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/SelectTestObject.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | 3 | namespace Redis.OM.Unit.Tests; 4 | 5 | [Document(StorageType = StorageType.Json)] 6 | public class SelectTestObject 7 | { 8 | [Indexed] 9 | public string Name { get; set; } 10 | public InnerObject Field1 { get; set; } 11 | public InnerObject Field2 { get; set; } 12 | } 13 | 14 | public class CongruentObject 15 | { 16 | public InnerObject Field3 { get; set; } 17 | public InnerObject Field4 { get; set; } 18 | } 19 | 20 | public class CongruentObjectWithLikeNames 21 | { 22 | public InnerObject Field1 { get; set; } 23 | public InnerObject Field2 { get; set; } 24 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/Serialization/StaticIncrementStrategey.cs: -------------------------------------------------------------------------------- 1 | namespace Redis.OM.Unit.Tests 2 | { 3 | public class StaticIncrementStrategy : IIdGenerationStrategy 4 | { 5 | public static int Current = 0; 6 | public string GenerateId() 7 | { 8 | return (Current++).ToString(); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /test/Redis.OM.Unit.Tests/SkipIfMissingEnvVarAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Xunit; 4 | 5 | namespace Redis.OM.Unit.Tests; 6 | 7 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 8 | public class SkipIfMissingEnvVarAttribute : FactAttribute 9 | { 10 | private readonly string[] _envVars; 11 | 12 | public SkipIfMissingEnvVarAttribute(params string[] envVars) 13 | { 14 | _envVars = envVars; 15 | } 16 | 17 | public override string Skip 18 | { 19 | get 20 | { 21 | var missingEnvVars = _envVars.Where(x => Environment.GetEnvironmentVariable(x) == null).ToArray(); 22 | if (missingEnvVars.Any()) 23 | { 24 | return $"Skipping because the following environment variables were missing: {string.Join(",", missingEnvVars)}"; 25 | } 26 | 27 | return null; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/Redis.OM.Vectorizer.Tests/DocWithVectors.cs: -------------------------------------------------------------------------------- 1 | using Redis.OM.Modeling; 2 | using Redis.OM.Modeling.Vectors; 3 | using Redis.OM.Vectorizers.AllMiniLML6V2; 4 | using Redis.OM.Vectorizers.Resnet18; 5 | 6 | namespace Redis.OM.Vectorizer.Tests; 7 | 8 | [Document(StorageType = StorageType.Json)] 9 | public class DocWithVectors 10 | { 11 | [RedisIdField] 12 | public string? Id { get; set; } 13 | 14 | [Indexed(Algorithm = VectorAlgorithm.HNSW)] 15 | [SentenceVectorizer] 16 | public Vector? Sentence { get; set; } 17 | 18 | [Indexed] 19 | [ImageVectorizer] 20 | public Vector? ImagePath { get; set; } 21 | 22 | public VectorScores? Scores { get; set; } 23 | } -------------------------------------------------------------------------------- /test/Redis.OM.Vectorizer.Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /test/Redis.OM.Vectorizer.Tests/Redis.OM.Vectorizer.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0 4 | enable 5 | enable 6 | latest 7 | 8 | false 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/Redis.OM.Vectorizer.Tests/hal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redis/redis-om-dotnet/d04d0959cf02d011e9344aa281e061722c6211f1/test/Redis.OM.Vectorizer.Tests/hal.jpg --------------------------------------------------------------------------------