Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ SharpConnector is a .NET library designed to streamline integration with NoSQL d
- Supported stores:
- Key–value: Redis, EnyimMemcached, DynamoDb
- Document: MongoDB, LiteDB, RavenDB, Couchbase
- Wide-column: Cassandra
- Multi-model: ArangoDB
- Simple configuration via `appsettings.json` and DI-friendly
- Sync and async operations (with CancellationToken support)
Expand All @@ -57,6 +58,7 @@ Through SharpConnector, you can use a consistent interface to perform Insert, Ge
* **Couchbase (document-oriented)**
* **DynamoDb (key-value or document-oriented)**
* **ArangoDB (multi-model)**
* **Apache Cassandra (wide-column)**

SharpConnector thus simplifies the development process, providing flexibility and compatibility across diverse NoSQL paradigms without the need to handle specific database implementations.

Expand Down Expand Up @@ -159,6 +161,20 @@ Then, add the specif `ConnectorConfig` node within your *appsettings.json* file:
}
```

- Cassandra
```json
{
"ConnectorConfig": {
"Instance": "Cassandra",
"ConnectionString": "127.0.0.1:9042",
"DatabaseName": "sharpconnector",
"TableName": "items",
"Username": "cassandra",
"Password": "cassandra"
}
}
```

Once configured, create a new SharpConnector client, specifying the payload type (e.g., string):

```csharp
Expand Down Expand Up @@ -226,6 +242,7 @@ Each of these libraries operates under a specific license, which governs its usa
* **Couchbase**, the official Couchbase SDK for .NET Core and Full Frameworks, see **license** [here](https://github.com/couchbase/couchbase-net-client/blob/master/LICENSE)
* **DynamoDb**, the official AWS SDK for .NET, see **license** [here](https://github.com/aws/aws-sdk-net/blob/main/License.txt)
* **ArangoDB**, a consistent, comprehensive, minimal driver for ArangoDB, see **license** [here](https://github.com/ArangoDB-Community/arangodb-net-standard/blob/master/LICENSE)
* **CassandraCSharpDriver**, the DataStax C# driver for Apache Cassandra, see **license** [here](https://github.com/datastax/csharp-driver/blob/master/LICENSE)

Each library is included to enhance the functionality of SharpConnector while adhering to its licensing terms.

Expand Down
4 changes: 2 additions & 2 deletions src/SharpConnector.Api/SharpConnector.Api.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFrameworks>net9.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
Expand Down Expand Up @@ -42,7 +42,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
</ItemGroup>

<ItemGroup>
Expand Down
10 changes: 10 additions & 0 deletions src/SharpConnector.Api/appsettings.cassandra.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"ConnectorConfig": {
"Instance": "Cassandra",
"ConnectionString": "127.0.0.1:9042",
"DatabaseName": "sharpconnector",
"TableName": "items",
"Username": "cassandra",
"Password": "cassandra"
}
}
123 changes: 123 additions & 0 deletions src/SharpConnector.Tests/CassandraConfigTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// (c) 2025 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpConnector.Configuration;
using System;
using System.Collections.Generic;

namespace SharpConnector.Tests
{
[TestClass]
public class CassandraConfigTests
{
private static IConfigurationSection BuildSection(Dictionary<string, string> values)
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

return configuration.GetSection("ConnectorConfig");
}

[TestMethod]
public void Ctor_ValidConfiguration_PopulatesAllProperties()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = "127.0.0.1:9042",
["ConnectorConfig:databasename"] = "sharpconnector",
["ConnectorConfig:tablename"] = "items",
["ConnectorConfig:username"] = "cassandra",
["ConnectorConfig:password"] = "cassandra"
});

var config = new CassandraConfig(section);

Assert.AreEqual("127.0.0.1:9042", config.ConnectionString);
Assert.AreEqual("sharpconnector", config.DatabaseName);
Assert.AreEqual("items", config.TableName);
Assert.AreEqual("cassandra", config.Username);
Assert.AreEqual("cassandra", config.Password);
}

[TestMethod]
public void Ctor_TrimsWhitespace()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = " 127.0.0.1:9042 ",
["ConnectorConfig:databasename"] = " ks ",
["ConnectorConfig:tablename"] = " tbl ",
["ConnectorConfig:username"] = " user ",
["ConnectorConfig:password"] = " pwd "
});

var config = new CassandraConfig(section);

Assert.AreEqual("127.0.0.1:9042", config.ConnectionString);
Assert.AreEqual("ks", config.DatabaseName);
Assert.AreEqual("tbl", config.TableName);
Assert.AreEqual("user", config.Username);
Assert.AreEqual("pwd", config.Password);
}

[TestMethod]
public void Ctor_OptionalCredentials_AreAllowedToBeNull()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = "127.0.0.1:9042",
["ConnectorConfig:databasename"] = "sharpconnector",
["ConnectorConfig:tablename"] = "items"
});

var config = new CassandraConfig(section);

Assert.IsNull(config.Username);
Assert.IsNull(config.Password);
}

[TestMethod]
public void Ctor_NullConfiguration_Throws()
{
Assert.ThrowsExactly<ArgumentNullException>(() => new CassandraConfig(null));
}

[TestMethod]
public void Ctor_MissingConnectionString_Throws()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:databasename"] = "sharpconnector",
["ConnectorConfig:tablename"] = "items"
});

Assert.ThrowsExactly<ArgumentException>(() => new CassandraConfig(section));
}

