Created
December 13, 2022 04:30
-
-
Save Vergil333/9d75408aae78af32f609060a91db9747 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @property accountNumber Text(40) | |
* @property accountSource Picklist | |
* @property active__c Picklist | |
* @property annualRevenue Currency(18, 0) | |
* @property billingAddress Address | |
* @property cleanStatus Picklist | |
* @property createdById Lookup(User) | |
* @property createdDate Date/Time | |
* @property customerPriority__c Picklist | |
* @property dandbCompanyId Lookup(D&B Company) | |
* @property description Long Text Area(32000) | |
* @property dunsNumber Text(9) | |
* @property fax Fax | |
* @property id Lookup() | |
* @property industry Picklist | |
* @property isDeleted Checkbox | |
* @property jigsaw Text(20) | |
* @property jigsawCompanyId External Lookup | |
* @property lastActivityDate Date | |
* @property lastModifiedById Lookup(User) | |
* @property lastModifiedDate Date/Time | |
* @property lastReferencedDate Date/Time | |
* @property lastViewedDate Date/Time | |
* @property masterRecordId Lookup(Account) | |
* @property naicsCode Text(8) | |
* @property naicsDesc Text(120) | |
* @property name Name | |
* @property numberOfEmployees Number(8, 0) | |
* @property numberofLocations__c Number(3, 0) | |
* @property operatingHoursId Lookup(Operating Hours) | |
* @property ownerId Lookup(User) | |
* @property ownership Picklist | |
* @property parentId Hierarchy | |
* @property phone Phone | |
* @property photoUrl URL(255) | |
* @property rating Picklist | |
* @property sLAExpirationDate__c Date | |
* @property sLASerialNumber__c Text(10) | |
* @property sLA__c Picklist | |
* @property shippingAddress Address | |
* @property sic Text(20) | |
* @property sicDesc Text(80) | |
* @property site Text(80) | |
* @property systemModstamp Date/Time | |
* @property tickerSymbol Content(20) | |
* @property tradestyle Text(255) | |
* @property type Picklist | |
* @property upsellOpportunity__c Picklist | |
* @property userRecordAccessId Lookup(User Record Access) | |
* @property website URL(255) | |
* @property yearStarted Text(4) | |
*/ | |
class Account ( | |
@JsonProperty("AccountNumber") val accountNumber: String? = null, | |
@JsonProperty("AccountSource") val accountSource: String? = null, | |
@JsonProperty("Active__c") val active__c: String? = null, | |
@JsonProperty("AnnualRevenue") val annualRevenue: Double? = null, | |
@JsonProperty("BillingAddress") val billingAddress: Map<String, Any?>? = null, | |
@JsonProperty("CleanStatus") val cleanStatus: String? = null, | |
@JsonProperty("CreatedById") val createdById: String, | |
@JsonProperty("CreatedDate") val createdDate: String, | |
@JsonProperty("CustomerPriority__c") val customerPriority__c: String? = null, | |
@JsonProperty("DandbCompanyId") val dandbCompanyId: String? = null, | |
@JsonProperty("Description") val description: String? = null, | |
@JsonProperty("DunsNumber") val dunsNumber: String? = null, | |
@JsonProperty("Fax") val fax: String? = null, | |
@JsonProperty("Industry") val industry: String? = null, | |
@JsonProperty("IsDeleted") val isDeleted: Boolean, | |
@JsonProperty("Jigsaw") val jigsaw: String? = null, | |
@JsonProperty("JigsawCompanyId") val jigsawCompanyId: String? = null, | |
@JsonProperty("LastActivityDate") val lastActivityDate: String? = null, | |
@JsonProperty("LastModifiedById") val lastModifiedById: String, | |
@JsonProperty("LastModifiedDate") val lastModifiedDate: String, | |
@JsonProperty("LastReferencedDate") val lastReferencedDate: String? = null, | |
@JsonProperty("LastViewedDate") val lastViewedDate: String? = null, | |
@JsonProperty("MasterRecordId") val masterRecordId: String? = null, | |
@JsonProperty("NaicsCode") val naicsCode: String? = null, | |
@JsonProperty("NaicsDesc") val naicsDesc: String? = null, | |
@JsonProperty("Name") val name: String, | |
@JsonProperty("NumberOfEmployees") val numberOfEmployees: Double? = null, | |
@JsonProperty("NumberofLocations__c") val numberofLocations__c: Double? = null, | |
@JsonProperty("OperatingHoursId") val operatingHoursId: String? = null, | |
@JsonProperty("OwnerId") val ownerId: String, | |
@JsonProperty("Ownership") val ownership: String? = null, | |
@JsonProperty("ParentId") val parentId: Map<String, Any?>? = null, | |
@JsonProperty("Phone") val phone: String? = null, | |
@JsonProperty("PhotoUrl") val photoUrl: String? = null, | |
@JsonProperty("Rating") val rating: String? = null, | |
@JsonProperty("SLAExpirationDate__c") val sLAExpirationDate__c: String? = null, | |
@JsonProperty("SLASerialNumber__c") val sLASerialNumber__c: String? = null, | |
@JsonProperty("SLA__c") val sLA__c: String? = null, | |
@JsonProperty("ShippingAddress") val shippingAddress: Map<String, Any?>? = null, | |
@JsonProperty("Sic") val sic: String? = null, | |
@JsonProperty("SicDesc") val sicDesc: String? = null, | |
@JsonProperty("Site") val site: String? = null, | |
@JsonProperty("SystemModstamp") val systemModstamp: String, | |
@JsonProperty("TickerSymbol") val tickerSymbol: String? = null, | |
@JsonProperty("Tradestyle") val tradestyle: String? = null, | |
@JsonProperty("Type") val type: String? = null, | |
@JsonProperty("UpsellOpportunity__c") val upsellOpportunity__c: String? = null, | |
@JsonProperty("UserRecordAccessId") val userRecordAccessId: String? = null, | |
@JsonProperty("Website") val website: String? = null, | |
@JsonProperty("YearStarted") val yearStarted: String? = null, | |
) : AbstractSObject<SObjectType>(type = SObjectType.ACCOUNT) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.fasterxml.jackson.annotation.JsonProperty | |
import com.fasterxml.jackson.core.type.TypeReference | |
import com.fasterxml.jackson.databind.DeserializationFeature | |
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper | |
import com.fasterxml.jackson.module.kotlin.registerKotlinModule | |
import java.net.HttpURLConnection | |
import java.net.IDN | |
import java.net.URI | |
import java.net.URL | |
import kotlin.reflect.KVisibility | |
import kotlin.reflect.full.findAnnotations | |
import kotlin.reflect.full.memberProperties | |
import kotlin.reflect.full.primaryConstructor | |
import kotlin.reflect.jvm.javaField | |
/** | |
* @param accessToken has to have [web, chatter_api, api] permissions for querying | |
* @param instanceUrl acquired in the same response as accessToken | |
* | |
* @credits to mjg123 https://github.com/mjg123/java-http-clients/blob/master/src/main/java/com/twilio/JavaHttpURLConnectionDemo.java | |
* @credits to madmax1028, broot https://discuss.kotlinlang.org/t/how-to-specify-generic-output-type-to-be-subclass-of-generic-type/24637/12 | |
*/ | |
class SalesforceClient( | |
@PublishedApi internal inline val accessToken: String, | |
@PublishedApi internal inline val instanceUrl: String, | |
) { | |
@PublishedApi | |
internal val apiVersion = "v53.0" | |
@PublishedApi | |
internal val mapper = jacksonObjectMapper().registerKotlinModule() | |
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) | |
inline fun <reified T: SObjectInterface> getAll(): SfResponse<T> = | |
getResponse<T>("SELECT ${getFields<T>().joinToString()} FROM ${T::class.simpleName}") | |
inline fun <reified T: SObjectInterface> count(): Int = | |
getResponse<T>("SELECT COUNT() FROM+${T::class.simpleName}") | |
.totalSize | |
@PublishedApi | |
internal inline fun <reified T: SObjectInterface> getResponse(query: String): SfResponse<T> { | |
val url = URL("$instanceUrl/services/data/$apiVersion/query?q=$query").toUri().toURL() | |
val connection: HttpURLConnection = url.openConnection() as HttpURLConnection | |
connection.setRequestProperty("accept", "application/json") | |
connection.setRequestProperty("Authorization", "Bearer $accessToken") | |
return mapper.readValue(connection.inputStream, object : TypeReference<SfResponse<T>>() {}) | |
} | |
@OptIn(ExperimentalStdlibApi::class) | |
inline fun <reified T: SObjectInterface> getFields(): List<String> { | |
val propertiesWeWant = T::class.java.kotlin.memberProperties | |
.filter { prop -> | |
prop.visibility == KVisibility.PUBLIC | |
&& listOf("java.util", "java.lang").contains(prop.javaField?.type?.packageName) | |
&& prop.name != "attributes" | |
} | |
val bodyProps = propertiesWeWant.mapNotNull { it.javaField?.getAnnotation(JsonProperty::class.java)?.value } | |
val constructorProps = T::class.java.kotlin.primaryConstructor?.parameters | |
?.filter { it.name in (propertiesWeWant.map { it.name }) } | |
?.map { it.findAnnotations(JsonProperty::class).first().value } | |
?: emptyList() | |
return bodyProps + constructorProps | |
} | |
/** | |
* URI is used for URL encoding. | |
*/ | |
@PublishedApi | |
internal fun URL.toUri() = URI( | |
this.protocol, | |
this.userInfo, | |
IDN.toASCII(this.host), | |
this.port, | |
this.path, | |
this.query, this.ref, | |
) | |
} | |
class SfResponse<T: SObjectInterface>( | |
val totalSize: Int, | |
val done: Boolean, | |
val records: List<T>, | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface SObjectInterface | |
data class SObjectAttributes<T: SObjectType>( | |
val type: T, | |
val url: String? = null, | |
) | |
abstract class AbstractSObject<T: SObjectType>( | |
type: T, | |
) : SObjectInterface { | |
val attributes: SObjectAttributes<T> = SObjectAttributes(type = type) | |
@JsonProperty("Id") val id: String? = null | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum class SObjectType(val jsonName: String) { | |
@JsonProperty("Account") ACCOUNT("Account"), | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment