Skip to content
Draft
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
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,19 @@ http_memprof_out

# custom dc sqlite database
sqlite

# C++ client

# CMake
cpp-client/build/
cpp-client/CMakeCache.txt
cpp-client/CMakeFiles/
cpp-client/cmake_install.cmake

# Compiled files
*.o
*.so
*.a
*.dll
*.exe
*.out
13 changes: 13 additions & 0 deletions cpp-client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CMake
build/
CMakeCache.txt
CMakeFiles/
cmake_install.cmake

# Compiled files
*.o
*.so
*.a
*.dll
*.exe
*.out
29 changes: 29 additions & 0 deletions cpp-client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.11)
project(datacommons-cpp)

set(CMAKE_CXX_STANDARD 17)

include(FetchContent)

FetchContent_Declare(
cpr
GIT_REPOSITORY https://github.com/libcpr/cpr.git
GIT_TAG 1.8.3
)

FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.10.5
)

FetchContent_MakeAvailable(cpr nlohmann_json)

add_library(datacommons src/DataCommons.cpp)

target_include_directories(datacommons PUBLIC include)

target_link_libraries(datacommons PUBLIC cpr::cpr nlohmann_json::nlohmann_json)

add_executable(example examples/main.cpp)
target_link_libraries(example PRIVATE datacommons)
58 changes: 58 additions & 0 deletions cpp-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Data Commons C++ Client Library

A C++ client library for accessing the Data Commons API.

## Authentication

The recommended way to provide your API key is by setting the `DC_API_KEY` environment variable. The client will automatically detect and use it.

```bash
export DC_API_KEY="YOUR_API_KEY"
```

Alternatively, you can pass the key directly to the constructor:

```cpp
#include "DataCommons.h"

int main() {
datacommons::DataCommons dc("YOUR_API_KEY");
// ...
return 0;
}
```

## Building and Running the Example

### Prerequisites

- C++17 compiler (g++ or Clang)
- CMake (3.11+)
- Git
- OpenSSL development libraries (`libssl-dev` on Debian/Ubuntu)

### Steps

1. **Clone the repository and navigate to the client directory.**
2. **Create a build directory:**
```bash
mkdir build
cd build
```
3. **Configure and build the project:**
```bash
cmake ..
make
```
4. **Set your API key:**
```bash
export DC_API_KEY="YOUR_API_KEY"
```
5. **Run the example:**
```bash
./example
```

## Usage

See the `USAGE.md` file for a detailed guide to the library's functions.
212 changes: 212 additions & 0 deletions cpp-client/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Data Commons C++ Client Usage Guide

This guide provides a summary of the available endpoints in the Data Commons C++ client library and examples of how to use them.

## Getting Started

First, ensure you have set your Data Commons API key as an environment variable:

```bash
export DC_API_KEY="YOUR_API_KEY"
```

Then, you can create a `DataCommons` client object in your C++ code:

```cpp
#include "DataCommons.h"
#include <iostream>
#include <stdexcept>

int main() {
try {
datacommons::DataCommons dc;
// Your code here...
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
```

## Core V2 API Endpoints

The C++ client provides access to the four core V2 endpoints of the Data Commons REST API.

### 1. GetPropertyValues

Fetches property values for one or more nodes. This method returns the raw JSON response from the API, giving you the flexibility to parse it as needed.

**Use Case:** Find the name and type of a place, like a state or city.

**Example:** Get the `name` and `typeOf` for California (`geoId/06`) and Colorado (`geoId/08`).

```cpp
std::vector<std::string> dcids = {"geoId/06", "geoId/08"};
std::vector<std::string> properties = {"name", "typeOf"};
auto result = dc.GetPropertyValues(dcids, "->", properties);

std::cout << result.dump(2) << std::endl;
```

### 2. GetObservations

Fetches statistical observations. This endpoint provides a flexible way to query for data by specifying variables, entities, and dates in various combinations.

**Use Case:** Get the total, male, and female population counts for California and Colorado in the year 2020.

**Example:**

