Skip to content
Merged
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
15 changes: 0 additions & 15 deletions .claude/settings.local.json

This file was deleted.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ stackql
stackql-zip
.stackql/
stackql-server.log

.claude/
/provider-dev/downloaded/*
dependent_schemas.yaml
45 changes: 44 additions & 1 deletion bin/generate-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,46 @@ function createResourceIndexContent(serviceName, resourceName, resourceType, res

}

// Custom view resources (vw_ prefix, x-type: custom_view)
// These use config.docs.fields for field definitions and config.docs.requiredParams for WHERE clause
if (resourceType === 'custom_view') {
const docsConfig = resourceData?.config?.docs;
const docFields = docsConfig?.fields || [];
const requiredParams = docsConfig?.requiredParams || [];

// Build a synthetic schema.properties from config.docs.fields for field display
// Exclude 'region' as it is auto-added by the doc generator
const nonRegionFields = docFields.filter(f => f.name !== 'region');
const syntheticProperties = {};
for (const field of nonRegionFields) {
syntheticProperties[field.name] = {
type: field.type || 'string',
description: field.description || '',
};
}
// fields as array of field names (used by getColumns with isList=true)
fields = nonRegionFields.map(f => f.name);
schema = { properties: syntheticProperties };

resourceDescription = `Custom view of <code>${resourceName.replace(/^vw_/, '')}</code> resources in a region`;

sqlVerbsList.push({
sqlVerbName: 'select',
methodName: 'view',
requiredParams: requiredParams.length > 0 ? requiredParams.map(p => p.name).join(', ') : 'region'
});

hasList = true;

// Build WHERE clause from requiredParams
if (requiredParams.length > 0) {
const whereParts = requiredParams.map(p => `${p.name} = '{{ ${p.name} }}'`);
sqlExampleWhere = `WHERE ${whereParts.join(' AND\n ')}`;
}

sqlExampleListWhere = `WHERE\n ${sqlExampleWhere.replace(/^WHERE\s+/, '')};`;
}

// DDL view exception: only for native services (cloud_control, tagging)
// These views have no x-type but have config.views.select.ddl with a SELECT * FROM <base_resource>
if (!resourceType && nativeServices.includes(serviceName) && resourceData?.config?.views?.select?.ddl) {
Expand Down Expand Up @@ -1407,7 +1447,10 @@ ${codeBlockEnd}
if(hasList){
let listDesc = `Lists all <code>${resourceName.replace('_list_only','')}</code> in a region.`;

if(resourceName.endsWith('_list_only')){
if(resourceName.startsWith('vw_')){
listDesc = `Lists all <code>${resourceName}</code> in a region.`;
returnString += `${listDesc}\n${sqlCodeBlockStart}\n${sqlExampleSelect}\n${sqlExampleListCols}\n${sqlExampleFrom}\n${sqlExampleListWhere}\n${codeBlockEnd}`;
} else if(resourceName.endsWith('_list_only')){
returnString += `${listDesc}\n${sqlCodeBlockStart}\n${sqlExampleSelect}\n${sqlExampleListCols}\n${sqlExampleFrom}\n${sqlExampleListWhere}\n${codeBlockEnd}`;
} else if(resourceName.endsWith('_tags')){
listDesc = `Expands tags for all <code>${pluralize.plural(resourceName.replace('_tags',''))}</code> in a region.`;
Expand Down
40 changes: 40 additions & 0 deletions bin/generate-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const libDir = '../lib';
const providerDevDir = '../provider-dev';
const openAPIDir = '../openapi';
const viewsDir = '../views';

import * as fs from 'fs'; // For synchronous methods like fs.existsSync
import path from "path";
Expand Down Expand Up @@ -225,6 +226,13 @@ async function processService(servicePrefix, outputFilename) {
}
Object.assign(openAPI.components['x-stackQL-resources'], stackqlViews);

// Load and merge custom views for this service
const customViews = loadCustomViews(serviceTitle);
if (Object.keys(customViews).length > 0) {
Object.assign(openAPI.components['x-stackQL-resources'], customViews);
console.log(`Merged ${Object.keys(customViews).length} custom view(s) for ${serviceTitle}`);
}

if (!Object.keys(openAPI.components['x-stackQL-resources']).length) {
return false;
}
Expand Down Expand Up @@ -308,6 +316,38 @@ function addAdditionalRoutes(openAPISpec, serviceTitle) {
return openAPISpec;
}

function loadCustomViews(serviceName) {
const serviceViewsDir = path.join(__dirname, viewsDir, serviceName.toLowerCase());
const customViews = {};

if (!fs.existsSync(serviceViewsDir)) {
return customViews;
}

const viewFiles = fs.readdirSync(serviceViewsDir).filter(file => file.endsWith('.yaml'));

for (const file of viewFiles) {
const filePath = path.join(serviceViewsDir, file);
const content = fs.readFileSync(filePath, 'utf8');
const viewDefs = load(content);

for (const [viewName, viewDef] of Object.entries(viewDefs)) {
// Ensure x-type is set to 'custom_view' for custom views
viewDef['x-type'] = 'custom_view';
viewDef.methods = viewDef.methods || {};
viewDef.sqlVerbs = viewDef.sqlVerbs || {
insert: [],
delete: [],
update: [],
};
customViews[viewName] = viewDef;
console.log(`Loaded custom view: ${viewName} for service ${serviceName}`);
}
}

return customViews;
}

function findFilesInDocs(filter) {

const filePath = filter? path.join(docsDir, filter) : docsDir;
Expand Down
59 changes: 59 additions & 0 deletions openapi/src/awscc/v00.00.00000/services/ec2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28780,6 +28780,65 @@ components:
json_extract_path_text(Properties, 'VPNGatewayId') as v_pn_gateway_id
FROM awscc.cloud_control.resources WHERE TypeName = 'AWS::EC2::VPNGateway'
AND region = 'us-east-1'
vw_subnet_route_table_associations:
name: vw_subnet_route_table_associations
id: awscc.ec2.vw_subnet_route_table_associations
config:
docs:
fields:
- name: region
type: string
description: AWS region.
- name: route_table_id
type: string
description: The ID of the route table associated with the subnet.
- name: id
type: string
description: The unique identifier for the subnet route table association.
- name: subnet_id
type: string
description: The ID of the subnet.
requiredParams:
- name: region
type: string
description: AWS region (e.g. us-east-1).
views:
select:
predicate: sqlDialect == "sqlite3"
ddl: |-
SELECT
detail.region,
JSON_EXTRACT(detail.Properties, '$.RouteTableId') as route_table_id,
JSON_EXTRACT(detail.Properties, '$.Id') as id,
JSON_EXTRACT(detail.Properties, '$.SubnetId') as subnet_id
FROM awscc.cloud_control.resources listing
INNER JOIN awscc.cloud_control.resource detail
ON detail.Identifier = listing.Identifier
AND detail.region = listing.region
WHERE listing.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND detail.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND listing.region = 'us-east-1'
fallback:
predicate: sqlDialect == "postgres"
ddl: |-
SELECT
detail.region,
json_extract_path_text(detail.Properties, 'RouteTableId') as route_table_id,
json_extract_path_text(detail.Properties, 'Id') as id,
json_extract_path_text(detail.Properties, 'SubnetId') as subnet_id
FROM awscc.cloud_control.resources listing
INNER JOIN awscc.cloud_control.resource detail
ON detail.Identifier = listing.Identifier
AND detail.region = listing.region
WHERE listing.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND detail.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND listing.region = 'us-east-1'
x-type: custom_view
methods: {}
sqlVerbs:
insert: []
delete: []
update: []
paths:
/?Action=CreateResource&Version=2021-09-30:
parameters:
Expand Down
53 changes: 53 additions & 0 deletions views/ec2/vw_subnet_route_table_associations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
vw_subnet_route_table_associations:
name: vw_subnet_route_table_associations
id: awscc.ec2.vw_subnet_route_table_associations
config:
docs:
fields:
- name: region
type: string
description: AWS region.
- name: route_table_id
type: string
description: The ID of the route table associated with the subnet.
- name: id
type: string
description: The unique identifier for the subnet route table association.
- name: subnet_id
type: string
description: The ID of the subnet.
requiredParams:
- name: region
type: string
description: AWS region (e.g. us-east-1).
views:
select:
predicate: sqlDialect == "sqlite3"
ddl: |-
SELECT
detail.region,
JSON_EXTRACT(detail.Properties, '$.RouteTableId') as route_table_id,
JSON_EXTRACT(detail.Properties, '$.Id') as id,
JSON_EXTRACT(detail.Properties, '$.SubnetId') as subnet_id
FROM awscc.cloud_control.resources listing
INNER JOIN awscc.cloud_control.resource detail
ON detail.Identifier = listing.Identifier
AND detail.region = listing.region
WHERE listing.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND detail.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND listing.region = 'us-east-1'
fallback:
predicate: sqlDialect == "postgres"
ddl: |-
SELECT
detail.region,
json_extract_path_text(detail.Properties, 'RouteTableId') as route_table_id,
json_extract_path_text(detail.Properties, 'Id') as id,
json_extract_path_text(detail.Properties, 'SubnetId') as subnet_id
FROM awscc.cloud_control.resources listing
INNER JOIN awscc.cloud_control.resource detail
ON detail.Identifier = listing.Identifier
AND detail.region = listing.region
WHERE listing.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND detail.TypeName = 'AWS::EC2::SubnetRouteTableAssociation'
AND listing.region = 'us-east-1'
2 changes: 1 addition & 1 deletion website/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ AWS Cloud Control API provider for StackQL.
<div class="row">
<div class="providerDocColumn">
<span>total services:&nbsp;<b>237</b></span><br />
<span>total resources:&nbsp;<b>1233</b></span><br />
<span>total resources:&nbsp;<b>1234</b></span><br />
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_cancelled_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_cancelled_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_create_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_create_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_delete_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_delete_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_failed_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_failed_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_pending_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_pending_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_successful_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_successful_requests
WHERE
region = '{{ region }}';
```



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ View of <code>resource_requests</code> filtered by the SQL WHERE clause; see <a
</table>

## `SELECT` examples

Lists all <code>vw_update_requests</code> in a region.
```sql
SELECT
region
FROM awscc.cloud_control.vw_update_requests
WHERE
region = '{{ region }}';
```



Expand Down
Loading
Loading