UNPKG

@stackql/provider-utils

Version:

Utilities for building StackQL providers from OpenAPI specifications.

208 lines (168 loc) 8.23 kB
// src/docgen/resource/examples/insert-example.js import { getSqlMethodsWithOrderedFields, sanitizeHtml } from '../../helpers.js'; export function createInsertExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) { const insertMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'insert'); // if there are no insert methods, return empty content if (Object.keys(insertMethods).length === 0) { return ''; } let content = '\n\n## `INSERT` examples\n\n'; // Create tab structure with values array content += '<Tabs\n defaultValue="' + Object.keys(insertMethods)[0] + '"\n values={[\n'; // Add each method as a tab option Object.keys(insertMethods).forEach((methodName, index) => { content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }'; if (index < Object.keys(insertMethods).length - 1 || true) { // Always add comma for manifest tab content += ',\n'; } }); // Add manifest tab content += ' { label: \'Manifest\', value: \'manifest\' }\n'; content += ' ]}\n>\n'; // Create each method tab content Object.entries(insertMethods).forEach(([methodName, methodDetails]) => { content += '<TabItem value="' + methodName + '">\n\n'; // Add method description const opDescription = methodDetails.opDescription || 'No description available.'; content += sanitizeHtml(opDescription); // content += methodDetails.opDescription || 'No description available.'; // Create SQL example content += '\n\n```sql\nINSERT INTO ' + providerName + '.' + serviceName + '.' + resourceName + ' (\n'; // Add requestBody fields prefixed with data__ (excluding read-only props) const reqBodyProps = methodDetails.requestBody?.properties ? Object.entries(methodDetails.requestBody.properties) .filter(([_, propDetails]) => propDetails.readOnly !== true) .map(([propName]) => propName) : []; const requiredBodyProps = methodDetails.requestBody?.required ? methodDetails.requestBody.required : []; const dataProps = reqBodyProps.map(prop => 'data__' + prop); // Combine data props with params const requiredParams = Object.keys(methodDetails.requiredParams || {}); const optionalParams = Object.keys(methodDetails.optionalParams || {}); const allFields = [...dataProps, ...requiredParams, ...optionalParams]; // Add fields to INSERT content += allFields.join(',\n'); // Start SELECT statement content += '\n)\nSELECT \n'; // Add values placeholders const valueLines = allFields.map(field => { const isDataField = field.startsWith('data__'); const paramName = isDataField ? field.substring(6) : field; // Check for required body props let isRequiredBodyParam = false; if(isDataField){ if (requiredBodyProps.includes(paramName)) { isRequiredBodyParam = true; } } // Check if it's a number or boolean type let isNumber = false; let isBoolean = false; if (isDataField && methodDetails.requestBody?.properties?.[paramName]) { const propType = methodDetails.requestBody.properties[paramName].type; isNumber = propType === 'number' || propType === 'integer'; isBoolean = propType === 'boolean'; } if (isNumber || isBoolean) { return '{{ ' + paramName + ' }}' + (isRequiredBodyParam ? ' /* required */' : ''); } else { return '\'{{ ' + paramName + ' }}\'' + (isRequiredBodyParam ? ' /* required */' : ''); } }); content += valueLines.join(',\n'); // returning clause if properties exist if (methodDetails.properties && Object.keys(methodDetails.properties).length > 0) { content += '\nRETURNING\n'; const keys = Object.keys(methodDetails.properties); keys.forEach((key, index) => { if (index === keys.length - 1) { // For the last item, don't add a newline after it content += `${key}`; } else { content += `${key},\n`; } }); } content += '\n;\n```\n</TabItem>\n'; }); // Create manifest tab content += '<TabItem value="manifest">\n\n'; content += '```yaml\n# Description fields are for documentation purposes\n- name: ' + resourceName + '\n props:\n'; // Collect all unique params and request body props across all methods const allParams = {}; const allRequestBodyProps = {}; Object.values(insertMethods).forEach(method => { // Add required params Object.entries(method.requiredParams || {}).forEach(([name, details]) => { allParams[name] = { ...details, required: true }; }); // Add optional params Object.entries(method.optionalParams || {}).forEach(([name, details]) => { if (!allParams[name]) { allParams[name] = { ...details, required: false }; } }); // Add request body props (excluding read-only props) if (method.requestBody && method.requestBody.properties) { Object.entries(method.requestBody.properties) .filter(([_, propDetails]) => propDetails.readOnly !== true) .forEach(([name, details]) => { allRequestBodyProps[name] = details; }); } }); // Add required params first Object.entries(allParams) .filter(([_, details]) => details.required) .forEach(([name, details]) => { const type = details.type || 'string'; content += ' - name: ' + name + '\n'; content += ' value: ' + type + '\n'; content += ' description: Required parameter for the ' + resourceName + ' resource.\n'; }); // Add request body props Object.entries(allRequestBodyProps).forEach(([name, details]) => { const type = details.type || 'string'; const description = details.description || ''; content += ' - name: ' + name + '\n'; content += ' value: ' + type + '\n'; if (description) { content += ' description: |\n'; // Split by lines and remove empty lines const lines = description .split(/\n/) .filter(line => line.trim() !== ''); // Remove completely empty lines // Process each line with proper indentation lines.forEach(line => { content += ' ' + line.trim() + '\n'; // trim each line to remove extra spaces }); } // Add enum values if available if (details.enum) { content += ' valid_values: [\'' + details.enum.join('\', \'') + '\']\n'; } // Add default value if available if (details.default !== undefined) { content += ' default: ' + details.default + '\n'; } }); // Add optional params last Object.entries(allParams) .filter(([_, details]) => !details.required) .forEach(([name, details]) => { const type = details.type || 'string'; const description = details.description || ''; content += ' - name: ' + name + '\n'; content += ' value: ' + type + '\n'; if (description) { content += ' description: ' + description + '\n'; } }); content += '```\n</TabItem>\n'; // Close tabs content += '</Tabs>\n'; return content; }