[TestMethod]
public void Ctor_MissingDatabaseName_Throws()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = "127.0.0.1:9042",
["ConnectorConfig:tablename"] = "items"
});

Assert.ThrowsExactly<ArgumentException>(() => new CassandraConfig(section));
}

[TestMethod]
public void Ctor_MissingTableName_Throws()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = "127.0.0.1:9042",
["ConnectorConfig:databasename"] = "sharpconnector"
});

Assert.ThrowsExactly<ArgumentException>(() => new CassandraConfig(section));
}
}
}
51 changes: 51 additions & 0 deletions src/SharpConnector.Tests/CassandraFactoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// (c) 2025 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpConnector.Configuration;
using SharpConnector.Enums;
using SharpConnector.Operations;
using System;
using System.Collections.Generic;

namespace SharpConnector.Tests
{
[TestClass]
public class CassandraFactoryTests
{
private static IConfigurationSection BuildSection(Dictionary<string, string> values)
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();

return configuration.GetSection("ConnectorConfig");
}

[TestMethod]
public void ConnectorTypeEnum_ContainsCassandra()
{
var defined = Enum.IsDefined(typeof(ConnectorTypeEnums), ConnectorTypeEnums.Cassandra);
Assert.IsTrue(defined);
}

[TestMethod]
public void OperationFactory_GetConfigurationStrategy_ReturnsCassandraConfig()
{
var section = BuildSection(new Dictionary<string, string>
{
["ConnectorConfig:connectionstring"] = "127.0.0.1:9042",
["ConnectorConfig:databasename"] = "sharpconnector",
["ConnectorConfig:tablename"] = "items"
});

var factory = new OperationsFactory<string>(section);
var config = factory.GetConfigurationStrategy(section, ConnectorTypeEnums.Cassandra);

Assert.IsNotNull(config);
Assert.IsInstanceOfType(config, typeof(CassandraConfig));
Assert.AreEqual("sharpconnector", config.DatabaseName);
Assert.AreEqual("items", config.TableName);
}
}
}
7 changes: 5 additions & 2 deletions src/SharpConnector.Tests/ConnectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public ConnectorTests()
_mockClient.Setup(client => client.InsertManyAsync(
It.IsAny<IEnumerable<string>>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync(true);
.ReturnsAsync((IEnumerable<string> v, CancellationToken _) =>
(IReadOnlyCollection<string>)v.Select(_ => Guid.NewGuid().ToString()).ToList().AsReadOnly());

_sharpConnectorClient = _mockClient.Object;
}
Expand Down Expand Up @@ -183,7 +184,9 @@ public async Task InsertManyAsync_Enumerable()
{
var values = new List<string> { "payload1", "payload2", "payload3" };
var result = await _sharpConnectorClient.InsertManyAsync(values);
Assert.IsTrue(result);
Assert.IsNotNull(result);
Assert.AreEqual(values.Count, result.Count);
Assert.IsTrue(result.All(k => !string.IsNullOrEmpty(k)));
}

[TestMethod]
Expand Down
12 changes: 6 additions & 6 deletions src/SharpConnector.Tests/SharpConnector.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFrameworks>net9.0;net10.0</TargetFrameworks>

<IsPackable>false</IsPackable>

Expand All @@ -25,11 +25,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
<PackageReference Include="coverlet.collector" Version="8.0.0">
<PackageReference Include="MSTest.TestAdapter" Version="4.3.2" />
<PackageReference Include="MSTest.TestFramework" Version="4.3.2" />
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
55 changes: 55 additions & 0 deletions src/SharpConnector/Configuration/CassandraConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// (c) 2025 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.Extensions.Configuration;
using SharpConnector.Enums;
using SharpConnector.Interfaces;
using System;

namespace SharpConnector.Configuration
{
/// <summary>
/// Provides configuration settings for Apache Cassandra.
/// </summary>
public class CassandraConfig : IConnectorConfig
{
public string ConnectionString { get; }
public string DatabaseName { get; }
public string TableName { get; }
public string Username { get; }
public string Password { get; }

#region NOT USED
public int DatabaseNumber { get; private set; }
public string CollectionName { get; private set; }
public string BucketName { get; private set; }
public string AccessKey { get; private set; }
public string SecretKey { get; private set; }
public string Region { get; private set; }
public string ServiceUrl { get; private set; }
public bool UseHttp { get; private set; }
#endregion

public CassandraConfig(IConfiguration configuration)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}

ConnectionString = configuration[AppConfigParameterEnums.connectionstring.ToString()]?.Trim();
if (string.IsNullOrEmpty(ConnectionString))
throw new ArgumentException("Cassandra ConnectionString (contact points) is required but was not found in configuration.");

DatabaseName = configuration[AppConfigParameterEnums.databasename.ToString()]?.Trim();
if (string.IsNullOrEmpty(DatabaseName))
throw new ArgumentException("Cassandra DatabaseName (keyspace) is required but was not found in configuration.");

TableName = configuration[AppConfigParameterEnums.tablename.ToString()]?.Trim();
if (string.IsNullOrEmpty(TableName))
throw new ArgumentException("Cassandra TableName is required but was not found in configuration.");

Username = configuration[AppConfigParameterEnums.username.ToString()]?.Trim();
Password = configuration[AppConfigParameterEnums.password.ToString()]?.Trim();
}
}
}
Loading
Loading