Skip to content

Commit fbd07ea

Browse files
authored
New version with benchmark lookup by custom name and value (#12)
* new version with benchmark lookup by custom name/val * precommit * fixes
1 parent ae43dfb commit fbd07ea

File tree

6 files changed

+1318
-663
lines changed

6 files changed

+1318
-663
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,4 @@ salesforce-config*.json
9999
!salesforce-config-example.json
100100
seed-config*.json
101101
!seed-config-example.json
102+
example_usage.py

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
## Version 0.2.0
4+
5+
Added a method to look up a benchmark with a custom ID name / value pair
6+
Updated testing to first retrieve a benchmark by custom ID and then update it
7+
Dependency updates
8+
39
## Version 0.1.1
410

511
Updated Python compatibility for v3.9-v3.12, and reformatted with Ruff

poetry.lock

Lines changed: 1263 additions & 646 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "seed-salesforce"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
description = "Package for connecting SEED data to Salesforce"
55
authors = ["Nicholas Long <nicholas.long@nrel.gov>", "Katherine Fleming <katherine.fleming@nrel.gov>"]
66
license = "BSD-3-Clause"
@@ -28,7 +28,7 @@ python = ">=3.9, <3.13"
2828
python-dateutil = "*"
2929
simple-salesforce = "^1.12.6"
3030

31-
[tool.poetry.dev-dependencies]
31+
[tool.poetry.group.dev.dependencies]
3232
mypy = "^1.11.2"
3333
pre-commit = "^3.8.0"
3434
pytest = "^7.1.2"

seed_salesforce/salesforce_client.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
import logging
5+
import re
56
from pathlib import Path
67
from typing import Optional
78

@@ -129,13 +130,15 @@ def get_first_benchmark(self) -> dict:
129130
else:
130131
raise Exception("Failed to return a Benchmark")
131132

132-
def get_benchmark_by_custom_id(self, salesforce_benchmark_id: str) -> dict:
133-
"""Return the benchmark by the Salesforce Benchmark ID.
133+
def get_benchmark_by_custom_id(self, custom_id_name: str, custom_id_value: str) -> dict:
134+
"""Return the benchmark by the custom Salesforce Benchmark ID.
134135
135136
Args:
136-
salesforce_benchmark_id (str): Salesforce Benchmark ID of the property to return
137-
Note: this is not necessarily the Benchmark ID (it's a separate field)
138-
# TODO: make this configurable?
137+
custom_id_name (str): Name of the custom ID field
138+
custom_id_value (str): Value of the custom ID field
139+
Note: this is not necessarily the Benchmark ID (it's a separate field that should be unique
140+
and serves as the "key" for retrieving the benchmark, but it is not necessarily the actual
141+
record ID in Salesforce)
139142
140143
Returns:
141144
dict: OrderedDict([('attributes',
@@ -145,18 +148,23 @@ def get_benchmark_by_custom_id(self, salesforce_benchmark_id: str) -> dict:
145148
...
146149
"""
147150

151+
# Validate field name to prevent SQL injection
152+
# Field names in Salesforce should only contain alphanumeric characters, underscores, and end with __c for custom fields
153+
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*(__c)?$", custom_id_name):
154+
raise ValueError(f"Invalid field name: {custom_id_name}")
155+
148156
benchmark_exist = self.connection.query(
149-
format_soql("Select Id from Benchmark__c where Salesforce_Benchmark_ID__c = {}", salesforce_benchmark_id),
157+
format_soql(f"Select Id from Benchmark__c where {custom_id_name} = {{}}", custom_id_value), # noqa: S608
150158
)
151159
if len(benchmark_exist["records"]) == 1:
152160
# if there is a single record, then it exist, but
153161
# we need to get the entire record for the request
154162
rec = self.get_benchmark_by_id(benchmark_exist["records"][0]["Id"])
155163
return rec
156164
elif len(benchmark_exist["records"]) > 1:
157-
# there are multiple properties with the same name, raise error
165+
# there are multiple properties with the same custom ID, raise error
158166
raise Exception(
159-
f"Failed to return Benchmark {salesforce_benchmark_id}...multiple benchmarks with that name found",
167+
f"Failed to return Benchmark {custom_id_value}...multiple benchmarks with that custom ID found",
160168
)
161169
else:
162170
# there is no property, return empty dict
@@ -307,6 +315,26 @@ def get_property_by_id(self, property_id: str) -> dict:
307315
except BaseException:
308316
raise Exception("Error retrieving property by ID")
309317

318+
def get_accounts(self) -> list:
319+
"""Get all accounts in salesforce
320+
321+
Returns:
322+
list: list of accounts in salesforce
323+
"""
324+
soql_query = "SELECT Id, Name FROM Account"
325+
results = self.connection.query_all(soql_query)
326+
return results["records"]
327+
328+
def get_contacts(self) -> list:
329+
"""Get all contacts in salesforce
330+
331+
Returns:
332+
list: list of contacts in salesforce
333+
"""
334+
soql_query = "SELECT Id, Name, Email FROM Contact"
335+
results = self.connection.query_all(soql_query)
336+
return results["records"]
337+
310338
def get_account_by_account_id(self, account_id: str) -> dict:
311339
"""Return the account by the account ID.
312340

tests/test_salesforce_client.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,28 +165,31 @@ def test_benchmark(self):
165165
benchmark = self.sf.get_first_benchmark()
166166
print(f" Benchmark: {benchmark}")
167167
assert benchmark is not None
168-
benchmark_id = benchmark["Id"]
169-
salesforce_benchmark_id = benchmark["Salesforce_Benchmark_ID__c"]
170168

171169
# can you retrieve by "Salesforce Benchmark ID" custom field?
170+
salesforce_benchmark_id = benchmark["Salesforce_Benchmark_ID__c"]
172171
print(" ...retrieving benchmark by Salesforce Benchmark ID...")
173-
bench_by_custom_id = self.sf.get_benchmark_by_custom_id(salesforce_benchmark_id)
172+
bench_by_custom_id = self.sf.get_benchmark_by_custom_id("Salesforce_Benchmark_ID__c", salesforce_benchmark_id)
174173
print(f" benchmark by custom id: {bench_by_custom_id}")
175-
assert bench_by_custom_id["Id"] == benchmark_id
174+
# We are not retrieving by the actual record ID,
175+
# but rather a custom field that should be unique but is not necessarily the record ID
176+
actual_id = bench_by_custom_id["Id"]
177+
# assert that bench_by_custom_id has the same Salesforce Benchmark Id as the original custom ID
178+
assert bench_by_custom_id["Salesforce_Benchmark_ID__c"] == salesforce_benchmark_id
176179

177180
# can you update a benchmark field?
178181
print(" ...updating benchmark...")
179182
# TODO: again assuming this field exists...it might not?
180183
energy_star_score = benchmark["ENERGY_STAR_Score__c"]
181184
new_energy_star_score = 20
182185
args = {"ENERGY_STAR_Score__c": new_energy_star_score}
183-
bench_updated = self.sf.update_benchmark(salesforce_benchmark_id, **args)
186+
bench_updated = self.sf.update_benchmark(actual_id, **args)
184187
print(f"benchmark updated: {bench_updated}")
185188

186189
# retrieve again to see if it was updated
187-
bench2 = self.sf.get_benchmark_by_custom_id(salesforce_benchmark_id)
190+
bench2 = self.sf.get_benchmark_by_custom_id("Salesforce_Benchmark_ID__c", salesforce_benchmark_id)
188191
assert bench2["ENERGY_STAR_Score__c"] == new_energy_star_score
189192

190193
# restore value
191194
args["ENERGY_STAR_Score__c"] = energy_star_score
192-
self.sf.update_benchmark(salesforce_benchmark_id, **args)
195+
self.sf.update_benchmark(actual_id, **args)

0 commit comments

Comments
 (0)