From 07254abf8f107b2d0e7d90c7097652cb8d9f74d7 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Tue, 17 Mar 2026 13:32:06 +1100 Subject: [PATCH 1/2] stop tracking .claude dir --- .claude/settings.local.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 7f3b3ac7c..000000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(find c:LocalGitReposstackql-registryprovidersstackql-provider-awscc -maxdepth 2 \\\\\\(-name Makefile -o -name *.json -o -name *.sh \\\\\\) -type f)", - "Bash(grep -E \"\\(Makefile|package\\\\.json|.*\\\\.sh$\\)\")", - "Bash(find c:LocalGitReposstackql-registryprovidersstackql-provider-awsccopenapisrcawsccv00.00.00000services -name *.yaml -type f)", - "Bash(node bin/generate-docs.js)", - "Bash(xargs echo:*)", - "Bash(grep -A5 \"## \\\\`SELECT\\\\`\" \"c:/LocalGitRepos/stackql-registry/providers/stackql-provider-awscc/website/docs/services/tagging/tagged_resources/index.md\")", - "Bash(for r:*)", - "Bash(do echo:*)", - "Bash(node -e \":*)" - ] - } -} From 2b93e83ae07d96fae01bb289ad168dbe351b2541 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Tue, 17 Mar 2026 14:02:45 +1100 Subject: [PATCH 2/2] website update to include custom views --- .gitignore | 2 +- bin/generate-docs.js | 45 ++++++++- bin/generate-provider.js | 40 ++++++++ .../src/awscc/v00.00.00000/services/ec2.yaml | 59 ++++++++++++ .../vw_subnet_route_table_associations.yaml | 53 +++++++++++ website/docs/index.md | 2 +- .../vw_cancelled_requests/index.md | 9 +- .../cloud_control/vw_create_requests/index.md | 9 +- .../cloud_control/vw_delete_requests/index.md | 9 +- .../cloud_control/vw_failed_requests/index.md | 9 +- .../vw_pending_requests/index.md | 9 +- .../vw_successful_requests/index.md | 9 +- .../cloud_control/vw_update_requests/index.md | 9 +- website/docs/services/ec2/index.md | 9 +- .../index.md | 92 +++++++++++++++++++ 15 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 views/ec2/vw_subnet_route_table_associations.yaml create mode 100644 website/docs/services/ec2/vw_subnet_route_table_associations/index.md diff --git a/.gitignore b/.gitignore index b21cefbb8..de63d239c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,6 @@ stackql stackql-zip .stackql/ stackql-server.log - +.claude/ /provider-dev/downloaded/* dependent_schemas.yaml diff --git a/bin/generate-docs.js b/bin/generate-docs.js index 5e0f241ef..9542534f5 100644 --- a/bin/generate-docs.js +++ b/bin/generate-docs.js @@ -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 ${resourceName.replace(/^vw_/, '')} 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 if (!resourceType && nativeServices.includes(serviceName) && resourceData?.config?.views?.select?.ddl) { @@ -1407,7 +1447,10 @@ ${codeBlockEnd} if(hasList){ let listDesc = `Lists all ${resourceName.replace('_list_only','')} in a region.`; - if(resourceName.endsWith('_list_only')){ + if(resourceName.startsWith('vw_')){ + listDesc = `Lists all ${resourceName} 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 ${pluralize.plural(resourceName.replace('_tags',''))} in a region.`; diff --git a/bin/generate-provider.js b/bin/generate-provider.js index 8012c4448..6aa23c0b3 100644 --- a/bin/generate-provider.js +++ b/bin/generate-provider.js @@ -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"; @@ -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; } @@ -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; diff --git a/openapi/src/awscc/v00.00.00000/services/ec2.yaml b/openapi/src/awscc/v00.00.00000/services/ec2.yaml index a9df88b36..30c986606 100644 --- a/openapi/src/awscc/v00.00.00000/services/ec2.yaml +++ b/openapi/src/awscc/v00.00.00000/services/ec2.yaml @@ -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: diff --git a/views/ec2/vw_subnet_route_table_associations.yaml b/views/ec2/vw_subnet_route_table_associations.yaml new file mode 100644 index 000000000..44f8f31c3 --- /dev/null +++ b/views/ec2/vw_subnet_route_table_associations.yaml @@ -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' diff --git a/website/docs/index.md b/website/docs/index.md index bc3c63606..0e07a8afd 100644 --- a/website/docs/index.md +++ b/website/docs/index.md @@ -24,7 +24,7 @@ AWS Cloud Control API provider for StackQL.
total services: 237
-total resources: 1233
+total resources: 1234
diff --git a/website/docs/services/cloud_control/vw_cancelled_requests/index.md b/website/docs/services/cloud_control/vw_cancelled_requests/index.md index c3fc934a7..caa2100e2 100644 --- a/website/docs/services/cloud_control/vw_cancelled_requests/index.md +++ b/website/docs/services/cloud_control/vw_cancelled_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_cancelled_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_cancelled_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_create_requests/index.md b/website/docs/services/cloud_control/vw_create_requests/index.md index 62d903463..98fe486ee 100644 --- a/website/docs/services/cloud_control/vw_create_requests/index.md +++ b/website/docs/services/cloud_control/vw_create_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_create_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_create_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_delete_requests/index.md b/website/docs/services/cloud_control/vw_delete_requests/index.md index dcbdc0fb4..5a4e61b5e 100644 --- a/website/docs/services/cloud_control/vw_delete_requests/index.md +++ b/website/docs/services/cloud_control/vw_delete_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_delete_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_delete_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_failed_requests/index.md b/website/docs/services/cloud_control/vw_failed_requests/index.md index 2380524a1..d289020ab 100644 --- a/website/docs/services/cloud_control/vw_failed_requests/index.md +++ b/website/docs/services/cloud_control/vw_failed_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_failed_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_failed_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_pending_requests/index.md b/website/docs/services/cloud_control/vw_pending_requests/index.md index be4883943..d92979802 100644 --- a/website/docs/services/cloud_control/vw_pending_requests/index.md +++ b/website/docs/services/cloud_control/vw_pending_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_pending_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_pending_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_successful_requests/index.md b/website/docs/services/cloud_control/vw_successful_requests/index.md index 8463dbd2c..b1ac40590 100644 --- a/website/docs/services/cloud_control/vw_successful_requests/index.md +++ b/website/docs/services/cloud_control/vw_successful_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_successful_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_successful_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/cloud_control/vw_update_requests/index.md b/website/docs/services/cloud_control/vw_update_requests/index.md index b5a0b46a2..52705b174 100644 --- a/website/docs/services/cloud_control/vw_update_requests/index.md +++ b/website/docs/services/cloud_control/vw_update_requests/index.md @@ -104,7 +104,14 @@ View of resource_requests filtered by the SQL WHERE clause; see ## `SELECT` examples - +Lists all vw_update_requests in a region. +```sql +SELECT + region +FROM awscc.cloud_control.vw_update_requests +WHERE + region = '{{ region }}'; +``` diff --git a/website/docs/services/ec2/index.md b/website/docs/services/ec2/index.md index e61b11840..57bec86de 100644 --- a/website/docs/services/ec2/index.md +++ b/website/docs/services/ec2/index.md @@ -20,7 +20,7 @@ The ec2 service documentation.
-total resources: 96
+total resources: 97
@@ -76,10 +76,10 @@ The ec2 service documentation.
route_server_propagations
route_servers
route_tables
-routes +routes
+security_group_egresses \ No newline at end of file diff --git a/website/docs/services/ec2/vw_subnet_route_table_associations/index.md b/website/docs/services/ec2/vw_subnet_route_table_associations/index.md new file mode 100644 index 000000000..354bed4b8 --- /dev/null +++ b/website/docs/services/ec2/vw_subnet_route_table_associations/index.md @@ -0,0 +1,92 @@ +--- +title: vw_subnet_route_table_associations +hide_title: false +hide_table_of_contents: false +keywords: + - vw_subnet_route_table_associations + - ec2 + - aws + - stackql + - infrastructure-as-code + - configuration-as-data + - cloud inventory +description: Query, deploy and manage AWS resources using SQL +custom_edit_url: null +image: /img/stackql-aws-provider-featured-image.png +--- + +import CopyableCode from '@site/src/components/CopyableCode/CopyableCode'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import SchemaTable from '@site/src/components/SchemaTable/SchemaTable'; + +Custom view of subnet_route_table_associations resources in a region + +## Overview + + + + + + + +
Namevw_subnet_route_table_associations
TypeResource
Descriptionvw_subnet_route_table_associations
Id
+ +## Fields + + +## Methods + + + + + + + + + + + + + + +
NameAccessible byRequired Params
SELECT
+ +## `SELECT` examples +Lists all vw_subnet_route_table_associations in a region. +```sql +SELECT + region, + route_table_id, + id, + subnet_id +FROM awscc.ec2.vw_subnet_route_table_associations +WHERE + region = '{{ region }}'; +``` + + + + +