-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add salesforce connector #57
base: main
Are you sure you want to change the base?
Changes from all commits
d03e662
0e77bee
6e7caed
6f566fa
e497a46
dda3893
1f9feba
b2df90d
77967e7
8e408dd
641e994
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Exceptions; | ||
|
||
/// <summary> | ||
/// Thrown if the Salesforce job was aborted. | ||
/// </summary> | ||
[ExcludeFromCodeCoverage(Justification = "Trivial")] | ||
public class SalesForceJobAbortedException : SalesForceJobException | ||
{ | ||
public SalesForceJobAbortedException(string message) : base(message) | ||
{ | ||
} | ||
|
||
public SalesForceJobAbortedException(string message, Exception inner) : base(message, inner) | ||
Check warning on line 16 in src/Sources/SalesForce/Exceptions/SalesForceJobAbortedException.cs GitHub Actions / Validate commit
|
||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Exceptions; | ||
|
||
/// <summary> | ||
/// Base class for all Salesforce-related exceptions | ||
/// </summary> | ||
[ExcludeFromCodeCoverage(Justification = "Trivial")] | ||
public class SalesForceJobException : Exception | ||
{ | ||
public SalesForceJobException(string message) | ||
: base(message) | ||
{ | ||
} | ||
|
||
public SalesForceJobException(string message, Exception inner) | ||
: base(message, inner) | ||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Exceptions; | ||
|
||
/// <summary> | ||
/// Thrown if the Salesforce job return with failed status. | ||
/// </summary> | ||
[ExcludeFromCodeCoverage(Justification = "Trivial")] | ||
public class SalesForceJobFailedException : SalesForceJobException | ||
{ | ||
public SalesForceJobFailedException(string message) : base(message) | ||
{ | ||
} | ||
|
||
public SalesForceJobFailedException(string message, Exception inner) : base(message, inner) | ||
{ | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Models; | ||
|
||
/// <summary> | ||
/// Represents Salesforce attribute | ||
/// </summary> | ||
public class SalesForceAttribute | ||
{ | ||
private static readonly Dictionary<string, Type> salesforceTypeMap = new() | ||
{ | ||
{ "string", typeof(string) }, | ||
{ "id", typeof(string) }, | ||
{ "datetime", typeof(DateTime) }, | ||
{ "date", typeof(DateTime) }, | ||
{ "decimal", typeof(decimal) }, | ||
{ "integer", typeof(int) }, | ||
{ "long", typeof(long) }, | ||
{ "double", typeof(double) }, | ||
{ "boolean", typeof(bool) }, | ||
}; | ||
|
||
/// <summary> | ||
/// Attribute name | ||
/// </summary> | ||
[JsonPropertyName("Name")] | ||
public string Name { get; set; } | ||
|
||
/// <summary> | ||
/// Attribute data type | ||
/// </summary> | ||
[JsonPropertyName("ValueTypeId")] | ||
public string DataType { get; set; } | ||
|
||
|
||
/// <summary> | ||
/// Attribute comparer | ||
/// </summary> | ||
public static IEqualityComparer<SalesForceAttribute> SalesForceAttributeComparer { get; } = | ||
new SalesForceAttributeEqualityComparer(); | ||
|
||
/// <summary> | ||
/// Maps Salesforce type to .NET type | ||
/// </summary> | ||
/// <param name="salesforceTypeName">Salesforce type name</param> | ||
/// <returns>.NET type instance</returns> | ||
/// <exception cref="InvalidOperationException">Thrown if type is not supported</exception> | ||
public static Type MapSalesforceType(string salesforceTypeName) | ||
{ | ||
if (salesforceTypeMap.ContainsKey(salesforceTypeName.ToLower())) | ||
{ | ||
return salesforceTypeMap[salesforceTypeName.ToLower()]; | ||
} | ||
|
||
throw new InvalidOperationException($"Unsupported type: {salesforceTypeName}"); | ||
} | ||
|
||
private sealed class SalesForceAttributeEqualityComparer : IEqualityComparer<SalesForceAttribute> | ||
{ | ||
public bool Equals(SalesForceAttribute x, SalesForceAttribute y) | ||
{ | ||
if (ReferenceEquals(x, y)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (ReferenceEquals(x, null)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (ReferenceEquals(y, null)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (x.GetType() != y.GetType()) | ||
{ | ||
return false; | ||
} | ||
|
||
return x.Name == y.Name && | ||
x.DataType == y.DataType; | ||
} | ||
|
||
public int GetHashCode(SalesForceAttribute obj) | ||
{ | ||
return HashCode.Combine(obj.Name, obj.DataType); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Data; | ||
using System.Linq; | ||
using System.Text.Json; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Models; | ||
|
||
/// <summary> | ||
/// Represents Salesforce entity | ||
/// </summary> | ||
public class SalesForceEntity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The classes that are not intended for use by plugins should always be |
||
{ | ||
/// <summary> | ||
/// Entity name | ||
/// </summary> | ||
public string EntityName { get; set; } | ||
|
||
|
||
/// <summary> | ||
/// Attributes collection | ||
/// </summary> | ||
public SalesForceAttribute[] Attributes { get; set; } | ||
|
||
/// <summary> | ||
/// Comparer class | ||
/// </summary> | ||
public static IEqualityComparer<SalesForceEntity> SalesForceEntityComparer { get; } = | ||
new SalesForceEntityEqualityComparer(); | ||
|
||
/// <summary> | ||
/// Parse Salesforce entity from a JSON document | ||
/// </summary> | ||
/// <param name="entityName">Name of the Salesforce entity </param> | ||
/// <param name="document">Json document to parse</param> | ||
/// <returns>Parsed SalesForceEntity object</returns> | ||
public static SalesForceEntity FromJson(string entityName, JsonDocument document) | ||
{ | ||
var entity = new SalesForceEntity | ||
{ | ||
EntityName = entityName, | ||
Attributes = document.RootElement.GetProperty("records").Deserialize<SalesForceAttribute[]>() | ||
}; | ||
|
||
|
||
return entity; | ||
} | ||
|
||
/// <summary> | ||
/// Create DataReader for the entity | ||
/// </summary> | ||
/// <returns>DataReader instance</returns> | ||
public IDataReader GetReader() | ||
{ | ||
var dt = new DataTable(); | ||
|
||
foreach (var attr in this.Attributes) | ||
{ | ||
dt.Columns.Add(new DataColumn(attr.Name, SalesForceAttribute.MapSalesforceType(attr.DataType))); | ||
} | ||
|
||
return dt.CreateDataReader(); | ||
} | ||
|
||
private sealed class SalesForceEntityEqualityComparer : IEqualityComparer<SalesForceEntity> | ||
{ | ||
public bool Equals(SalesForceEntity x, SalesForceEntity y) | ||
{ | ||
if (ReferenceEquals(x, y)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (ReferenceEquals(x, null)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (ReferenceEquals(y, null)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (x.GetType() != y.GetType()) | ||
{ | ||
return false; | ||
} | ||
|
||
return x.EntityName == y.EntityName | ||
&& x.Attributes.SequenceEqual(y.Attributes, SalesForceAttribute.SalesForceAttributeComparer); | ||
} | ||
|
||
public int GetHashCode(SalesForceEntity obj) | ||
{ | ||
return HashCode.Combine(obj.EntityName, obj.Attributes); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Arcane.Framework.Sources.SalesForce.Models; | ||
|
||
/// <summary> | ||
/// Job status types | ||
/// </summary> | ||
[JsonConverter(typeof(JsonStringEnumConverter))] | ||
public enum SalesforceJobStatus | ||
{ | ||
UploadComplete, | ||
InProgress, | ||
Aborted, | ||
JobComplete, | ||
Failed, | ||
None | ||
} | ||
|
||
/// <summary> | ||
/// Represents Salesforce job | ||
/// </summary> | ||
public class SalesForceJob | ||
{ | ||
/// <summary> | ||
/// Id | ||
/// </summary> | ||
[JsonPropertyName("id")] | ||
public string Id { get; set; } | ||
|
||
|
||
/// <summary> | ||
/// Job status | ||
/// </summary> | ||
[JsonPropertyName("state")] | ||
public SalesforceJobStatus Status { get; set; } | ||
|
||
/// <summary> | ||
/// object | ||
/// </summary> | ||
[JsonPropertyName("object")] | ||
public string Object { get; set; } | ||
|
||
/// <summary> | ||
/// Total processing time of the job | ||
/// </summary> | ||
[JsonPropertyName("totalProcessingTime")] | ||
public long? TotalProcessingTime { get; set; } | ||
|
||
/// <summary> | ||
/// Numbers of records processed by the job | ||
/// </summary> | ||
[JsonPropertyName("numberRecordsProcessed")] | ||
public long? NumberRecordsProcessed { get; set; } | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The warnings about comment should be fixed, here and below.