```cpp
datacommons::ObservationVariable variables;
variables.dcids = {"Count_Person", "Count_Person_Male", "Count_Person_Female"};

datacommons::ObservationEntity entities;
entities.dcids = {"geoId/06", "geoId/08"};

datacommons::ObservationDate date = "2020";

auto result = dc.GetObservations(variables, entities, date);

for (const auto& [variable, entity_map] : result) {
std::cout << "Variable: " << variable << std::endl;
for (const auto& [entity, observations] : entity_map) {
std::cout << " Entity: " << entity << std::endl;
for (const auto& obs : observations) {
std::cout << " Date: " << obs.date << ", Value: " << obs.value << std::endl;
}
}
}
```

You can also use expressions to select entities, for example, to get the population of all counties in California:

```cpp
datacommons::ObservationVariable variables;
variables.dcids = {"Count_Person"};

datacommons::ObservationEntity entities;
entities.expression = "<-containedInPlace{typeOf:County, dcid:geoId/06}";

datacommons::ObservationDate date = "LATEST";

auto result = dc.GetObservations(variables, entities, date);
// ... (process results as above)
```

### 3. Resolve

Resolves human-readable identifiers (like names or coordinates) to Data Commons IDs (DCIDs).

**Use Case:** Find the unique DCID for a place when you only know its name.

**Example:** Find the DCIDs for "California" and "Colorado".

```cpp
std::vector<std::string> nodes = {"California", "Colorado"};
std::string property = "<-description->dcid";
auto result = dc.Resolve(nodes, property);

for (const auto& [node, candidates] : result) {
std::cout << "Node: " << node << std::endl;
for (const auto& candidate : candidates) {
std::cout << " DCID: " << candidate.dcid << ", Type: " << candidate.dominant_type << std::endl;
}
}
```

### 2. GetObservations

Fetches statistical observations. This endpoint provides a flexible way to query for data by specifying variables, entities, and dates in various combinations.

**Use Case:** Get the total, male, and female population counts for California and Colorado in the year 2020.

**Example:**

```cpp
datacommons::ObservationVariable variables;
variables.dcids = {"Count_Person", "Count_Person_Male", "Count_Person_Female"};

datacommons::ObservationEntity entities;
entities.dcids = {"geoId/06", "geoId/08"};

datacommons::ObservationDate date = "2020";

auto result = dc.GetObservations(variables, entities, date);

for (const auto& [variable, entity_map] : result) {
std::cout << "Variable: " << variable << std::endl;
for (const auto& [entity, observations] : entity_map) {
std::cout << " Entity: " << entity << std::endl;
for (const auto& obs : observations) {
std::cout << " Date: " << obs.date << ", Value: " << obs.value << std::endl;
}
}
}
```

You can also use expressions to select entities, for example, to get the population of all counties in California:

```cpp
datacommons::ObservationVariable variables;
variables.dcids = {"Count_Person"};

datacommons::ObservationEntity entities;
entities.expression = "<-containedInPlace{typeOf:County, dcid:geoId/06}";

datacommons::ObservationDate date = "LATEST";

auto result = dc.GetObservations(variables, entities, date);
// ... (process results as above)
```


### 3. Resolve

Resolves human-readable identifiers (like names or coordinates) to Data Commons IDs (DCIDs).

**Use Case:** Find the unique DCID for a place when you only know its name.

**Example:** Find the DCIDs for "California" and "Colorado".

```cpp
std::vector<std::string> nodes = {"California", "Colorado"};
std::string from_property = "description";
std::string to_property = "dcid";
auto result = dc.Resolve(nodes, from_property, to_property);

for (const auto& [node, candidates] : result) {
std::cout << "Node: " << node << std::endl;
for (const auto& candidate : candidates) {
std::cout << " DCID: " << candidate.dcid << ", Type: " << candidate.dominant_type << std::endl;
}
}
```

### 4. Query

Executes a SPARQL query directly against the Data Commons knowledge graph for advanced use cases.

**Use Case:** Retrieve a custom table of data, such as the names and DCIDs of the first 10 states found in the graph.

**Example:**

```cpp
std::string query = "SELECT ?name ?dcid WHERE { ?place typeOf State . ?place name ?name . ?place dcid ?dcid . } LIMIT 10";
auto result = dc.Query(query);

// Print header
for (const auto& header : result.header) {
std::cout << header << "\t";
}
std::cout << std::endl;

// Print rows
for (const auto& row : result.rows) {
for (const auto& header : result.header) {
std::cout << row.at(header) << "\t";
}
std::cout << std::endl;
}
```

Loading