Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion demo/custom-renderers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ interface TableMetadata {
indexes: IndexMetadata[];
}

export type Schema = "users" | "posts" | "orders" | "customers" | "categories";
export type Schema = "users" | "posts" | "orders" | "customers" | "categories" | "Users_Posts";

export const tableTooltipRenderer = (data: NamespaceTooltipData) => {
// Show table name, columns, description, primary key, foreign key, index, unique, check, default, comment
Expand Down Expand Up @@ -292,6 +292,24 @@ function getTableMetadata(tableName: string): TableMetadata {
{ name: "idx_categories_parent", columns: ["parent_id"], unique: false },
],
},
Users_Posts: {
description: "User-Post relationships",
rowCount: "1,234",
columns: {
user_id: { type: "INT", notNull: true, foreignKey: true, comment: "User who posted" },
post_id: {
type: "INT",
notNull: true,
foreignKey: true,
comment: "Post being commented on",
},
},
foreignKeys: [
{ column: "user_id", referencedTable: "users", referencedColumn: "id" },
{ column: "post_id", referencedTable: "posts", referencedColumn: "id" },
],
indexes: [{ name: "idx_users_posts_user", columns: ["user_id"], unique: false }],
},
};

return (
Expand Down
81 changes: 81 additions & 0 deletions demo/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { Schema } from "./custom-renderers";

// Default SQL content for the demo
export const defaultSqlDoc = `-- Welcome to the SQL Editor Demo!
-- Try editing the queries below to see real-time validation

WITH cte_name AS (
SELECT * FROM users
)

-- Valid queries (no errors):
SELECT id, name, email
FROM users
WHERE active = true
ORDER BY created_at DESC;

SELECT
u.name,
p.title,
p.created_at
FROM users u
JOIN posts p ON u.id = p.user_id
WHERE u.status = 'active'
AND p.published = true
LIMIT 10;

-- Try editing these to create syntax errors:
-- Uncomment the lines below to see error highlighting

-- SELECT * FROM; -- Missing table name
-- SELECT * FORM users; -- Typo in FROM keyword
-- INSERT INTO VALUES (1, 2); -- Missing table name
-- UPDATE SET name = 'test'; -- Missing table name

-- Complex example with subquery:
SELECT
customer_id,
order_date,
total_amount,
(SELECT AVG(total_amount) FROM orders) as avg_order_value
FROM orders
WHERE order_date >= '2024-01-01'
AND total_amount > (
SELECT AVG(total_amount) * 0.8
FROM orders
WHERE YEAR(order_date) = 2024
)
ORDER BY total_amount DESC;
`;

export const schema: Record<Schema, string[]> = {
// Users table
users: ["id", "name", "email", "active", "status", "created_at", "updated_at", "profile_id"],
// Posts table
posts: [
"id",
"title",
"content",
"user_id",
"published",
"created_at",
"updated_at",
"category_id",
],
// Orders table
orders: [
"id",
"customer_id",
"order_date",
"total_amount",
"status",
"shipping_address",
"created_at",
],
// Customers table (additional example)
customers: ["id", "first_name", "last_name", "email", "phone", "address", "city", "country"],
// Categories table
categories: ["id", "name", "description", "parent_id"],
// Users_Posts table
Users_Posts: ["user_id", "post_id"],
};
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2 class="text-2xl font-bold mb-4">SQL Editor with Diagnostics</h2>
</p>

<div class="flex justify-end items-center mb-2">
<select id="dialect-select" class="border rounded-md p-1.5">
<select id="database-select" class="border rounded-md p-1.5">
<option value="PostgreSQL">PostgreSQL</option>
<option value="MySQL">MySQL</option>
<option value="SQLite">SQLite</option>
Expand Down
167 changes: 52 additions & 115 deletions demo/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { acceptCompletion } from "@codemirror/autocomplete";
import { PostgreSQL, sql } from "@codemirror/lang-sql";
import { type EditorState, StateEffect, StateField } from "@codemirror/state";
import { PostgreSQL, type SQLDialect, sql } from "@codemirror/lang-sql";
import { Compartment, type EditorState, StateEffect, StateField } from "@codemirror/state";
import { keymap } from "@codemirror/view";
import { basicSetup, EditorView } from "codemirror";
import {
Expand All @@ -11,85 +11,9 @@ import {
type SupportedDialects,
sqlExtension,
} from "../src/index.js";
import { type Schema, tableTooltipRenderer } from "./custom-renderers.js";

// Default SQL content for the demo
const defaultSqlDoc = `-- Welcome to the SQL Editor Demo!
-- Try editing the queries below to see real-time validation

WITH cte_name AS (
SELECT * FROM users
)

-- Valid queries (no errors):
SELECT id, name, email
FROM users
WHERE active = true
ORDER BY created_at DESC;

SELECT
u.name,
p.title,
p.created_at
FROM users u
JOIN posts p ON u.id = p.user_id
WHERE u.status = 'active'
AND p.published = true
LIMIT 10;

-- Try editing these to create syntax errors:
-- Uncomment the lines below to see error highlighting

-- SELECT * FROM; -- Missing table name
-- SELECT * FORM users; -- Typo in FROM keyword
-- INSERT INTO VALUES (1, 2); -- Missing table name
-- UPDATE SET name = 'test'; -- Missing table name

-- Complex example with subquery:
SELECT
customer_id,
order_date,
total_amount,
(SELECT AVG(total_amount) FROM orders) as avg_order_value
FROM orders
WHERE order_date >= '2024-01-01'
AND total_amount > (
SELECT AVG(total_amount) * 0.8
FROM orders
WHERE YEAR(order_date) = 2024
)
ORDER BY total_amount DESC;
`;

const schema: Record<Schema, string[]> = {
// Users table
users: ["id", "name", "email", "active", "status", "created_at", "updated_at", "profile_id"],
// Posts table
posts: [
"id",
"title",
"content",
"user_id",
"published",
"created_at",
"updated_at",
"category_id",
],
// Orders table
orders: [
"id",
"customer_id",
"order_date",
"total_amount",
"status",
"shipping_address",
"created_at",
],
// Customers table (additional example)
customers: ["id", "first_name", "last_name", "email", "phone", "address", "city", "country"],
// Categories table
categories: ["id", "name", "description", "parent_id"],
};
import { tableTooltipRenderer } from "./custom-renderers.js";
import { defaultSqlDoc, schema } from "./data.js";
import { guessSqlDialect } from "./utils.js";

let editor: EditorView;

Expand All @@ -104,7 +28,7 @@ const completionKindStyles = {
height: "12px",
};

const dialect = PostgreSQL;
const defaultDialect = PostgreSQL;

const defaultKeymap = [
{
Expand Down Expand Up @@ -148,7 +72,6 @@ const getKeywordDocs = async () => {
};

const setDatabase = StateEffect.define<SupportedDialects>();

const databaseField = StateField.define<SupportedDialects>({
create: () => "PostgreSQL",
update: (prevValue, transaction) => {
Expand All @@ -161,13 +84,45 @@ const databaseField = StateField.define<SupportedDialects>({
},
});

// Allows us to reconfigure the base sql extension without reloading the editor
const baseSqlCompartment = new Compartment();

const baseSqlExtension = (dialect: SQLDialect) => {
return sql({
dialect: dialect,
// Example schema for autocomplete
schema: schema,
// Enable uppercase keywords for more traditional SQL style
upperCaseKeywords: true,
keywordCompletion: (label, _type) => {
return {
label,
keyword: label,
info: async () => {
const dom = document.createElement("div");
const keywordDocs = await getKeywordDocs();
const description = keywordDocs[label.toLocaleLowerCase()];
if (!description) {
return null;
}
dom.innerHTML = DefaultSqlTooltipRenders.keyword({
keyword: label,
info: description,
});
return dom;
},
};
},
});
};

// Initialize the SQL editor
function initializeEditor() {
// Use the same parser
const parser = new NodeSqlParser({
getParserOptions: (state: EditorState) => {
return {
database: getDialect(state),
database: getDatabase(state),
};
},
});
Expand All @@ -177,32 +132,7 @@ function initializeEditor() {
EditorView.lineWrapping,
keymap.of(defaultKeymap),
databaseField,
sql({
dialect: dialect,
// Example schema for autocomplete
schema: schema,
// Enable uppercase keywords for more traditional SQL style
upperCaseKeywords: true,
keywordCompletion: (label, _type) => {
return {
label,
keyword: label,
info: async () => {
const dom = document.createElement("div");
const keywordDocs = await getKeywordDocs();
const description = keywordDocs[label.toLocaleLowerCase()];
if (!description) {
return null;
}
dom.innerHTML = DefaultSqlTooltipRenders.keyword({
keyword: label,
info: description,
});
return dom;
},
};
},
}),
baseSqlCompartment.of(baseSqlExtension(defaultDialect)),
sqlExtension({
// Linter extension configuration
linterConfig: {
Expand Down Expand Up @@ -237,7 +167,7 @@ function initializeEditor() {
parser,
},
}),
dialect.language.data.of({
defaultDialect.language.data.of({
autocomplete: cteCompletionSource,
}),
// Custom theme for better SQL editing
Expand Down Expand Up @@ -339,27 +269,34 @@ function setupExampleButtons() {
});
}

function getDialect(state: EditorState): SupportedDialects {
function getDatabase(state: EditorState): SupportedDialects {
return state.field(databaseField);
}

function setupDialectSelect() {
const select = document.querySelector("#dialect-select");
function setupDatabaseSelect() {
const select = document.querySelector("#database-select");
if (select) {
select.addEventListener("change", (e) => {
const value = (e.target as HTMLSelectElement).value as SupportedDialects;
updateSqlDialect(editor, guessSqlDialect(value));
editor.dispatch({
effects: [setDatabase.of(value)],
});
});
}
}

function updateSqlDialect(view: EditorView, dialect: SQLDialect) {
view.dispatch({
effects: [baseSqlCompartment.reconfigure(baseSqlExtension(dialect))],
});
}

// Initialize everything when the page loads
document.addEventListener("DOMContentLoaded", () => {
initializeEditor();
setupExampleButtons();
setupDialectSelect();
setupDatabaseSelect();

console.log("SQL Editor Demo initialized!");
console.log("Features:");
Expand Down
19 changes: 19 additions & 0 deletions demo/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MySQL, PostgreSQL, type SQLDialect, SQLite } from "@codemirror/lang-sql";
import { DuckDBDialect } from "../src/dialects/duckdb/duckdb";
import type { SupportedDialects } from "../src/sql/parser";

export function guessSqlDialect(dialect: SupportedDialects): SQLDialect {
// Other supported dialects: Cassandra, MSSQL, MariaSQL, MySQL, PLSQL, PostgreSQL
switch (dialect) {
case "PostgreSQL":
return PostgreSQL;
case "DuckDB":
return DuckDBDialect;
case "MySQL":
return MySQL;
case "Sqlite":
return SQLite;
default:
return PostgreSQL;
}
}
Loading
Loading