UNPKG

pg-proto-parser

Version:
160 lines (159 loc) 7.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.generateTsAstCodeFromPgAst = generateTsAstCodeFromPgAst; const index_1 = require("./index"); const t = __importStar(require("@babel/types")); /** * Converts an AST (Abstract Syntax Tree) representation of a SQL query into * a meta-level AST that represents the code to generate the original AST. * This meta-level AST can then be used to programmatically construct the AST * for similar SQL queries. Essentially, it's an AST that describes how to * build an AST, enabling dynamic code generation based on the structure of * the original SQL AST. */ // TODO — handle TypeName and SPECIAL_TYPES cases function generateTsAstCodeFromPgAst(ast, runtimeSchema) { const schemaMap = new Map(); runtimeSchema.forEach(spec => { schemaMap.set(spec.name, spec); }); function createAstNode(functionName, properties, isWrapped = true) { const args = properties.map(([propKey, propValue]) => { if (propValue && typeof propValue === 'object' && propValue.type) { return t.objectProperty(t.identifier(propKey), propValue); } return t.objectProperty(t.identifier(propKey), getValueNode(propValue)); }); const builderPath = isWrapped ? 'nodes' : 'ast'; return t.callExpression(t.memberExpression(t.memberExpression(t.identifier('t'), t.identifier(builderPath)), t.identifier(functionName)), [t.objectExpression(args)]); } function getValueNode(value, parentNodeType, fieldName) { if (Array.isArray(value)) { return t.arrayExpression(value.map(item => getValueNode(item, parentNodeType, fieldName))); } else if (typeof value === 'object') { if (value === null) return t.nullLiteral(); if (parentNodeType && fieldName) { const parentSpec = schemaMap.get(parentNodeType); if (parentSpec) { const fieldSpec = parentSpec.fields.find(f => f.name === fieldName); } } return traverse(value, parentNodeType, fieldName); } switch (typeof value) { case 'boolean': return t.booleanLiteral(value); case 'number': return t.numericLiteral(value); case 'string': return t.stringLiteral(value); default: return t.stringLiteral(String(value)); // Fallback for other types } } function findNodeTypeByFields(fieldNames) { for (const nodeSpec of runtimeSchema) { const specFieldNames = nodeSpec.fields.map(f => f.name).sort(); const sortedFieldNames = [...fieldNames].sort(); const hasAllRequiredFields = specFieldNames.every(fieldName => sortedFieldNames.includes(fieldName) || nodeSpec.fields.find(f => f.name === fieldName)?.optional); const hasOnlyValidFields = sortedFieldNames.every(fieldName => specFieldNames.includes(fieldName)); if (hasAllRequiredFields && hasOnlyValidFields && sortedFieldNames.length > 0) { return nodeSpec; } } return null; } function traverse(node, parentNodeType, fieldName) { if (Array.isArray(node)) { return t.arrayExpression(node.map(item => traverse(item, parentNodeType, fieldName))); } else if (node && typeof node === 'object') { const entries = Object.entries(node); if (entries.length === 0) return t.objectExpression([]); if (entries.length === 1) { const [key, value] = entries[0]; const functionName = (0, index_1.toSpecialCamelCase)(key); let isWrapped = true; if (parentNodeType && fieldName) { const parentSpec = schemaMap.get(parentNodeType); if (parentSpec) { const fieldSpec = parentSpec.fields.find(f => f.name === fieldName); if (fieldSpec && fieldSpec.type !== 'Node' && schemaMap.has(fieldSpec.type)) { isWrapped = false; } } } const processedProperties = Object.entries(value).map(([propKey, propValue]) => { return [propKey, getValueNode(propValue, key, propKey)]; }); return createAstNode(functionName, processedProperties, isWrapped); } else { const fieldNames = entries.map(([key]) => key); const matchingNodeSpec = findNodeTypeByFields(fieldNames); if (matchingNodeSpec) { const functionName = (0, index_1.toSpecialCamelCase)(matchingNodeSpec.name); let isWrapped = true; if (parentNodeType && fieldName) { const parentSpec = schemaMap.get(parentNodeType); if (parentSpec) { const parentFieldSpec = parentSpec.fields.find(f => f.name === fieldName); if (parentFieldSpec && parentFieldSpec.type !== 'Node' && schemaMap.has(parentFieldSpec.type)) { isWrapped = false; } } } const processedProperties = entries.map(([propKey, propValue]) => { return [propKey, traverse(propValue, matchingNodeSpec.name, propKey)]; }); return createAstNode(functionName, processedProperties, isWrapped); } else { const properties = entries.map(([propKey, propValue]) => { return t.objectProperty(t.identifier(propKey), traverse(propValue, parentNodeType, propKey)); }); return t.objectExpression(properties); } } } return getValueNode(node, parentNodeType, fieldName); } return traverse(ast); }