@stackql/provider-utils 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +320 -0
- package/package.json +52 -0
- package/src/docgen/generator.js +298 -0
- package/src/docgen/helpers.js +572 -0
- package/src/docgen/index.js +5 -0
- package/src/docgen/resource/examples/delete-example.js +74 -0
- package/src/docgen/resource/examples/exec-example.js +121 -0
- package/src/docgen/resource/examples/insert-example.js +211 -0
- package/src/docgen/resource/examples/select-example.js +73 -0
- package/src/docgen/resource/examples/update-example.js +154 -0
- package/src/docgen/resource/examples.js +31 -0
- package/src/docgen/resource/fields.js +82 -0
- package/src/docgen/resource/methods.js +90 -0
- package/src/docgen/resource/overview.js +39 -0
- package/src/docgen/resource/parameters.js +76 -0
- package/src/docgen/resource-content.js +25 -0
- package/src/index.js +4 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/docgen/resource/examples/exec-example.js
|
|
2
|
+
import {
|
|
3
|
+
getSqlMethodsWithOrderedFields,
|
|
4
|
+
} from '../../helpers.js';
|
|
5
|
+
|
|
6
|
+
export function createExecExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
|
|
7
|
+
const execMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'exec');
|
|
8
|
+
|
|
9
|
+
// if there are no exec methods, return empty content
|
|
10
|
+
if (Object.keys(execMethods).length === 0) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let content = '\n\n## Lifecycle Methods\n\n';
|
|
15
|
+
|
|
16
|
+
// Create tab structure with values array
|
|
17
|
+
content += '<Tabs\n defaultValue="' + Object.keys(execMethods)[0] + '"\n values={[\n';
|
|
18
|
+
|
|
19
|
+
// Add each method as a tab option
|
|
20
|
+
Object.keys(execMethods).forEach((methodName, index, arr) => {
|
|
21
|
+
content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
|
|
22
|
+
content += index < arr.length - 1 ? ',\n' : '\n';
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
content += ' ]}\n>\n';
|
|
26
|
+
|
|
27
|
+
// Create each method tab content
|
|
28
|
+
Object.entries(execMethods).forEach(([methodName, methodDetails]) => {
|
|
29
|
+
content += '<TabItem value="' + methodName + '">\n\n';
|
|
30
|
+
|
|
31
|
+
// Add method description
|
|
32
|
+
content += methodDetails.opDescription || methodDetails.respDescription || 'No description available.';
|
|
33
|
+
|
|
34
|
+
// Create SQL example
|
|
35
|
+
content += '\n\n```sql\nEXEC ' + providerName + '.' + serviceName + '.' + resourceName + '.' + methodName + ' \n';
|
|
36
|
+
|
|
37
|
+
// Add required and optional parameters with @ prefix
|
|
38
|
+
const requiredParams = Object.keys(methodDetails.requiredParams || {});
|
|
39
|
+
const optionalParams = Object.keys(methodDetails.optionalParams || {});
|
|
40
|
+
|
|
41
|
+
// Add parameters
|
|
42
|
+
let hasParams = false;
|
|
43
|
+
|
|
44
|
+
// Add required parameters
|
|
45
|
+
requiredParams.forEach((param, index) => {
|
|
46
|
+
content += '@' + param + '=\'{{ ' + param + ' }}\' --required';
|
|
47
|
+
hasParams = true;
|
|
48
|
+
|
|
49
|
+
if (index < requiredParams.length - 1 || optionalParams.length > 0) {
|
|
50
|
+
content += ', \n';
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Add optional parameters
|
|
55
|
+
optionalParams.forEach((param, index) => {
|
|
56
|
+
const paramDetails = methodDetails.optionalParams[param];
|
|
57
|
+
const isBoolean = paramDetails.type === 'boolean';
|
|
58
|
+
|
|
59
|
+
content += '@' + param + '=';
|
|
60
|
+
|
|
61
|
+
if (isBoolean) {
|
|
62
|
+
content += '{{ ' + param + ' }}';
|
|
63
|
+
} else {
|
|
64
|
+
content += '\'{{ ' + param + ' }}\'';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
hasParams = true;
|
|
68
|
+
|
|
69
|
+
if (index < optionalParams.length - 1) {
|
|
70
|
+
content += ', \n';
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Add request body if present
|
|
75
|
+
if (methodDetails.requestBody && methodDetails.requestBody.properties &&
|
|
76
|
+
Object.keys(methodDetails.requestBody.properties).length > 0) {
|
|
77
|
+
|
|
78
|
+
if (hasParams) {
|
|
79
|
+
content += ' \n';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
content += '@@json=\n\'{\n';
|
|
83
|
+
|
|
84
|
+
// Format request body properties as JSON
|
|
85
|
+
// Filter out read-only properties based on OpenAPI readOnly flag
|
|
86
|
+
const bodyProps = Object.entries(methodDetails.requestBody.properties)
|
|
87
|
+
.filter(([_, propDetails]) => propDetails.readOnly !== true)
|
|
88
|
+
.map(([propName]) => propName);
|
|
89
|
+
|
|
90
|
+
bodyProps.forEach((prop, index) => {
|
|
91
|
+
const propDetails = methodDetails.requestBody.properties[prop];
|
|
92
|
+
const isString = propDetails.type !== 'number' &&
|
|
93
|
+
propDetails.type !== 'integer' &&
|
|
94
|
+
propDetails.type !== 'boolean';
|
|
95
|
+
|
|
96
|
+
content += '"' + prop + '": ';
|
|
97
|
+
|
|
98
|
+
if (isString) {
|
|
99
|
+
content += '"{{ ' + prop + ' }}"';
|
|
100
|
+
} else {
|
|
101
|
+
content += '{{ ' + prop + ' }}';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (index < bodyProps.length - 1) {
|
|
105
|
+
content += ', \n';
|
|
106
|
+
} else {
|
|
107
|
+
content += '\n';
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
content += '}\'';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
content += ';\n```\n</TabItem>\n';
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Close tabs
|
|
118
|
+
content += '</Tabs>\n';
|
|
119
|
+
|
|
120
|
+
return content;
|
|
121
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// src/docgen/resource/examples/insert-example.js
|
|
2
|
+
import {
|
|
3
|
+
getSqlMethodsWithOrderedFields,
|
|
4
|
+
} from '../../helpers.js';
|
|
5
|
+
|
|
6
|
+
export function createInsertExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
|
|
7
|
+
const insertMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'insert');
|
|
8
|
+
|
|
9
|
+
// if there are no insert methods, return empty content
|
|
10
|
+
if (Object.keys(insertMethods).length === 0) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let content = '\n\n## `INSERT` examples\n\n';
|
|
15
|
+
|
|
16
|
+
// Create tab structure with values array
|
|
17
|
+
content += '<Tabs\n defaultValue="' + Object.keys(insertMethods)[0] + '"\n values={[\n';
|
|
18
|
+
|
|
19
|
+
// Add each method as a tab option
|
|
20
|
+
Object.keys(insertMethods).forEach((methodName, index) => {
|
|
21
|
+
content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
|
|
22
|
+
if (index < Object.keys(insertMethods).length - 1 || true) { // Always add comma for manifest tab
|
|
23
|
+
content += ',\n';
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Add manifest tab
|
|
28
|
+
content += ' { label: \'Manifest\', value: \'manifest\' }\n';
|
|
29
|
+
content += ' ]}\n>\n';
|
|
30
|
+
|
|
31
|
+
// Create each method tab content
|
|
32
|
+
Object.entries(insertMethods).forEach(([methodName, methodDetails]) => {
|
|
33
|
+
content += '<TabItem value="' + methodName + '">\n\n';
|
|
34
|
+
content += methodDetails.opDescription || 'No description available.';
|
|
35
|
+
|
|
36
|
+
// Create SQL example
|
|
37
|
+
content += '\n\n```sql\nINSERT INTO ' + providerName + '.' + serviceName + '.' + resourceName + ' (\n';
|
|
38
|
+
|
|
39
|
+
// Add requestBody fields prefixed with data__ (excluding read-only props)
|
|
40
|
+
const reqBodyProps = methodDetails.requestBody?.properties
|
|
41
|
+
? Object.entries(methodDetails.requestBody.properties)
|
|
42
|
+
.filter(([_, propDetails]) => propDetails.readOnly !== true)
|
|
43
|
+
.map(([propName]) => propName)
|
|
44
|
+
: [];
|
|
45
|
+
|
|
46
|
+
const requiredBodyProps = methodDetails.requestBody?.required ? methodDetails.requestBody.required : [];
|
|
47
|
+
|
|
48
|
+
const dataProps = reqBodyProps.map(prop => 'data__' + prop);
|
|
49
|
+
|
|
50
|
+
// Combine data props with params
|
|
51
|
+
const requiredParams = Object.keys(methodDetails.requiredParams || {});
|
|
52
|
+
const optionalParams = Object.keys(methodDetails.optionalParams || {});
|
|
53
|
+
const allFields = [...dataProps, ...requiredParams, ...optionalParams];
|
|
54
|
+
|
|
55
|
+
// Add fields to INSERT
|
|
56
|
+
content += allFields.join(',\n');
|
|
57
|
+
|
|
58
|
+
// Start SELECT statement
|
|
59
|
+
content += '\n)\nSELECT \n';
|
|
60
|
+
|
|
61
|
+
// Add values placeholders
|
|
62
|
+
const valueLines = allFields.map(field => {
|
|
63
|
+
const isDataField = field.startsWith('data__');
|
|
64
|
+
const paramName = isDataField ? field.substring(6) : field;
|
|
65
|
+
|
|
66
|
+
// Check for required body props
|
|
67
|
+
let isRequiredBodyParam = false;
|
|
68
|
+
if(isDataField){
|
|
69
|
+
if (requiredBodyProps.includes(paramName)) {
|
|
70
|
+
isRequiredBodyParam = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if it's a number or boolean type
|
|
75
|
+
let isNumber = false;
|
|
76
|
+
let isBoolean = false;
|
|
77
|
+
|
|
78
|
+
if (isDataField && methodDetails.requestBody?.properties?.[paramName]) {
|
|
79
|
+
const propType = methodDetails.requestBody.properties[paramName].type;
|
|
80
|
+
isNumber = propType === 'number' || propType === 'integer';
|
|
81
|
+
isBoolean = propType === 'boolean';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isNumber || isBoolean) {
|
|
85
|
+
return '{{ ' + paramName + ' }}' + (isRequiredBodyParam ? ' --required' : '');
|
|
86
|
+
} else {
|
|
87
|
+
return '\'{{ ' + paramName + ' }}\'' + (isRequiredBodyParam ? ' --required' : '');
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
content += valueLines.join(',\n');
|
|
92
|
+
|
|
93
|
+
// returning clause if properties exist
|
|
94
|
+
if (methodDetails.properties && Object.keys(methodDetails.properties).length > 0) {
|
|
95
|
+
content += '\nRETURNING\n';
|
|
96
|
+
const keys = Object.keys(methodDetails.properties);
|
|
97
|
+
keys.forEach((key, index) => {
|
|
98
|
+
if (index === keys.length - 1) {
|
|
99
|
+
// For the last item, don't add a newline after it
|
|
100
|
+
content += `${key}`;
|
|
101
|
+
} else {
|
|
102
|
+
content += `${key},\n`;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
content += '\n;\n```\n</TabItem>\n';
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
// {
|
|
112
|
+
// "code": {
|
|
113
|
+
// "type": "string",
|
|
114
|
+
// "description": " (example: 000123)"
|
|
115
|
+
// },
|
|
116
|
+
// "createdOn": {
|
|
117
|
+
// "type": "integer (int64)",
|
|
118
|
+
// "description": "Timestamp that specifies when the statement execution started. The timestamp is expressed in milliseconds since the epoch."
|
|
119
|
+
// },
|
|
120
|
+
// "data": {
|
|
121
|
+
// "type": "array",
|
|
122
|
+
// "description": "Result set data."
|
|
123
|
+
// },
|
|
124
|
+
// }
|
|
125
|
+
|
|
126
|
+
// Create manifest tab
|
|
127
|
+
content += '<TabItem value="manifest">\n\n';
|
|
128
|
+
content += '```yaml\n# Description fields are for documentation purposes\n- name: ' + resourceName + '\n props:\n';
|
|
129
|
+
|
|
130
|
+
// Collect all unique params and request body props across all methods
|
|
131
|
+
const allParams = {};
|
|
132
|
+
const allRequestBodyProps = {};
|
|
133
|
+
|
|
134
|
+
Object.values(insertMethods).forEach(method => {
|
|
135
|
+
// Add required params
|
|
136
|
+
Object.entries(method.requiredParams || {}).forEach(([name, details]) => {
|
|
137
|
+
allParams[name] = { ...details, required: true };
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Add optional params
|
|
141
|
+
Object.entries(method.optionalParams || {}).forEach(([name, details]) => {
|
|
142
|
+
if (!allParams[name]) {
|
|
143
|
+
allParams[name] = { ...details, required: false };
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Add request body props (excluding read-only props)
|
|
148
|
+
if (method.requestBody && method.requestBody.properties) {
|
|
149
|
+
Object.entries(method.requestBody.properties)
|
|
150
|
+
.filter(([_, propDetails]) => propDetails.readOnly !== true)
|
|
151
|
+
.forEach(([name, details]) => {
|
|
152
|
+
allRequestBodyProps[name] = details;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Add required params first
|
|
158
|
+
Object.entries(allParams)
|
|
159
|
+
.filter(([_, details]) => details.required)
|
|
160
|
+
.forEach(([name, details]) => {
|
|
161
|
+
const type = details.type || 'string';
|
|
162
|
+
content += ' - name: ' + name + '\n';
|
|
163
|
+
content += ' value: ' + type + '\n';
|
|
164
|
+
content += ' description: Required parameter for the ' + resourceName + ' resource.\n';
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Add request body props
|
|
168
|
+
Object.entries(allRequestBodyProps).forEach(([name, details]) => {
|
|
169
|
+
const type = details.type || 'string';
|
|
170
|
+
const description = details.description || '';
|
|
171
|
+
content += ' - name: ' + name + '\n';
|
|
172
|
+
content += ' value: ' + type + '\n';
|
|
173
|
+
|
|
174
|
+
if (description) {
|
|
175
|
+
// Format multi-line descriptions
|
|
176
|
+
const wrappedDesc = description.replace(/(.{1,80})(\\s+|$)/g, '$1\n ');
|
|
177
|
+
content += ' description: >\n ' + wrappedDesc + '\n';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add enum values if available
|
|
181
|
+
if (details.enum) {
|
|
182
|
+
content += ' valid_values: [\'' + details.enum.join('\', \'') + '\']\n';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Add default value if available
|
|
186
|
+
if (details.default !== undefined) {
|
|
187
|
+
content += ' default: ' + details.default + '\n';
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Add optional params last
|
|
192
|
+
Object.entries(allParams)
|
|
193
|
+
.filter(([_, details]) => !details.required)
|
|
194
|
+
.forEach(([name, details]) => {
|
|
195
|
+
const type = details.type || 'string';
|
|
196
|
+
const description = details.description || '';
|
|
197
|
+
content += ' - name: ' + name + '\n';
|
|
198
|
+
content += ' value: ' + type + '\n';
|
|
199
|
+
|
|
200
|
+
if (description) {
|
|
201
|
+
content += ' description: ' + description + '\n';
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
content += '```\n</TabItem>\n';
|
|
206
|
+
|
|
207
|
+
// Close tabs
|
|
208
|
+
content += '</Tabs>\n';
|
|
209
|
+
|
|
210
|
+
return content;
|
|
211
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/docgen/resource/examples/select-example.js
|
|
2
|
+
import {
|
|
3
|
+
getSqlMethodsWithOrderedFields,
|
|
4
|
+
} from '../../helpers.js';
|
|
5
|
+
|
|
6
|
+
export function createSelectExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
|
|
7
|
+
const selectMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'select');
|
|
8
|
+
|
|
9
|
+
// if there are no select methods, return empty content
|
|
10
|
+
if (Object.keys(selectMethods).length === 0) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let content = '\n\n## `SELECT` examples\n\n';
|
|
15
|
+
|
|
16
|
+
// Create tab structure with values array
|
|
17
|
+
content += '<Tabs\n defaultValue="' + Object.keys(selectMethods)[0] + '"\n values={[\n';
|
|
18
|
+
|
|
19
|
+
// Add each method as a tab option
|
|
20
|
+
Object.keys(selectMethods).forEach((methodName, index, arr) => {
|
|
21
|
+
content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
|
|
22
|
+
content += index < arr.length - 1 ? ',\n' : '\n';
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
content += ' ]}\n>\n';
|
|
26
|
+
|
|
27
|
+
// Create each tab content
|
|
28
|
+
Object.entries(selectMethods).forEach(([methodName, methodDetails]) => {
|
|
29
|
+
content += '<TabItem value="' + methodName + '">\n\n';
|
|
30
|
+
content += methodDetails.opDescription || 'No description available.';
|
|
31
|
+
|
|
32
|
+
// Create SQL example
|
|
33
|
+
content += '\n\n```sql\nSELECT\n';
|
|
34
|
+
|
|
35
|
+
// Add fields
|
|
36
|
+
const fieldNames = Object.keys(methodDetails.properties || {});
|
|
37
|
+
if (fieldNames.length > 0) {
|
|
38
|
+
content += fieldNames.join(',\n');
|
|
39
|
+
} else {
|
|
40
|
+
content += '*';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Add FROM clause
|
|
44
|
+
content += '\nFROM ' + providerName + '.' + serviceName + '.' + resourceName;
|
|
45
|
+
|
|
46
|
+
// Add WHERE clause with parameters
|
|
47
|
+
const requiredParams = Object.keys(methodDetails.requiredParams || {});
|
|
48
|
+
const optionalParams = Object.keys(methodDetails.optionalParams || {});
|
|
49
|
+
|
|
50
|
+
if (requiredParams.length > 0 || optionalParams.length > 0) {
|
|
51
|
+
content += '\nWHERE ';
|
|
52
|
+
|
|
53
|
+
// Add required parameters
|
|
54
|
+
requiredParams.forEach((param, index) => {
|
|
55
|
+
content += param + ' = \'{{ ' + param + ' }}\' -- required';
|
|
56
|
+
content += index < requiredParams.length - 1 || optionalParams.length > 0 ? '\nAND ' : '';
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Add optional parameters
|
|
60
|
+
optionalParams.forEach((param, index) => {
|
|
61
|
+
content += param + ' = \'{{ ' + param + ' }}\'';
|
|
62
|
+
content += index < optionalParams.length - 1 ? '\nAND ' : '';
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
content += ';\n```\n</TabItem>\n';
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Close tabs
|
|
70
|
+
content += '</Tabs>\n';
|
|
71
|
+
|
|
72
|
+
return content;
|
|
73
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/docgen/resource/examples/update-example.js
|
|
2
|
+
import {
|
|
3
|
+
getSqlMethodsWithOrderedFields,
|
|
4
|
+
} from '../../helpers.js';
|
|
5
|
+
|
|
6
|
+
export function createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, isReplace = false) {
|
|
7
|
+
const updateMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, isReplace ? 'replace' : 'update');
|
|
8
|
+
|
|
9
|
+
// if there are no update methods, return empty content
|
|
10
|
+
if (Object.keys(updateMethods).length === 0) {
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let content = '';
|
|
15
|
+
if (isReplace) {
|
|
16
|
+
content += '\n\n## `REPLACE` examples\n\n';
|
|
17
|
+
} else {
|
|
18
|
+
content += '\n\n## `UPDATE` examples\n\n';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Create tab structure with values array
|
|
22
|
+
content += '<Tabs\n defaultValue="' + Object.keys(updateMethods)[0] + '"\n values={[\n';
|
|
23
|
+
|
|
24
|
+
// Add each method as a tab option
|
|
25
|
+
Object.keys(updateMethods).forEach((methodName, index, arr) => {
|
|
26
|
+
content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
|
|
27
|
+
content += index < arr.length - 1 ? ',\n' : '\n';
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
content += ' ]}\n>\n';
|
|
31
|
+
|
|
32
|
+
// Create each method tab content
|
|
33
|
+
Object.entries(updateMethods).forEach(([methodName, methodDetails]) => {
|
|
34
|
+
content += '<TabItem value="' + methodName + '">\n\n';
|
|
35
|
+
|
|
36
|
+
// Add method description
|
|
37
|
+
content += methodDetails.opDescription || methodDetails.respDescription || 'No description available.';
|
|
38
|
+
|
|
39
|
+
// Create SQL example
|
|
40
|
+
content += '\n\n```sql\n';
|
|
41
|
+
content += (isReplace ? 'REPLACE ' : 'UPDATE ') + providerName + '.' + serviceName + '.' + resourceName;
|
|
42
|
+
|
|
43
|
+
// Add SET clause with requestBody fields (excluding read-only props)
|
|
44
|
+
content += '\nSET \n';
|
|
45
|
+
|
|
46
|
+
// Get request body fields (excluding read-only props)
|
|
47
|
+
const reqBodyProps = methodDetails.requestBody?.properties
|
|
48
|
+
? Object.entries(methodDetails.requestBody.properties)
|
|
49
|
+
.filter(([_, propDetails]) => propDetails.readOnly !== true)
|
|
50
|
+
.map(([propName]) => propName)
|
|
51
|
+
: [];
|
|
52
|
+
|
|
53
|
+
// Add data__ prefixed fields to SET clause
|
|
54
|
+
if (reqBodyProps.length > 0) {
|
|
55
|
+
const setLines = reqBodyProps.map(prop => {
|
|
56
|
+
const propDetails = methodDetails.requestBody.properties[prop];
|
|
57
|
+
const isNumber = propDetails.type === 'number' || propDetails.type === 'integer';
|
|
58
|
+
const isBoolean = propDetails.type === 'boolean';
|
|
59
|
+
|
|
60
|
+
if (isNumber || isBoolean) {
|
|
61
|
+
return 'data__' + prop + ' = {{ ' + prop + ' }}';
|
|
62
|
+
} else {
|
|
63
|
+
return 'data__' + prop + ' = \'{{ ' + prop + ' }}\'';
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
content += setLines.join(',\n');
|
|
68
|
+
} else {
|
|
69
|
+
content += '-- No updatable properties';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Add WHERE clause with parameters
|
|
73
|
+
const requiredParams = Object.keys(methodDetails.requiredParams || {});
|
|
74
|
+
const optionalParams = Object.keys(methodDetails.optionalParams || {});
|
|
75
|
+
|
|
76
|
+
// Get required body props (excluding read-only props)
|
|
77
|
+
const requiredBodyProps = methodDetails.requestBody?.required
|
|
78
|
+
? methodDetails.requestBody.required.filter(prop =>
|
|
79
|
+
methodDetails.requestBody.properties[prop] &&
|
|
80
|
+
methodDetails.requestBody.properties[prop].readOnly !== true)
|
|
81
|
+
: [];
|
|
82
|
+
|
|
83
|
+
content += '\nWHERE \n';
|
|
84
|
+
|
|
85
|
+
// Add required parameters
|
|
86
|
+
let clauseCount = 0;
|
|
87
|
+
|
|
88
|
+
// Add required query/path/header params
|
|
89
|
+
requiredParams.forEach(param => {
|
|
90
|
+
if (clauseCount > 0) content += '\nAND ';
|
|
91
|
+
content += param + ' = \'{{ ' + param + ' }}\' --required';
|
|
92
|
+
clauseCount++;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Add required body params (only non-readonly ones)
|
|
96
|
+
requiredBodyProps.forEach(prop => {
|
|
97
|
+
if (clauseCount > 0) content += '\nAND ';
|
|
98
|
+
|
|
99
|
+
const propDetails = methodDetails.requestBody.properties[prop];
|
|
100
|
+
const isBoolean = propDetails.type === 'boolean';
|
|
101
|
+
|
|
102
|
+
if (isBoolean) {
|
|
103
|
+
content += 'data__' + prop + ' = {{ ' + prop + ' }} --required';
|
|
104
|
+
} else {
|
|
105
|
+
content += 'data__' + prop + ' = \'{{ ' + prop + ' }}\' --required';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
clauseCount++;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Add optional parameters
|
|
112
|
+
optionalParams.forEach(param => {
|
|
113
|
+
if (clauseCount > 0) content += '\nAND ';
|
|
114
|
+
|
|
115
|
+
// For boolean parameters, we can add a comment about their default value
|
|
116
|
+
const paramDetails = methodDetails.optionalParams[param];
|
|
117
|
+
const isBoolean = paramDetails.type === 'boolean';
|
|
118
|
+
const defaultValue = paramDetails.default;
|
|
119
|
+
|
|
120
|
+
if (isBoolean) {
|
|
121
|
+
content += param + ' = {{ ' + param + '}}';
|
|
122
|
+
} else {
|
|
123
|
+
content += param + ' = \'{{ ' + param + '}}\'';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (isBoolean && defaultValue !== undefined) {
|
|
127
|
+
content += ' -- default: ' + defaultValue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
clauseCount++;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// returning clause if properties exist
|
|
134
|
+
if (methodDetails.properties && Object.keys(methodDetails.properties).length > 0) {
|
|
135
|
+
content += '\nRETURNING\n';
|
|
136
|
+
const keys = Object.keys(methodDetails.properties);
|
|
137
|
+
keys.forEach((key, index) => {
|
|
138
|
+
if (index === keys.length - 1) {
|
|
139
|
+
// For the last item, don't add a newline after it
|
|
140
|
+
content += `${key}`;
|
|
141
|
+
} else {
|
|
142
|
+
content += `${key},\n`;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
content += ';\n```\n</TabItem>\n';
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Close tabs
|
|
151
|
+
content += '</Tabs>\n';
|
|
152
|
+
|
|
153
|
+
return content;
|
|
154
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/docgen/resource/examples.js
|
|
2
|
+
|
|
3
|
+
import { createSelectExamples } from './examples/select-example.js';
|
|
4
|
+
import { createInsertExamples } from './examples/insert-example.js';
|
|
5
|
+
import { createUpdateExamples } from './examples/update-example.js';
|
|
6
|
+
import { createDeleteExamples } from './examples/delete-example.js';
|
|
7
|
+
import { createExecExamples } from './examples/exec-example.js';
|
|
8
|
+
|
|
9
|
+
export function createExamplesSection(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
|
|
10
|
+
let content = '';
|
|
11
|
+
|
|
12
|
+
// Add SELECT examples
|
|
13
|
+
content += createSelectExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
|
|
14
|
+
|
|
15
|
+
// Add INSERT examples
|
|
16
|
+
content += createInsertExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
|
|
17
|
+
|
|
18
|
+
// Add UPDATE examples
|
|
19
|
+
content += createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, false);
|
|
20
|
+
|
|
21
|
+
// Add REPLACE examples
|
|
22
|
+
content += createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, true);
|
|
23
|
+
|
|
24
|
+
// Add DELETE examples
|
|
25
|
+
content += createDeleteExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
|
|
26
|
+
|
|
27
|
+
// Add EXEC examples
|
|
28
|
+
content += createExecExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
|
|
29
|
+
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/docgen/resource/fields.js
|
|
2
|
+
import {
|
|
3
|
+
getSqlMethodsWithOrderedFields,
|
|
4
|
+
} from '../helpers.js';
|
|
5
|
+
|
|
6
|
+
const mdCodeAnchor = "`";
|
|
7
|
+
|
|
8
|
+
export function createFieldsSection(resourceData, dereferencedAPI) {
|
|
9
|
+
let content = '## Fields\n\n';
|
|
10
|
+
|
|
11
|
+
content += 'The following fields are returned by `SELECT` queries:\n\n';
|
|
12
|
+
|
|
13
|
+
// Use the reusable function to get methods with ordered fields
|
|
14
|
+
const methods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'select');
|
|
15
|
+
|
|
16
|
+
if (Object.keys(methods).length > 0) {
|
|
17
|
+
// Create the tabs and markdown content
|
|
18
|
+
const methodNames = Object.keys(methods);
|
|
19
|
+
|
|
20
|
+
// Create the tab values array for the Tabs component
|
|
21
|
+
const tabValues = methodNames.map(methodName => {
|
|
22
|
+
return `{ label: '${methodName}', value: '${methodName}' }`;
|
|
23
|
+
}).join(',\n ');
|
|
24
|
+
|
|
25
|
+
// Start building the Tabs component
|
|
26
|
+
content += `<Tabs
|
|
27
|
+
defaultValue="${methodNames[0]}"
|
|
28
|
+
values={[
|
|
29
|
+
${tabValues}
|
|
30
|
+
]}
|
|
31
|
+
>\n`;
|
|
32
|
+
|
|
33
|
+
// Create the TabItems with table content
|
|
34
|
+
for (const methodName of methodNames) {
|
|
35
|
+
const methodData = methods[methodName];
|
|
36
|
+
|
|
37
|
+
// Start the TabItem
|
|
38
|
+
content += `<TabItem value="${methodName}">\n\n`;
|
|
39
|
+
|
|
40
|
+
// Add the method description if available
|
|
41
|
+
if (methodData.respDescription) {
|
|
42
|
+
content += `${methodData.respDescription}\n\n`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Add the table header
|
|
46
|
+
content += `<table>
|
|
47
|
+
<thead>
|
|
48
|
+
<tr>
|
|
49
|
+
<th>Name</th>
|
|
50
|
+
<th>Datatype</th>
|
|
51
|
+
<th>Description</th>
|
|
52
|
+
</tr>
|
|
53
|
+
</thead>
|
|
54
|
+
<tbody>`;
|
|
55
|
+
|
|
56
|
+
// Add each property as a row in the table
|
|
57
|
+
for (const [propName, propData] of Object.entries(methodData.properties)) {
|
|
58
|
+
content += `\n<tr>
|
|
59
|
+
<td><CopyableCode code="${propName}" /></td>
|
|
60
|
+
<td><code>${propData.type}</code></td>
|
|
61
|
+
<td>${propData.description}</td>
|
|
62
|
+
</tr>`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
content += `\n</tbody>
|
|
66
|
+
</table>
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
// Close the TabItem
|
|
70
|
+
content += `</TabItem>\n`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Close the Tabs component
|
|
74
|
+
content += `</Tabs>\n`;
|
|
75
|
+
} else {
|
|
76
|
+
// no fields
|
|
77
|
+
content += `${mdCodeAnchor}SELECT${mdCodeAnchor} not supported for this resource, use ${mdCodeAnchor}SHOW METHODS${mdCodeAnchor} to view available operations for the resource.\n\n`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return content;
|
|
81
|
+
}
|
|
82
|
+
|