@quickql/server 1.0.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 +91 -0
- package/dist/core/src/client.d.ts +57 -0
- package/dist/core/src/client.d.ts.map +1 -0
- package/dist/core/src/client.js +164 -0
- package/dist/core/src/client.js.map +1 -0
- package/dist/core/src/index.d.ts +13 -0
- package/dist/core/src/index.d.ts.map +1 -0
- package/dist/core/src/index.js +13 -0
- package/dist/core/src/index.js.map +1 -0
- package/dist/core/src/types.d.ts +82 -0
- package/dist/core/src/types.d.ts.map +1 -0
- package/dist/core/src/types.js +12 -0
- package/dist/core/src/types.js.map +1 -0
- package/dist/server/src/engine.d.ts +55 -0
- package/dist/server/src/engine.d.ts.map +1 -0
- package/dist/server/src/engine.js +422 -0
- package/dist/server/src/engine.js.map +1 -0
- package/dist/server/src/errors.d.ts +31 -0
- package/dist/server/src/errors.d.ts.map +1 -0
- package/dist/server/src/errors.js +73 -0
- package/dist/server/src/errors.js.map +1 -0
- package/dist/server/src/executor.d.ts +25 -0
- package/dist/server/src/executor.d.ts.map +1 -0
- package/dist/server/src/executor.js +121 -0
- package/dist/server/src/executor.js.map +1 -0
- package/dist/server/src/filters.d.ts +10 -0
- package/dist/server/src/filters.d.ts.map +1 -0
- package/dist/server/src/filters.js +47 -0
- package/dist/server/src/filters.js.map +1 -0
- package/dist/server/src/handler.d.ts +12 -0
- package/dist/server/src/handler.d.ts.map +1 -0
- package/dist/server/src/handler.js +138 -0
- package/dist/server/src/handler.js.map +1 -0
- package/dist/server/src/index.d.ts +25 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/index.js +26 -0
- package/dist/server/src/index.js.map +1 -0
- package/dist/server/src/parser/parser.d.ts +21 -0
- package/dist/server/src/parser/parser.d.ts.map +1 -0
- package/dist/server/src/parser/parser.js +99 -0
- package/dist/server/src/parser/parser.js.map +1 -0
- package/dist/server/src/parser/tokenizer.d.ts +18 -0
- package/dist/server/src/parser/tokenizer.d.ts.map +1 -0
- package/dist/server/src/parser/tokenizer.js +94 -0
- package/dist/server/src/parser/tokenizer.js.map +1 -0
- package/dist/server/src/parser/transformer.d.ts +24 -0
- package/dist/server/src/parser/transformer.d.ts.map +1 -0
- package/dist/server/src/parser/transformer.js +61 -0
- package/dist/server/src/parser/transformer.js.map +1 -0
- package/dist/server/src/parser/types.d.ts +21 -0
- package/dist/server/src/parser/types.d.ts.map +1 -0
- package/dist/server/src/parser/types.js +11 -0
- package/dist/server/src/parser/types.js.map +1 -0
- package/dist/server/src/playground/assets.d.ts +16 -0
- package/dist/server/src/playground/assets.d.ts.map +1 -0
- package/dist/server/src/playground/assets.js +1113 -0
- package/dist/server/src/playground/assets.js.map +1 -0
- package/dist/server/src/playground/docs.d.ts +15 -0
- package/dist/server/src/playground/docs.d.ts.map +1 -0
- package/dist/server/src/playground/docs.js +223 -0
- package/dist/server/src/playground/docs.js.map +1 -0
- package/dist/server/src/playground/html.d.ts +20 -0
- package/dist/server/src/playground/html.d.ts.map +1 -0
- package/dist/server/src/playground/html.js +50 -0
- package/dist/server/src/playground/html.js.map +1 -0
- package/dist/server/src/plugins/index.d.ts +21 -0
- package/dist/server/src/plugins/index.d.ts.map +1 -0
- package/dist/server/src/plugins/index.js +38 -0
- package/dist/server/src/plugins/index.js.map +1 -0
- package/dist/server/src/relations.d.ts +22 -0
- package/dist/server/src/relations.d.ts.map +1 -0
- package/dist/server/src/relations.js +98 -0
- package/dist/server/src/relations.js.map +1 -0
- package/dist/server/src/resolver/generator.d.ts +25 -0
- package/dist/server/src/resolver/generator.d.ts.map +1 -0
- package/dist/server/src/resolver/generator.js +65 -0
- package/dist/server/src/resolver/generator.js.map +1 -0
- package/dist/server/src/resolver/mapper.d.ts +23 -0
- package/dist/server/src/resolver/mapper.d.ts.map +1 -0
- package/dist/server/src/resolver/mapper.js +96 -0
- package/dist/server/src/resolver/mapper.js.map +1 -0
- package/dist/server/src/schema/builder.d.ts +21 -0
- package/dist/server/src/schema/builder.d.ts.map +1 -0
- package/dist/server/src/schema/builder.js +23 -0
- package/dist/server/src/schema/builder.js.map +1 -0
- package/dist/server/src/schema/types.d.ts +81 -0
- package/dist/server/src/schema/types.d.ts.map +1 -0
- package/dist/server/src/schema/types.js +11 -0
- package/dist/server/src/schema/types.js.map +1 -0
- package/dist/server/src/schema/utils.d.ts +16 -0
- package/dist/server/src/schema/utils.d.ts.map +1 -0
- package/dist/server/src/schema/utils.js +42 -0
- package/dist/server/src/schema/utils.js.map +1 -0
- package/dist/server/src/security.d.ts +46 -0
- package/dist/server/src/security.d.ts.map +1 -0
- package/dist/server/src/security.js +189 -0
- package/dist/server/src/security.js.map +1 -0
- package/dist/server/src/types.d.ts +158 -0
- package/dist/server/src/types.d.ts.map +1 -0
- package/dist/server/src/types.js +11 -0
- package/dist/server/src/types.js.map +1 -0
- package/dist/server/src/validator.d.ts +30 -0
- package/dist/server/src/validator.d.ts.map +1 -0
- package/dist/server/src/validator.js +171 -0
- package/dist/server/src/validator.js.map +1 -0
- package/package.json +25 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../../src/playground/assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;EAC1B,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqjCP,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;CAkB5B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Documentation Generator
|
|
3
|
+
*
|
|
4
|
+
* Logic for generating real-time, interactive API documentation
|
|
5
|
+
* from the server's processed schema metadata.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Documentation Generator for QuickQL Playground
|
|
13
|
+
*/
|
|
14
|
+
export declare const docsJs = "\nfunction renderDocsPage() {\n const schema = (window).currentSchema || [];\n if (schema.length === 0) {\n return '<div class=\"p-5 text-center text-muted\"><div class=\"mb-3\" style=\"font-size: 48px; opacity: 0.15;\"><i class=\"fas fa-book-open\"></i></div><h4 class=\"fw-bold\">No Schema Loaded</h4><p class=\"text-muted\">Navigate to a collection or refresh to load schema metadata.</p></div>';\n }\n\n // --- Helper: infer type badge ---\n function getTypeInfo(fName) {\n if (fName === 'id' || fName.endsWith('_id')) return { label: 'ID', color: '#7c3aed', bg: '#ede9fe' };\n if (fName === 'email') return { label: 'Email', color: '#0891b2', bg: '#e0f2fe' };\n if (fName === 'created_at' || fName === 'updated_at' || fName.endsWith('_at')) return { label: 'DateTime', color: '#d97706', bg: '#fef3c7' };\n if (fName.startsWith('is_') || fName.startsWith('has_') || fName === 'active' || fName === 'enabled') return { label: 'Boolean', color: '#059669', bg: '#d1fae5' };\n if (fName.includes('count') || fName === 'age' || fName === 'total' || fName.includes('amount') || fName.includes('price')) return { label: 'Number', color: '#dc2626', bg: '#fee2e2' };\n if (fName === 'password' || fName === 'token' || fName === 'secret') return { label: 'Hash', color: '#64748b', bg: '#f1f5f9' };\n if (fName.includes('url') || fName.includes('image') || fName.includes('avatar') || fName.includes('link')) return { label: 'URL', color: '#6366f1', bg: '#eef2ff' };\n return { label: 'String', color: '#475569', bg: '#f8fafc' };\n }\n\n function getFieldDesc(fName, colName) {\n if (fName === 'id') return 'Primary key. Unique record identifier \u2014 used for targeted lookups and as a foreign key reference in relations.';\n if (fName.endsWith('_id')) return 'Foreign key reference to a related <strong>' + fName.replace('_id','') + '</strong> record.';\n if (fName === 'email') return 'Email address. Used for authentication and contact. Must be a valid RFC 5321 format.';\n if (fName.includes('name')) return 'Human-readable display name or label for the <strong>' + colName + '</strong> record.';\n if (fName === 'created_at') return 'Timestamp of when this record was first persisted. Set automatically by the system.';\n if (fName === 'updated_at') return 'Timestamp of the last modification. Automatically updated on every write operation.';\n if (fName === 'password') return 'Hashed credential string. Never returned in plain text \u2014 always stored using a one-way hash.';\n if (fName.startsWith('is_')) return 'Boolean flag. Indicates whether the <em>' + fName.replace('is_','') + '</em> condition is true for this record.';\n if (fName.startsWith('has_')) return 'Boolean flag. Indicates presence or availability of <em>' + fName.replace('has_','') + '</em>.';\n if (fName.includes('count')) return 'Aggregate counter. Denormalized value tracking the number of related sub-items.';\n if (fName.includes('url') || fName.includes('image') || fName.includes('avatar')) return 'URL pointing to an external or stored resource. Should be a fully qualified URI.';\n if (fName.includes('amount') || fName.includes('price') || fName.includes('total')) return 'Monetary or numeric value. Stored as a fixed-precision number to avoid floating-point errors.';\n return 'Data attribute on <strong>' + colName + '</strong>. Stores domain-specific information for this field.';\n }\n\n let html = '';\n html += '<div class=\"d-flex h-100 bg-white\" style=\"min-width: 0;\">';\n\n // --- Left nav sidebar ---\n html += '<aside class=\"flex-shrink-0 border-end d-flex flex-column\" style=\"width: 190px; overflow-y: auto; background: #fafafa;\">';\n html += ' <div class=\"px-4 pt-4 pb-3 border-bottom bg-white\">';\n html += ' <div class=\"text-uppercase fw-bold text-muted mb-1\" style=\"font-size: 10px; letter-spacing: 2px;\">Collections</div>';\n html += ' <div class=\"text-muted\" style=\"font-size: 11px;\">' + schema.length + ' collection' + (schema.length !== 1 ? 's' : '') + ' detected</div>';\n html += ' </div>';\n html += ' <div class=\"py-2\">';\n schema.forEach((col, idx) => {\n const colors = ['#3b82f6','#8b5cf6','#ec4899','#10b981','#f59e0b','#ef4444','#06b6d4'];\n const c = colors[idx % colors.length];\n html += '<a href=\"#doc-' + col.name + '\" class=\"d-flex align-items-center gap-3 px-4 py-2 text-decoration-none docs-nav-item\" style=\"color: #374151; font-size: 13px; font-weight: 600; transition: background 0.15s;\">';\n html += ' <span style=\"width: 8px; height: 8px; border-radius: 50%; background: ' + c + '; flex-shrink: 0; display: inline-block;\"></span>';\n html += ' <span>' + col.name + '</span>';\n html += ' <span class=\"ms-auto text-muted fw-normal\" style=\"font-size: 11px;\">' + col.fields.length + 'f</span>';\n html += '</a>';\n });\n html += ' </div>';\n html += '</aside>';\n\n // --- Main docs body ---\n html += '<main class=\"flex-grow-1 overflow-auto\" style=\"min-width: 0; background: #fff;\">';\n html += ' <div class=\"mx-auto\" style=\"max-width: 900px; padding: 28px 24px;\">';\n\n // Header\n html += ' <div class=\"mb-4 pb-3 border-bottom\">';\n html += ' <div class=\"d-flex align-items-start justify-content-between\">';\n html += ' <div>';\n html += ' <h1 class=\"fw-bold mb-1\" style=\"font-size: 22px; letter-spacing: -0.5px;\">API Reference</h1>';\n html += ' <p class=\"text-muted mb-0\" style=\"font-size: 13px;\">Auto-generated docs for your QuickQL schema. Uses the QuickQL native query language.</p>';\n html += ' </div>';\n html += ' <span class=\"badge px-3 py-2 ms-3 flex-shrink-0\" style=\"background: #d1fae5; color: #065f46; font-size: 10px; border-radius: 100px; font-weight: 700;\">\u25CF LIVE</span>';\n html += ' </div>';\n html += ' </div>';\n\n // Query Syntax intro box\n html += ' <div class=\"mb-4 p-3 rounded-2\" style=\"background: #f8fafc; border: 1px solid #e2e8f0;\">';\n html += ' <div class=\"d-flex align-items-center gap-2 mb-2\">';\n html += ' <i class=\"fas fa-terminal text-primary\" style=\"font-size: 11px;\"></i>';\n html += ' <span class=\"fw-bold text-dark\" style=\"font-size: 11px; text-transform: uppercase; letter-spacing: 1px;\">QuickQL Query Syntax</span>';\n html += ' </div>';\n html += ' <div style=\"display: flex; gap: 12px; flex-wrap: wrap;\">';\n html += ' <div class=\"mb-4\" style=\"flex: 1 1 100%; min-width: 0;\">';\n html += ' <pre class=\"rounded-2 p-3 mb-1 font-monospace\" style=\"background: #0f172a; color: #e2e8f0; font-size: 12px; line-height: 1.7; overflow-x: auto; white-space: pre; margin: 0;\">users {\\n id,\\n username,\\n email\\n}</pre>';\n html += ' <div class=\"text-muted mt-1\" style=\"font-size: 11px;\"><i class=\"fas fa-arrow-right me-1\"></i>Select fields by name, comma-separated</div>';\n html += ' </div>';\n html += ' <div style=\"flex: 1 1 100%; min-width: 0;\">';\n html += ' <pre class=\"rounded-2 p-3 mb-1 font-monospace\" style=\"background: #0f172a; color: #e2e8f0; font-size: 12px; line-height: 1.7; overflow-x: auto; white-space: pre; margin: 0;\">users {\\n id,\\n posts { id, title }\\n}</pre>';\n html += ' <div class=\"text-muted mt-1\" style=\"font-size: 11px;\"><i class=\"fas fa-arrow-right me-1\"></i>Nest relation names inline for joins</div>';\n html += ' </div>';\n html += ' </div>';\n html += ' </div>';\n\n // Per-collection docs\n schema.forEach((col, idx) => {\n const colors = ['#3b82f6','#8b5cf6','#ec4899','#10b981','#f59e0b','#ef4444','#06b6d4'];\n const accentColor = colors[idx % colors.length];\n\n html += '<section id=\"doc-' + col.name + '\" class=\"mb-5\" style=\"scroll-margin-top: 24px;\">';\n\n // Collection header\n html += ' <div class=\"d-flex align-items-center gap-3 mb-3\">';\n html += ' <div class=\"rounded-2 d-flex align-items-center justify-content-center flex-shrink-0\" style=\"width: 36px; height: 36px; background: ' + accentColor + '18;\">';\n html += ' <i class=\"fas fa-table\" style=\"color: ' + accentColor + '; font-size: 14px;\"></i>';\n html += ' </div>';\n html += ' <div>';\n html += ' <h2 class=\"fw-bold mb-0\" style=\"font-size: 22px; color: #0f172a;\">' + col.name + '</h2>';\n html += ' <div class=\"text-muted\" style=\"font-size: 12px;\">' + col.fields.length + ' fields' + (col.relations && col.relations.length > 0 ? ' \u00B7 ' + col.relations.length + ' relation' + (col.relations.length > 1 ? 's' : '') : '') + '</div>';\n html += ' </div>';\n html += ' <button class=\"btn btn-sm ms-auto fw-bold px-3\" style=\"border: 1.5px solid ' + accentColor + '; color: ' + accentColor + '; border-radius: 8px; font-size: 12px;\" onclick=\"(window).setEditorTemplate(\\'' + col.name + '\\'); (window).switchView(\\'playground\\')\">';\n html += ' <i class=\"fas fa-play me-1\" style=\"font-size: 10px;\"></i>Try in Playground';\n html += ' </button>';\n html += ' </div>';\n\n html += ' <p class=\"text-muted mb-4\" style=\"font-size: 14px; line-height: 1.7;\">The <strong class=\"text-dark\">' + col.name + '</strong> collection stores records in your QuickQL data layer. Query it directly by name, select specific fields using comma-separated lists, and traverse relations by nesting collection names inline.</p>';\n\n // Fields table\n html += ' <div class=\"mb-4 rounded-2 overflow-hidden\" style=\"border: 1px solid #e2e8f0;\">';\n html += ' <div class=\"px-4 py-3 d-flex align-items-center gap-2\" style=\"background: #f8fafc; border-bottom: 1px solid #e2e8f0;\">';\n html += ' <i class=\"fas fa-list-ul text-muted\" style=\"font-size: 12px;\"></i>';\n html += ' <span class=\"fw-bold text-muted text-uppercase\" style=\"font-size: 11px; letter-spacing: 1px;\">Fields</span>';\n html += ' </div>';\n html += ' <table class=\"w-100 m-0\" style=\"border-collapse: collapse; font-size: 13px;\">';\n html += ' <thead>';\n html += ' <tr style=\"background: #fafafa; border-bottom: 1px solid #f1f5f9;\">';\n html += ' <th class=\"px-4 py-3 text-muted fw-bold text-uppercase\" style=\"font-size: 10px; letter-spacing: 1px; width: 30%;\">Field</th>';\n html += ' <th class=\"px-4 py-3 text-muted fw-bold text-uppercase\" style=\"font-size: 10px; letter-spacing: 1px;\">Description</th>';\n html += ' <th class=\"px-4 py-3 text-muted fw-bold text-uppercase\" style=\"font-size: 10px; letter-spacing: 1px; width: 100px; text-align: right;\">Type</th>';\n html += ' </tr>';\n html += ' </thead>';\n html += ' <tbody>';\n col.fields.forEach((f, fi) => {\n const fName = f.toLowerCase();\n const typeInfo = getTypeInfo(fName);\n const desc = getFieldDesc(fName, col.name);\n html += '<tr style=\"border-bottom: 1px solid #f8fafc; ' + (fi % 2 === 0 ? 'background: #fff;' : 'background: #fafafa;') + '\">';\n html += ' <td class=\"px-4 py-3\"><code style=\"font-size: 13px; font-weight: 700; color: ' + accentColor + '; background: ' + accentColor + '10; padding: 2px 8px; border-radius: 4px; font-family: JetBrains Mono, monospace;\">' + f + '</code></td>';\n html += ' <td class=\"px-4 py-3 text-muted\" style=\"line-height: 1.6;\">' + desc + '</td>';\n html += ' <td class=\"px-4 py-3\" style=\"text-align: right;\"><span class=\"fw-bold\" style=\"font-size: 11px; padding: 3px 10px; border-radius: 100px; background: ' + typeInfo.bg + '; color: ' + typeInfo.color + ';\">' + typeInfo.label + '</span></td>';\n html += '</tr>';\n });\n html += ' </tbody>';\n html += ' </table>';\n html += ' </div>';\n\n // Relations block\n if (col.relations && col.relations.length > 0) {\n html += ' <div class=\"mb-4 rounded-2 overflow-hidden\" style=\"border: 1px solid #e2e8f0;\">';\n html += ' <div class=\"px-4 py-3 d-flex align-items-center gap-2\" style=\"background: #f8fafc; border-bottom: 1px solid #e2e8f0;\">';\n html += ' <i class=\"fas fa-code-branch text-muted\" style=\"font-size: 12px;\"></i>';\n html += ' <span class=\"fw-bold text-muted text-uppercase\" style=\"font-size: 11px; letter-spacing: 1px;\">Relations</span>';\n html += ' </div>';\n col.relations.forEach(rel => {\n html += '<div class=\"px-4 py-3 d-flex align-items-center justify-content-between\" style=\"border-bottom: 1px solid #f8fafc;\">';\n html += ' <div class=\"d-flex align-items-center gap-3\">';\n html += ' <div class=\"d-flex align-items-center justify-content-center rounded-2\" style=\"width: 28px; height: 28px; background: #eff6ff;\">';\n html += ' <i class=\"fas fa-arrow-right text-primary\" style=\"font-size: 10px;\"></i>';\n html += ' </div>';\n html += ' <div>';\n html += ' <div class=\"fw-bold text-dark\" style=\"font-size: 13px;\">' + rel.name + '</div>';\n html += ' <div class=\"text-muted\" style=\"font-size: 11px;\">Points to \u2192 <strong>' + rel.target + '</strong> collection</div>';\n html += ' </div>';\n html += ' </div>';\n html += ' <button class=\"btn btn-sm text-primary fw-bold p-0 text-decoration-none\" style=\"font-size: 12px;\" onclick=\"document.getElementById(\\'doc-' + rel.target + '\\')?.scrollIntoView({behavior:\\'smooth\\'})\">View ' + rel.target + ' \u2192</button>';\n html += '</div>';\n });\n html += ' </div>';\n }\n\n // Sample query\n html += ' <div class=\"mb-2\">';\n html += ' <div class=\"fw-bold text-muted text-uppercase mb-2\" style=\"font-size: 11px; letter-spacing: 1px;\"><i class=\"fas fa-code me-1\"></i> Sample Query</div>';\n html += ' <div class=\"rounded-2 overflow-hidden\" style=\"border: 1px solid #1e293b;\">';\n html += ' <div class=\"px-4 py-2 d-flex align-items-center justify-content-between\" style=\"background: #1e293b;\">';\n html += ' <span class=\"text-muted\" style=\"font-size: 11px; font-family: monospace;\">quickql \u00B7 ' + col.name.toLowerCase() + '</span>';\n html += ' <button class=\"btn btn-sm p-0 fw-bold\" style=\"font-size: 11px; color: #94a3b8;\" onclick=\"(window).setEditorTemplate(\\'' + col.name + '\\'); (window).switchView(\\'playground\\')\">Copy to Editor \u2197</button>';\n html += ' </div>';\n html += ' <pre class=\"m-0 p-4 font-monospace\" style=\"background: #0f172a; color: #e2e8f0; font-size: 13px; line-height: 1.7;\">';\n const sampleFields = col.fields.slice(0, Math.min(col.fields.length, 4)).join(',\\n ');\n html += col.name.toLowerCase() + ' {\\n ' + sampleFields + '\\n}';\n if (col.relations && col.relations.length > 0) {\n html += '\\n\\n' + col.name.toLowerCase() + ' {\\n id,\\n ' + col.relations[0].name + ' {\\n id\\n }\\n}';\n }\n html += '</pre>';\n html += ' </div>';\n html += ' </div>';\n\n html += ' <div style=\"margin: 40px 0; border-top: 1px solid #f1f5f9;\"></div>';\n html += '</section>';\n });\n\n // Footer\n html += ' <div class=\"text-center py-5\" style=\"opacity: 0.2;\">';\n html += ' <img src=\"https://cdn-static.udinmo.com/content/logo/quickql.png\" style=\"height: 20px; filter: grayscale(1);\">';\n html += ' <div class=\"mt-2 fw-bold text-uppercase\" style=\"font-size: 10px; letter-spacing: 3px;\">End of Reference</div>';\n html += ' </div>';\n\n html += ' </div>';\n html += '</main>';\n html += '</div>';\n\n // Hover styles for sidebar nav items\n setTimeout(() => {\n document.querySelectorAll('.docs-nav-item').forEach(el => {\n el.addEventListener('mouseenter', () => { el.style.background = '#f1f5f9'; });\n el.addEventListener('mouseleave', () => { el.style.background = ''; });\n });\n }, 50);\n\n return html;\n}\n";
|
|
15
|
+
//# sourceMappingURL=docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../../src/playground/docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,eAAO,MAAM,MAAM,62gBAgNlB,CAAC"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Documentation Generator
|
|
3
|
+
*
|
|
4
|
+
* Logic for generating real-time, interactive API documentation
|
|
5
|
+
* from the server's processed schema metadata.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Documentation Generator for QuickQL Playground
|
|
13
|
+
*/
|
|
14
|
+
export const docsJs = `
|
|
15
|
+
function renderDocsPage() {
|
|
16
|
+
const schema = (window).currentSchema || [];
|
|
17
|
+
if (schema.length === 0) {
|
|
18
|
+
return '<div class="p-5 text-center text-muted"><div class="mb-3" style="font-size: 48px; opacity: 0.15;"><i class="fas fa-book-open"></i></div><h4 class="fw-bold">No Schema Loaded</h4><p class="text-muted">Navigate to a collection or refresh to load schema metadata.</p></div>';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// --- Helper: infer type badge ---
|
|
22
|
+
function getTypeInfo(fName) {
|
|
23
|
+
if (fName === 'id' || fName.endsWith('_id')) return { label: 'ID', color: '#7c3aed', bg: '#ede9fe' };
|
|
24
|
+
if (fName === 'email') return { label: 'Email', color: '#0891b2', bg: '#e0f2fe' };
|
|
25
|
+
if (fName === 'created_at' || fName === 'updated_at' || fName.endsWith('_at')) return { label: 'DateTime', color: '#d97706', bg: '#fef3c7' };
|
|
26
|
+
if (fName.startsWith('is_') || fName.startsWith('has_') || fName === 'active' || fName === 'enabled') return { label: 'Boolean', color: '#059669', bg: '#d1fae5' };
|
|
27
|
+
if (fName.includes('count') || fName === 'age' || fName === 'total' || fName.includes('amount') || fName.includes('price')) return { label: 'Number', color: '#dc2626', bg: '#fee2e2' };
|
|
28
|
+
if (fName === 'password' || fName === 'token' || fName === 'secret') return { label: 'Hash', color: '#64748b', bg: '#f1f5f9' };
|
|
29
|
+
if (fName.includes('url') || fName.includes('image') || fName.includes('avatar') || fName.includes('link')) return { label: 'URL', color: '#6366f1', bg: '#eef2ff' };
|
|
30
|
+
return { label: 'String', color: '#475569', bg: '#f8fafc' };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getFieldDesc(fName, colName) {
|
|
34
|
+
if (fName === 'id') return 'Primary key. Unique record identifier — used for targeted lookups and as a foreign key reference in relations.';
|
|
35
|
+
if (fName.endsWith('_id')) return 'Foreign key reference to a related <strong>' + fName.replace('_id','') + '</strong> record.';
|
|
36
|
+
if (fName === 'email') return 'Email address. Used for authentication and contact. Must be a valid RFC 5321 format.';
|
|
37
|
+
if (fName.includes('name')) return 'Human-readable display name or label for the <strong>' + colName + '</strong> record.';
|
|
38
|
+
if (fName === 'created_at') return 'Timestamp of when this record was first persisted. Set automatically by the system.';
|
|
39
|
+
if (fName === 'updated_at') return 'Timestamp of the last modification. Automatically updated on every write operation.';
|
|
40
|
+
if (fName === 'password') return 'Hashed credential string. Never returned in plain text — always stored using a one-way hash.';
|
|
41
|
+
if (fName.startsWith('is_')) return 'Boolean flag. Indicates whether the <em>' + fName.replace('is_','') + '</em> condition is true for this record.';
|
|
42
|
+
if (fName.startsWith('has_')) return 'Boolean flag. Indicates presence or availability of <em>' + fName.replace('has_','') + '</em>.';
|
|
43
|
+
if (fName.includes('count')) return 'Aggregate counter. Denormalized value tracking the number of related sub-items.';
|
|
44
|
+
if (fName.includes('url') || fName.includes('image') || fName.includes('avatar')) return 'URL pointing to an external or stored resource. Should be a fully qualified URI.';
|
|
45
|
+
if (fName.includes('amount') || fName.includes('price') || fName.includes('total')) return 'Monetary or numeric value. Stored as a fixed-precision number to avoid floating-point errors.';
|
|
46
|
+
return 'Data attribute on <strong>' + colName + '</strong>. Stores domain-specific information for this field.';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let html = '';
|
|
50
|
+
html += '<div class="d-flex h-100 bg-white" style="min-width: 0;">';
|
|
51
|
+
|
|
52
|
+
// --- Left nav sidebar ---
|
|
53
|
+
html += '<aside class="flex-shrink-0 border-end d-flex flex-column" style="width: 190px; overflow-y: auto; background: #fafafa;">';
|
|
54
|
+
html += ' <div class="px-4 pt-4 pb-3 border-bottom bg-white">';
|
|
55
|
+
html += ' <div class="text-uppercase fw-bold text-muted mb-1" style="font-size: 10px; letter-spacing: 2px;">Collections</div>';
|
|
56
|
+
html += ' <div class="text-muted" style="font-size: 11px;">' + schema.length + ' collection' + (schema.length !== 1 ? 's' : '') + ' detected</div>';
|
|
57
|
+
html += ' </div>';
|
|
58
|
+
html += ' <div class="py-2">';
|
|
59
|
+
schema.forEach((col, idx) => {
|
|
60
|
+
const colors = ['#3b82f6','#8b5cf6','#ec4899','#10b981','#f59e0b','#ef4444','#06b6d4'];
|
|
61
|
+
const c = colors[idx % colors.length];
|
|
62
|
+
html += '<a href="#doc-' + col.name + '" class="d-flex align-items-center gap-3 px-4 py-2 text-decoration-none docs-nav-item" style="color: #374151; font-size: 13px; font-weight: 600; transition: background 0.15s;">';
|
|
63
|
+
html += ' <span style="width: 8px; height: 8px; border-radius: 50%; background: ' + c + '; flex-shrink: 0; display: inline-block;"></span>';
|
|
64
|
+
html += ' <span>' + col.name + '</span>';
|
|
65
|
+
html += ' <span class="ms-auto text-muted fw-normal" style="font-size: 11px;">' + col.fields.length + 'f</span>';
|
|
66
|
+
html += '</a>';
|
|
67
|
+
});
|
|
68
|
+
html += ' </div>';
|
|
69
|
+
html += '</aside>';
|
|
70
|
+
|
|
71
|
+
// --- Main docs body ---
|
|
72
|
+
html += '<main class="flex-grow-1 overflow-auto" style="min-width: 0; background: #fff;">';
|
|
73
|
+
html += ' <div class="mx-auto" style="max-width: 900px; padding: 28px 24px;">';
|
|
74
|
+
|
|
75
|
+
// Header
|
|
76
|
+
html += ' <div class="mb-4 pb-3 border-bottom">';
|
|
77
|
+
html += ' <div class="d-flex align-items-start justify-content-between">';
|
|
78
|
+
html += ' <div>';
|
|
79
|
+
html += ' <h1 class="fw-bold mb-1" style="font-size: 22px; letter-spacing: -0.5px;">API Reference</h1>';
|
|
80
|
+
html += ' <p class="text-muted mb-0" style="font-size: 13px;">Auto-generated docs for your QuickQL schema. Uses the QuickQL native query language.</p>';
|
|
81
|
+
html += ' </div>';
|
|
82
|
+
html += ' <span class="badge px-3 py-2 ms-3 flex-shrink-0" style="background: #d1fae5; color: #065f46; font-size: 10px; border-radius: 100px; font-weight: 700;">● LIVE</span>';
|
|
83
|
+
html += ' </div>';
|
|
84
|
+
html += ' </div>';
|
|
85
|
+
|
|
86
|
+
// Query Syntax intro box
|
|
87
|
+
html += ' <div class="mb-4 p-3 rounded-2" style="background: #f8fafc; border: 1px solid #e2e8f0;">';
|
|
88
|
+
html += ' <div class="d-flex align-items-center gap-2 mb-2">';
|
|
89
|
+
html += ' <i class="fas fa-terminal text-primary" style="font-size: 11px;"></i>';
|
|
90
|
+
html += ' <span class="fw-bold text-dark" style="font-size: 11px; text-transform: uppercase; letter-spacing: 1px;">QuickQL Query Syntax</span>';
|
|
91
|
+
html += ' </div>';
|
|
92
|
+
html += ' <div style="display: flex; gap: 12px; flex-wrap: wrap;">';
|
|
93
|
+
html += ' <div class="mb-4" style="flex: 1 1 100%; min-width: 0;">';
|
|
94
|
+
html += ' <pre class="rounded-2 p-3 mb-1 font-monospace" style="background: #0f172a; color: #e2e8f0; font-size: 12px; line-height: 1.7; overflow-x: auto; white-space: pre; margin: 0;">users {\\n id,\\n username,\\n email\\n}</pre>';
|
|
95
|
+
html += ' <div class="text-muted mt-1" style="font-size: 11px;"><i class="fas fa-arrow-right me-1"></i>Select fields by name, comma-separated</div>';
|
|
96
|
+
html += ' </div>';
|
|
97
|
+
html += ' <div style="flex: 1 1 100%; min-width: 0;">';
|
|
98
|
+
html += ' <pre class="rounded-2 p-3 mb-1 font-monospace" style="background: #0f172a; color: #e2e8f0; font-size: 12px; line-height: 1.7; overflow-x: auto; white-space: pre; margin: 0;">users {\\n id,\\n posts { id, title }\\n}</pre>';
|
|
99
|
+
html += ' <div class="text-muted mt-1" style="font-size: 11px;"><i class="fas fa-arrow-right me-1"></i>Nest relation names inline for joins</div>';
|
|
100
|
+
html += ' </div>';
|
|
101
|
+
html += ' </div>';
|
|
102
|
+
html += ' </div>';
|
|
103
|
+
|
|
104
|
+
// Per-collection docs
|
|
105
|
+
schema.forEach((col, idx) => {
|
|
106
|
+
const colors = ['#3b82f6','#8b5cf6','#ec4899','#10b981','#f59e0b','#ef4444','#06b6d4'];
|
|
107
|
+
const accentColor = colors[idx % colors.length];
|
|
108
|
+
|
|
109
|
+
html += '<section id="doc-' + col.name + '" class="mb-5" style="scroll-margin-top: 24px;">';
|
|
110
|
+
|
|
111
|
+
// Collection header
|
|
112
|
+
html += ' <div class="d-flex align-items-center gap-3 mb-3">';
|
|
113
|
+
html += ' <div class="rounded-2 d-flex align-items-center justify-content-center flex-shrink-0" style="width: 36px; height: 36px; background: ' + accentColor + '18;">';
|
|
114
|
+
html += ' <i class="fas fa-table" style="color: ' + accentColor + '; font-size: 14px;"></i>';
|
|
115
|
+
html += ' </div>';
|
|
116
|
+
html += ' <div>';
|
|
117
|
+
html += ' <h2 class="fw-bold mb-0" style="font-size: 22px; color: #0f172a;">' + col.name + '</h2>';
|
|
118
|
+
html += ' <div class="text-muted" style="font-size: 12px;">' + col.fields.length + ' fields' + (col.relations && col.relations.length > 0 ? ' · ' + col.relations.length + ' relation' + (col.relations.length > 1 ? 's' : '') : '') + '</div>';
|
|
119
|
+
html += ' </div>';
|
|
120
|
+
html += ' <button class="btn btn-sm ms-auto fw-bold px-3" style="border: 1.5px solid ' + accentColor + '; color: ' + accentColor + '; border-radius: 8px; font-size: 12px;" onclick="(window).setEditorTemplate(\\'' + col.name + '\\'); (window).switchView(\\'playground\\')">';
|
|
121
|
+
html += ' <i class="fas fa-play me-1" style="font-size: 10px;"></i>Try in Playground';
|
|
122
|
+
html += ' </button>';
|
|
123
|
+
html += ' </div>';
|
|
124
|
+
|
|
125
|
+
html += ' <p class="text-muted mb-4" style="font-size: 14px; line-height: 1.7;">The <strong class="text-dark">' + col.name + '</strong> collection stores records in your QuickQL data layer. Query it directly by name, select specific fields using comma-separated lists, and traverse relations by nesting collection names inline.</p>';
|
|
126
|
+
|
|
127
|
+
// Fields table
|
|
128
|
+
html += ' <div class="mb-4 rounded-2 overflow-hidden" style="border: 1px solid #e2e8f0;">';
|
|
129
|
+
html += ' <div class="px-4 py-3 d-flex align-items-center gap-2" style="background: #f8fafc; border-bottom: 1px solid #e2e8f0;">';
|
|
130
|
+
html += ' <i class="fas fa-list-ul text-muted" style="font-size: 12px;"></i>';
|
|
131
|
+
html += ' <span class="fw-bold text-muted text-uppercase" style="font-size: 11px; letter-spacing: 1px;">Fields</span>';
|
|
132
|
+
html += ' </div>';
|
|
133
|
+
html += ' <table class="w-100 m-0" style="border-collapse: collapse; font-size: 13px;">';
|
|
134
|
+
html += ' <thead>';
|
|
135
|
+
html += ' <tr style="background: #fafafa; border-bottom: 1px solid #f1f5f9;">';
|
|
136
|
+
html += ' <th class="px-4 py-3 text-muted fw-bold text-uppercase" style="font-size: 10px; letter-spacing: 1px; width: 30%;">Field</th>';
|
|
137
|
+
html += ' <th class="px-4 py-3 text-muted fw-bold text-uppercase" style="font-size: 10px; letter-spacing: 1px;">Description</th>';
|
|
138
|
+
html += ' <th class="px-4 py-3 text-muted fw-bold text-uppercase" style="font-size: 10px; letter-spacing: 1px; width: 100px; text-align: right;">Type</th>';
|
|
139
|
+
html += ' </tr>';
|
|
140
|
+
html += ' </thead>';
|
|
141
|
+
html += ' <tbody>';
|
|
142
|
+
col.fields.forEach((f, fi) => {
|
|
143
|
+
const fName = f.toLowerCase();
|
|
144
|
+
const typeInfo = getTypeInfo(fName);
|
|
145
|
+
const desc = getFieldDesc(fName, col.name);
|
|
146
|
+
html += '<tr style="border-bottom: 1px solid #f8fafc; ' + (fi % 2 === 0 ? 'background: #fff;' : 'background: #fafafa;') + '">';
|
|
147
|
+
html += ' <td class="px-4 py-3"><code style="font-size: 13px; font-weight: 700; color: ' + accentColor + '; background: ' + accentColor + '10; padding: 2px 8px; border-radius: 4px; font-family: JetBrains Mono, monospace;">' + f + '</code></td>';
|
|
148
|
+
html += ' <td class="px-4 py-3 text-muted" style="line-height: 1.6;">' + desc + '</td>';
|
|
149
|
+
html += ' <td class="px-4 py-3" style="text-align: right;"><span class="fw-bold" style="font-size: 11px; padding: 3px 10px; border-radius: 100px; background: ' + typeInfo.bg + '; color: ' + typeInfo.color + ';">' + typeInfo.label + '</span></td>';
|
|
150
|
+
html += '</tr>';
|
|
151
|
+
});
|
|
152
|
+
html += ' </tbody>';
|
|
153
|
+
html += ' </table>';
|
|
154
|
+
html += ' </div>';
|
|
155
|
+
|
|
156
|
+
// Relations block
|
|
157
|
+
if (col.relations && col.relations.length > 0) {
|
|
158
|
+
html += ' <div class="mb-4 rounded-2 overflow-hidden" style="border: 1px solid #e2e8f0;">';
|
|
159
|
+
html += ' <div class="px-4 py-3 d-flex align-items-center gap-2" style="background: #f8fafc; border-bottom: 1px solid #e2e8f0;">';
|
|
160
|
+
html += ' <i class="fas fa-code-branch text-muted" style="font-size: 12px;"></i>';
|
|
161
|
+
html += ' <span class="fw-bold text-muted text-uppercase" style="font-size: 11px; letter-spacing: 1px;">Relations</span>';
|
|
162
|
+
html += ' </div>';
|
|
163
|
+
col.relations.forEach(rel => {
|
|
164
|
+
html += '<div class="px-4 py-3 d-flex align-items-center justify-content-between" style="border-bottom: 1px solid #f8fafc;">';
|
|
165
|
+
html += ' <div class="d-flex align-items-center gap-3">';
|
|
166
|
+
html += ' <div class="d-flex align-items-center justify-content-center rounded-2" style="width: 28px; height: 28px; background: #eff6ff;">';
|
|
167
|
+
html += ' <i class="fas fa-arrow-right text-primary" style="font-size: 10px;"></i>';
|
|
168
|
+
html += ' </div>';
|
|
169
|
+
html += ' <div>';
|
|
170
|
+
html += ' <div class="fw-bold text-dark" style="font-size: 13px;">' + rel.name + '</div>';
|
|
171
|
+
html += ' <div class="text-muted" style="font-size: 11px;">Points to → <strong>' + rel.target + '</strong> collection</div>';
|
|
172
|
+
html += ' </div>';
|
|
173
|
+
html += ' </div>';
|
|
174
|
+
html += ' <button class="btn btn-sm text-primary fw-bold p-0 text-decoration-none" style="font-size: 12px;" onclick="document.getElementById(\\'doc-' + rel.target + '\\')?.scrollIntoView({behavior:\\'smooth\\'})">View ' + rel.target + ' →</button>';
|
|
175
|
+
html += '</div>';
|
|
176
|
+
});
|
|
177
|
+
html += ' </div>';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Sample query
|
|
181
|
+
html += ' <div class="mb-2">';
|
|
182
|
+
html += ' <div class="fw-bold text-muted text-uppercase mb-2" style="font-size: 11px; letter-spacing: 1px;"><i class="fas fa-code me-1"></i> Sample Query</div>';
|
|
183
|
+
html += ' <div class="rounded-2 overflow-hidden" style="border: 1px solid #1e293b;">';
|
|
184
|
+
html += ' <div class="px-4 py-2 d-flex align-items-center justify-content-between" style="background: #1e293b;">';
|
|
185
|
+
html += ' <span class="text-muted" style="font-size: 11px; font-family: monospace;">quickql · ' + col.name.toLowerCase() + '</span>';
|
|
186
|
+
html += ' <button class="btn btn-sm p-0 fw-bold" style="font-size: 11px; color: #94a3b8;" onclick="(window).setEditorTemplate(\\'' + col.name + '\\'); (window).switchView(\\'playground\\')">Copy to Editor ↗</button>';
|
|
187
|
+
html += ' </div>';
|
|
188
|
+
html += ' <pre class="m-0 p-4 font-monospace" style="background: #0f172a; color: #e2e8f0; font-size: 13px; line-height: 1.7;">';
|
|
189
|
+
const sampleFields = col.fields.slice(0, Math.min(col.fields.length, 4)).join(',\\n ');
|
|
190
|
+
html += col.name.toLowerCase() + ' {\\n ' + sampleFields + '\\n}';
|
|
191
|
+
if (col.relations && col.relations.length > 0) {
|
|
192
|
+
html += '\\n\\n' + col.name.toLowerCase() + ' {\\n id,\\n ' + col.relations[0].name + ' {\\n id\\n }\\n}';
|
|
193
|
+
}
|
|
194
|
+
html += '</pre>';
|
|
195
|
+
html += ' </div>';
|
|
196
|
+
html += ' </div>';
|
|
197
|
+
|
|
198
|
+
html += ' <div style="margin: 40px 0; border-top: 1px solid #f1f5f9;"></div>';
|
|
199
|
+
html += '</section>';
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Footer
|
|
203
|
+
html += ' <div class="text-center py-5" style="opacity: 0.2;">';
|
|
204
|
+
html += ' <img src="https://cdn-static.udinmo.com/content/logo/quickql.png" style="height: 20px; filter: grayscale(1);">';
|
|
205
|
+
html += ' <div class="mt-2 fw-bold text-uppercase" style="font-size: 10px; letter-spacing: 3px;">End of Reference</div>';
|
|
206
|
+
html += ' </div>';
|
|
207
|
+
|
|
208
|
+
html += ' </div>';
|
|
209
|
+
html += '</main>';
|
|
210
|
+
html += '</div>';
|
|
211
|
+
|
|
212
|
+
// Hover styles for sidebar nav items
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
document.querySelectorAll('.docs-nav-item').forEach(el => {
|
|
215
|
+
el.addEventListener('mouseenter', () => { el.style.background = '#f1f5f9'; });
|
|
216
|
+
el.addEventListener('mouseleave', () => { el.style.background = ''; });
|
|
217
|
+
});
|
|
218
|
+
}, 50);
|
|
219
|
+
|
|
220
|
+
return html;
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
//# sourceMappingURL=docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../../src/playground/docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgNrB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Playground HTML
|
|
3
|
+
*
|
|
4
|
+
* Provides the main HTML shell for the QuickQL Console/Playground,
|
|
5
|
+
* integrating CDN-based assets for maximum performance and light bundle size.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
export interface PlaygroundOptions {
|
|
12
|
+
endpoint: string;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Renders the HTML shell for the QuickQL Playground.
|
|
17
|
+
* Loads core assets (JS/CSS) from the official CDN to keep the server package lightweight.
|
|
18
|
+
*/
|
|
19
|
+
export declare function renderPlayground(options: PlaygroundOptions): string;
|
|
20
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/playground/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAmCnE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Playground HTML
|
|
3
|
+
*
|
|
4
|
+
* Provides the main HTML shell for the QuickQL Console/Playground,
|
|
5
|
+
* integrating CDN-based assets for maximum performance and light bundle size.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Renders the HTML shell for the QuickQL Playground.
|
|
13
|
+
* Loads core assets (JS/CSS) from the official CDN to keep the server package lightweight.
|
|
14
|
+
*/
|
|
15
|
+
export function renderPlayground(options) {
|
|
16
|
+
const cdnBase = 'https://cdn-static.udinmo.com/qucikql';
|
|
17
|
+
return `
|
|
18
|
+
<!DOCTYPE html>
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="UTF-8">
|
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
23
|
+
<title>QuickQL Console</title>
|
|
24
|
+
<!-- External & CDN Assets -->
|
|
25
|
+
<link rel="stylesheet" href="https://cdn-static.udinmo.com/@static/css/bootstrap.min.css" crossorigin="anonymous">
|
|
26
|
+
<link rel="stylesheet" href="https://cdn-static.udinmo.com/@static/css/awesome/css/all.min.css" crossorigin="anonymous">
|
|
27
|
+
<link rel="stylesheet" href="${cdnBase}/playground.css" crossorigin="anonymous">
|
|
28
|
+
<script src="https://cdn-static.udinmo.com/@static/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<div id="app">
|
|
32
|
+
<!-- Initial Loader -->
|
|
33
|
+
<div style="height: 100vh; width: 100vw; display: flex; align-items: center; justify-content: center; background: #0d1117">
|
|
34
|
+
<div style="border: 4px solid rgba(255, 255, 255, 0.1); border-top: 4px solid #3b82f6; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite"></div>
|
|
35
|
+
</div>
|
|
36
|
+
<style>@keyframes spin { 0% { transform: rotate(0deg) } 100% { transform: rotate(360deg) } }</style>
|
|
37
|
+
</div>
|
|
38
|
+
<script>
|
|
39
|
+
window.QuickQLConfig = {
|
|
40
|
+
endpoint: '${options.endpoint}',
|
|
41
|
+
debug: ${options.debug || false}
|
|
42
|
+
};
|
|
43
|
+
</script>
|
|
44
|
+
<!-- CDN Logic -->
|
|
45
|
+
<script src="${cdnBase}/playground.js" crossorigin="anonymous"></script>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|
|
48
|
+
`.trim();
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../src/playground/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,MAAM,OAAO,GAAG,uCAAuC,CAAC;IAExD,OAAO;;;;;;;;;;mCAU0B,OAAO;;;;;;;;;;;;;yBAajB,OAAO,CAAC,QAAQ;qBACpB,OAAO,CAAC,KAAK,IAAI,KAAK;;;;mBAIxB,OAAO;;;GAGvB,CAAC,IAAI,EAAE,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Standard Plugins
|
|
3
|
+
*
|
|
4
|
+
* Collection of built-in hooks for audit logging, result minification,
|
|
5
|
+
* and other common server-side middleware.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
import { QuickQLPlugin } from '../types';
|
|
12
|
+
/**
|
|
13
|
+
* Standard Audit Logging Plugin for Security and Compliance.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AuditLogPlugin: QuickQLPlugin;
|
|
16
|
+
/**
|
|
17
|
+
* Intelligent Response Minification Plugin.
|
|
18
|
+
* Automatically strips nulls or internal keys to reduce bandwidth.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MinifyResponsePlugin: QuickQLPlugin;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,aAAa,EAAwB,MAAM,UAAU,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,aAK5B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAalC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Standard Plugins
|
|
3
|
+
*
|
|
4
|
+
* Collection of built-in hooks for audit logging, result minification,
|
|
5
|
+
* and other common server-side middleware.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Standard Audit Logging Plugin for Security and Compliance.
|
|
13
|
+
*/
|
|
14
|
+
export const AuditLogPlugin = {
|
|
15
|
+
name: 'audit-log',
|
|
16
|
+
onMutation: async (mutation, ctx) => {
|
|
17
|
+
console.log(`[AUDIT] Mutation: ${mutation.type} in ${mutation.collection} by ${ctx.user?.id || 'anonymous'}`);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Intelligent Response Minification Plugin.
|
|
22
|
+
* Automatically strips nulls or internal keys to reduce bandwidth.
|
|
23
|
+
*/
|
|
24
|
+
export const MinifyResponsePlugin = {
|
|
25
|
+
name: 'minify-response',
|
|
26
|
+
afterQuery: async (results) => {
|
|
27
|
+
return results.map(row => {
|
|
28
|
+
const cleaned = {};
|
|
29
|
+
for (const [k, v] of Object.entries(row)) {
|
|
30
|
+
if (v !== null && v !== undefined && k !== '_internal') {
|
|
31
|
+
cleaned[k] = v;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return cleaned;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,IAAI,EAAE,WAAW;IACjB,UAAU,EAAE,KAAK,EAAE,QAAkB,EAAE,GAAyB,EAAE,EAAE;QAClE,OAAO,CAAC,GAAG,CAAC,qBAAqB,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,UAAU,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,WAAW,EAAE,CAAC,CAAC;IAChH,CAAC;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAkB;IACjD,IAAI,EAAE,iBAAiB;IACvB,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACrB,MAAM,OAAO,GAAQ,EAAE,CAAC;YACxB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;oBACrD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC;YACL,CAAC;YACD,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Relation Engine
|
|
3
|
+
*
|
|
4
|
+
* Optimized engine for resolving and mapping nested data relations
|
|
5
|
+
* while maintaining high performance and preventing N+1 problems.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
import { Query } from '@quickql/core';
|
|
12
|
+
import { SchemaConfig, ServerFeatures } from './types';
|
|
13
|
+
export declare class RelationEngine {
|
|
14
|
+
private schema;
|
|
15
|
+
private executeQueryRef;
|
|
16
|
+
private features;
|
|
17
|
+
constructor(schema: SchemaConfig, executeQueryRef: (query: Query, depth: number) => Promise<any[]>, features?: ServerFeatures);
|
|
18
|
+
resolve(items: any[], include: {
|
|
19
|
+
[key: string]: Partial<Query>;
|
|
20
|
+
}, relations: any, depth: number): Promise<any[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=relations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../../src/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,cAAc;IAEvB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,QAAQ;gBAFR,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,EAChE,QAAQ,GAAE,cAAiD;IAG/D,OAAO,CACX,KAAK,EAAE,GAAG,EAAE,EACZ,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;KAAE,EAC1C,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,GAAG,EAAE,CAAC;CAwFlB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Relation Engine
|
|
3
|
+
*
|
|
4
|
+
* Optimized engine for resolving and mapping nested data relations
|
|
5
|
+
* while maintaining high performance and preventing N+1 problems.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
export class RelationEngine {
|
|
12
|
+
schema;
|
|
13
|
+
executeQueryRef;
|
|
14
|
+
features;
|
|
15
|
+
constructor(schema, executeQueryRef, features = { smartRelationDiscovery: true }) {
|
|
16
|
+
this.schema = schema;
|
|
17
|
+
this.executeQueryRef = executeQueryRef;
|
|
18
|
+
this.features = features;
|
|
19
|
+
}
|
|
20
|
+
async resolve(items, include, relations, depth) {
|
|
21
|
+
const newItems = [...items];
|
|
22
|
+
for (const [relationKey, relationQuery] of Object.entries(include)) {
|
|
23
|
+
let relationDef = relations[relationKey];
|
|
24
|
+
// Smart Discovery: If relation is missing, try to infer it from field naming conventions
|
|
25
|
+
if (!relationDef && this.features.smartRelationDiscovery) {
|
|
26
|
+
const parentItems = items[0];
|
|
27
|
+
if (!parentItems)
|
|
28
|
+
continue;
|
|
29
|
+
// Try user_id -> user or userId -> user
|
|
30
|
+
const possibleKeys = [`${relationKey}Id`, `${relationKey}_id`, `${relationKey}`];
|
|
31
|
+
const localKey = possibleKeys.find(k => k in parentItems);
|
|
32
|
+
if (localKey) {
|
|
33
|
+
// Guess target collection (singular or plural)
|
|
34
|
+
const target = [relationKey, `${relationKey}s`, `${relationKey}es`].find(t => this.schema[t]);
|
|
35
|
+
if (target) {
|
|
36
|
+
relationDef = {
|
|
37
|
+
from: target,
|
|
38
|
+
localKey,
|
|
39
|
+
foreignKey: 'id', // Default to 'id' for target
|
|
40
|
+
isSingle: true // Default to single for inferred child relations
|
|
41
|
+
};
|
|
42
|
+
console.warn(`\x1b[33m[QuickQL][SmartDiscovery]\x1b[0m Inferred relation: '${relationKey}' -> '${target}' via field '${localKey}'`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!relationDef)
|
|
47
|
+
continue;
|
|
48
|
+
const targetCollection = this.schema[relationDef.from];
|
|
49
|
+
if (!targetCollection)
|
|
50
|
+
continue;
|
|
51
|
+
// Group local keys to avoid redundant queries (Optimizing N+1 problem)
|
|
52
|
+
const localKeys = [...new Set(items.map(item => item[relationDef.localKey]).filter(Boolean))];
|
|
53
|
+
if (localKeys.length === 0)
|
|
54
|
+
continue;
|
|
55
|
+
// Execute a single query for the entire batch of parent items
|
|
56
|
+
const select = relationQuery.select ? [...relationQuery.select] : undefined;
|
|
57
|
+
// ALWAYS include the foreign key in the sub-query, otherwise we can't map it back!
|
|
58
|
+
if (select && !select.includes(relationDef.foreignKey)) {
|
|
59
|
+
select.push(relationDef.foreignKey);
|
|
60
|
+
}
|
|
61
|
+
const fullRelationQuery = {
|
|
62
|
+
...relationQuery,
|
|
63
|
+
from: relationDef.from,
|
|
64
|
+
select,
|
|
65
|
+
where: {
|
|
66
|
+
[relationDef.foreignKey]: { in: localKeys }
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const relatedData = await this.executeQueryRef(fullRelationQuery, depth + 1);
|
|
70
|
+
// --- HIGHLY OPTIMIZED MAPPING SYSTEM ---
|
|
71
|
+
// Use a Map for O(1) lookups instead of O(N) filter in a loop
|
|
72
|
+
const lookupMap = new Map();
|
|
73
|
+
for (const rd of relatedData) {
|
|
74
|
+
const key = rd[relationDef.foreignKey];
|
|
75
|
+
if (!lookupMap.has(key))
|
|
76
|
+
lookupMap.set(key, []);
|
|
77
|
+
lookupMap.get(key).push(rd);
|
|
78
|
+
}
|
|
79
|
+
const originalSelect = relationQuery.select;
|
|
80
|
+
const shouldClean = originalSelect && !originalSelect.includes(relationDef.foreignKey);
|
|
81
|
+
for (const item of newItems) {
|
|
82
|
+
const localKeyValue = item[relationDef.localKey];
|
|
83
|
+
const matches = lookupMap.get(localKeyValue) || [];
|
|
84
|
+
// 2. Clean up unrequested fields from the matches
|
|
85
|
+
const finalMatches = shouldClean
|
|
86
|
+
? matches.map(rd => {
|
|
87
|
+
const clean = { ...rd };
|
|
88
|
+
delete clean[relationDef.foreignKey];
|
|
89
|
+
return clean;
|
|
90
|
+
})
|
|
91
|
+
: matches;
|
|
92
|
+
item[relationKey] = relationDef.isSingle ? (finalMatches[0] || null) : finalMatches;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return newItems;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sourceRoot":"","sources":["../../../src/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,OAAO,cAAc;IAEf;IACA;IACA;IAHV,YACU,MAAoB,EACpB,eAAgE,EAChE,WAA2B,EAAE,sBAAsB,EAAE,IAAI,EAAE;QAF3D,WAAM,GAAN,MAAM,CAAc;QACpB,oBAAe,GAAf,eAAe,CAAiD;QAChE,aAAQ,GAAR,QAAQ,CAAmD;IAClE,CAAC;IAEJ,KAAK,CAAC,OAAO,CACX,KAAY,EACZ,OAA0C,EAC1C,SAAc,EACd,KAAa;QAEb,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAE5B,KAAK,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACnE,IAAI,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;YAEzC,yFAAyF;YACzF,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAsB,EAAE,CAAC;gBACzD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC7B,IAAI,CAAC,WAAW;oBAAE,SAAS;gBAE3B,wCAAwC;gBACxC,MAAM,YAAY,GAAG,CAAC,GAAG,WAAW,IAAI,EAAE,GAAG,WAAW,KAAK,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC;gBACjF,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC;gBAE1D,IAAI,QAAQ,EAAE,CAAC;oBACb,+CAA+C;oBAC/C,MAAM,MAAM,GAAG,CAAC,WAAW,EAAE,GAAG,WAAW,GAAG,EAAE,GAAG,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC9F,IAAI,MAAM,EAAE,CAAC;wBACX,WAAW,GAAG;4BACZ,IAAI,EAAE,MAAM;4BACZ,QAAQ;4BACR,UAAU,EAAE,IAAI,EAAE,6BAA6B;4BAC/C,QAAQ,EAAE,IAAI,CAAC,iDAAiD;yBACjE,CAAC;wBACF,OAAO,CAAC,IAAI,CAAC,gEAAgE,WAAW,SAAS,MAAM,gBAAgB,QAAQ,GAAG,CAAC,CAAC;oBACtI,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,WAAW;gBAAE,SAAS;YAE3B,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACvD,IAAI,CAAC,gBAAgB;gBAAE,SAAS;YAEhC,uEAAuE;YACvE,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC9F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAErC,8DAA8D;YAC9D,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5E,mFAAmF;YACnF,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;gBACvD,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,iBAAiB,GAAU;gBAC/B,GAAG,aAAa;gBAChB,IAAI,EAAE,WAAW,CAAC,IAAI;gBACtB,MAAM;gBACN,KAAK,EAAE;oBACL,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE;iBACrC;aACT,CAAC;YAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,iBAAiB,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAE7E,0CAA0C;YAC1C,8DAA8D;YAC9D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;YACxC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;gBAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;gBACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAChD,SAAS,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/B,CAAC;YAED,MAAM,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC;YAC5C,MAAM,WAAW,GAAG,cAAc,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YAEvF,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACjD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;gBAEnD,kDAAkD;gBAClD,MAAM,YAAY,GAAG,WAAW;oBAC9B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;wBACf,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;wBACxB,OAAO,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;wBACrC,OAAO,KAAK,CAAC;oBACf,CAAC,CAAC;oBACJ,CAAC,CAAC,OAAO,CAAC;gBAEZ,IAAI,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;YACtF,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickQL Resolver Generator
|
|
3
|
+
*
|
|
4
|
+
* Automated resolver generation for ORM-backed collections (Prisma, etc.),
|
|
5
|
+
* bridging the gap between QuickQL queries and native database operations.
|
|
6
|
+
*
|
|
7
|
+
* (c) 2024-2026 Udinmo Inc. All rights reserved.
|
|
8
|
+
* Author: Udinmo Inc. <engineering@udinmo.com>
|
|
9
|
+
* License: MIT
|
|
10
|
+
*/
|
|
11
|
+
import { Query, Mutation } from '@quickql/core';
|
|
12
|
+
import { CollectionDefinition, QuickQLServerContext } from '../schema/types';
|
|
13
|
+
export declare class ResolverGenerator {
|
|
14
|
+
/**
|
|
15
|
+
* Generates a single Prisma-backed resolver for a given collection.
|
|
16
|
+
* Handles findMany and findUnique operations.
|
|
17
|
+
*/
|
|
18
|
+
static generateResolver(collection: CollectionDefinition): (query: Query, ctx: QuickQLServerContext) => Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Generates an automatic Prisma mutation resolver for a collection.
|
|
21
|
+
* Supports create, update, and delete actions.
|
|
22
|
+
*/
|
|
23
|
+
static generateMutationResolver(collection: CollectionDefinition): (mutation: Mutation, ctx: QuickQLServerContext) => Promise<any>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../src/resolver/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG7E,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,oBAAoB,WAGjC,KAAK,OAAO,oBAAoB;IAkBvD;;;OAGG;IACH,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,oBAAoB,cAGtC,QAAQ,OAAO,oBAAoB;CA4B9D"}
|