aws / aws/graph-explorer

Detect database capabilities using probe queries

Open
#1,596 0 comments 0 reactions 0 assignees View on GitHub
connection database support enhancement
Dominant language
TypeScript
Stars
481
Forks
108
Avg merge
6d 8h
Merged PRs (30d)
5

Description

## Description

Different graph database engines and versions support different query language features. Currently, query templates use a one-size-fits-all approach that cannot take advantage of newer capabilities (e.g., case-insensitive matching) or gracefully degrade when features are unavailable.

We need a capabilities detection system that runs probe queries against the connected database to determine which features are supported, then stores the results on the `RawConfiguration` so query templates can adapt accordingly.

### Example: Case-Insensitive Search

| Engine | Approach |
|---|---|
| Gremlin 3.7.1+ | `asString().toLower()` step |
| Gremlin 3.6.0+ | `TextP.regex()` with `(?i)` flag |
| Gremlin < 3.6 | Case-sensitive `containing()` only |
| openCypher | `toLower()` (always available per openCypher spec v9) |
| SPARQL | `regex()` with `"i"` flag or `LCASE()` (W3C SPARQL 1.1 standard) |

## Preferred Solution

### 1. Define capabilities as a const type with query-language-prefixed keys

Following the same pattern as `queryEngineOptions`:

```typescript
export const databaseCapabilityOptions = [
"gremlin:toLower",
"gremlin:regex",
] as const;

export type DatabaseCapability = (typeof databaseCapabilityOptions)[number];
```

### 2. Store capabilities on `RawConfiguration`

Capabilities are a per-connection concern persisted alongside the schema:

```typescript
export type RawConfiguration = {
id: ConfigurationId;
displayLabel?: string;
connection?: ConnectionConfig;
schema?: SchemaStorageModel;
capabilities?: DatabaseCapability[];
};
```

### 3. Expose `hasCapability` on `NormalizedConnection`

The `Set` is abstracted away from consumers. `normalizeConnection` accepts the capabilities array from `RawConfiguration` and exposes a typed method:

```typescript
export function normalizeConnection(
connection: ConnectionConfig,
capabilities?: DatabaseCapability[],
) {
const capabilitySet = new Set(capabilities);
return {
...connection,
// ...existing normalization...
hasCapability(key: DatabaseCapability) {
return capabilitySet.has(key);
},
};
}
```

`activeConnectionAtom` and `mergeConfiguration` would pass `config.capabilities` through to `normalizeConnection`. Since `NormalizedConnection` is `ReturnType`, the method is automatically available on the type.

### 4. Implement probe queries per engine

Run lightweight queries that succeed or fail to detect support:

- **Gremlin toLower** (3.7.1+): `g.inject("TEST").asString().toLower()`
- **Gremlin regex** (3.6.0+): `g.V().limit(0).has("_x", regex(".*"))`
- **openCypher**: No probing needed — `toLower()` is part of the openCypher spec v9
- **SPARQL**: No probing needed — `regex()` and `LCASE()` are part of the W3C SPARQL 1.1 standard

For openCypher and SPARQL, probing simply populates the capabilities array with their inherent capabilities.

### 5. Run probing at connection establishment time

Probing could run as part of:
- The test connection flow (#1289)
- Schema sync
- Or both

Results are persisted on `RawConfiguration` so they survive page reloads.

### 6. Use capabilities in query templates

Templates conditionally generate different query syntax:

```typescript
if (connection.hasCapability("gremlin:toLower")) {
// use toLower step
} else if (connection.hasCapability("gremlin:regex")) {
// use regex with (?i)
} else {
// case-sensitive fallback
}
```

### Initial capability candidates

- **`gremlin:toLower`** — TinkerPop 3.7.1+ string manipulation step
- **`gremlin:regex`** — TinkerPop 3.6.0+ regex predicates

This list can grow over time as we identify more features that vary across engines and versions.

## Related Issues

- Related to #1289

Contributor guide

Open the contributing guide

Research direction

Start with RawConfiguration, normalizeConnection, activeConnectionAtom, and mergeConfiguration to trace how connection state is stored and established. Review the test connection flow (#1289), schema sync, and query templates before choosing where probes run. Done means supported capabilities are persisted, exposed through hasCapability, and used by templates with the specified fallbacks.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.