SQL Editor Getting Started
SQL Editor, easy to use, easy to extend full-fledged and open-sourced SQL editor.
Overview
SQL Editor is built on CodeMirror6, a modern code editor that is written in TypeScript and supports a wide range of extensions. Based on that, we provide a set of extensions to make it easy to use and easy to extend, all these features are validated in the TiDB Cloud Console, with countless customers all around the world. We also contribute to the CodeMirror6 project, and we are happy to share our extensions with the community.
Installation
Inside your project directory, run the following command to install the core package which provides SQLEditorInstance
and EditorCache
variables.
SQLEditorInstance
creates EditorView instance with pre-configured extensions.EditorCache
stores theSQLEditorInstance
in a map.
npm install @tidbcloud/tisqleditor
If you need some extension, you can just install it alone. such as the extension @tidbcloud/codemirror-extension-events:
npm install @tidbcloud/codemirror-extension-events
All the extensions as below:
package | desc |
---|---|
@tidbcloud/tisqleditor | SQLEditorInstance with pre-configured extensions |
@tidbcloud/tisqleditor-react | React component wrapper |
@tidbcloud/codemirror-extension-sql-parser | parse the editor content to SQL statements |
@tidbcloud/codemirror-extension-cur-sql | get the selected SQL statements |
@tidbcloud/codemirror-extension-cur-sql-gutter | show gutter for the selected SQL statements |
@tidbcloud/codemirror-extension-save-helper | save the editor content if it changes |
@tidbcloud/codemirror-extension-autocomplete | SQL keyword and database schema autocomplete tips |
@tidbcloud/codemirror-extension-linters | Full-width characters, regular expression, or use statements linter |
@tidbcloud/codemirror-extension-events | 3 normal event extension |
@tidbcloud/codemirror-extension-themes | 2 simple builtin themes, bbedit for light mode, oneDark for dark mode |
@tidbcloud/codemirror-extension-basic-setup | Basic configuration for the CodeMirror6 code editor |
Quick Start
A mini Editor
Install packages:
npm install @tidbcloud/tisqleditor-react
npm install @tidbcloud/codemirror-extension-themes
npm install @tidbcloud/codemirror-extension-cur-sql-gutter
// Editor.tsx
import { SQLEditor } from '@tidbcloud/tisqleditor-react'
import { oneDark } from '@tidbcloud/codemirror-extension-themes'
import { curSqlGutter } from '@tidbcloud/codemirror-extension-cur-sql-gutter'
export const Editor = () => {
return (
<SQLEditor
editorId="MySQLEditor"
doc={"USE game;\n"}
theme={oneDark}
basicSetupOptions={{
autocompletion: true
}}
extraExts={[
curSqlGutter()
// here you can add some other extensions as you need
]}
/>
)
}
A mini Editor based on CodeMirror
Install packages:
npm install @codemirror/state
npm install @codemirror/view
npm install @codemirror/lang-sql
npm install @tidbcloud/codemirror-extension-basic-setup
npm install @tidbcloud/codemirror-extension-themes
//Editor.tsx
import { useEffect, useRef } from 'react'
import { EditorState, Compartment } from '@codemirror/state'
import { EditorView } from '@codemirror/view'
import { basicSetup } from '@tidbcloud/codemirror-extension-basic-setup'
import { bbedit, oneDark } from '@tidbcloud/codemirror-extension-themes'
import { sql, MySQL } from '@codemirror/lang-sql'
const Editor = () => {
const editorContainerRef = useRef<HTMLDivElement>(null)
const sqlCompartment = new Compartment()
useEffect(() => {
const editorInst = new EditorView({
state: EditorState.create({
doc: "USE game;\n",
extensions: [
basicSetup({
// set foldGutter: true will add a collapse/expand icon before the multi-line statement
foldGutter: false,
foldKeymap: false,
searchKeymap: true,
autocompletion: true
}),
sqlCompartment.of(sql({
dialect: MySQL,
upperCaseKeywords: true
})),
oneDark
// ------ Or ------
// bbedit
]
})
})
editorContainerRef.current?.appendChild(editorInst.dom)
return () => {
if (editorContainerRef.current && editorInst) {
editorContainerRef.current.removeChild(editorInst.dom)
}
}
}, [])
return (
<div ref={editorContainerRef}></div>
)
}
A SQL Editor with some extensions use @tidbcloud/tisqleditor-react
npm install @tidbcloud/tisqleditor-react
npm install @tidbcloud/codemirror-extension-save-helper
npm install @tidbcloud/codemirror-extension-themes
npm install @tidbcloud/codemirror-extension-cur-sql-gutter
npm install @tidbcloud/codemirror-extension-linters
npm install @tidbcloud/codemirror-extension-sql-autocomplete
npm install @tidbcloud/codemirror-extension-events
npm install @tidbcloud/codemirror-extension-sql-parser
npm i
import { SQLEditor } from '@tidbcloud/tisqleditor-react'
import { oneDark } from '@tidbcloud/codemirror-extension-themes'
import { curSqlGutter } from '@tidbcloud/codemirror-extension-cur-sql-gutter'
import { fullWidthCharLinter } from '@tidbcloud/codemirror-extension-linters'
import { sqlAutoCompletion } from '@tidbcloud/codemirror-extension-sql-autocomplete'
import { onSelectionChange, onDocChange, SelectionRange } from '@tidbcloud/codemirror-extension-events'
import { getNearbyStatement, getSqlStatements } from '@tidbcloud/codemirror-extension-sql-parser'
import { EditorView } from '@codemirror/view'
import { SQLConfig } from '@codemirror/lang-sql'
interface SchemaData {
name: string
tables: {
name: string
columns: {
col: string
data_type: string
nullable?: boolean
}[]
}[]
}
/**
* mock schema data
*/
const schema: SchemaData[] = [
{
"name": "game",
"tables": [
{
"name": "all_audio_language",
"columns": [
{
"col": "app_id",
"data_type": "int",
"nullable": false
}
]
},
{
"name": "category",
"columns": [
{
"col": "category_id",
"data_type": "int",
"nullable": false
}
]
}
]
},
{
"name": "test",
"tables": []
}
]
/**
* initial SQL contents
*/
const initialSQL = `USE game;
SELECT
g.*
FROM
game_genre gg
LEFT JOIN games g ON g.app_id = gg.app_id
WHERE
gg.genre_id = 9
ORDER BY
g.estimated_owners DESC;`
interface ColumnItem {
label: string
type: string
}
/**
convert schema data to SQL config format that the auto-complete list can be displayed
when typing database/table/column name.
*/
const convertSchemaToSQLConfig = (dbList: SchemaData[]): SQLConfig => {
const schema: {
[key: string]: ColumnItem[]
} = {}
const tables: ColumnItem[] = []
dbList.forEach((d) => {
const db = d.name
// allow you autocomplete when you type database name,
tables.push({
label: db,
type: 'database'
})
d.tables.forEach((t) => {
const table = t.name
tables.push({ label: table, type: 'table' })
const columns = t.columns.map((c) => ({
label: c.col,
type: c.data_type
}))
tables.push(...columns)
// allow you autocomplete when you type table, database.table name,
schema[`${db}.${table}`] = columns
schema[table] = columns
})
})
return { schema, tables }
}
const Editor = () => {
const sqlConfig = convertSchemaToSQLConfig(schema)
return (
<SQLEditor
editorId="mySQLEditor"
doc={initialSQL}
sqlConfig={sqlConfig}
theme={oneDark}
// ------ Or ------
// theme={bbedit}
basicSetupOptions={{
foldGutter: true
}}
extraExts={[
sqlAutoCompletion(),
curSqlGutter(),
fullWidthCharLinter(),
onDocChange((view: EditorView, doc: string) => {
// doc is all the current SQL content
console.log('doc change', doc)
}),
/**
* Triggered when your selection or cursor position changes,
* you can get the selection data from & to by the selRanges params,
* it is the cursor position if from equals to
*/
onSelectionChange((view: EditorView, selRanges: SelectionRange[]) => {
console.log('selection change', selRanges)
console.log(getNearbyStatement(view.state, selRanges[0].from))
console.log(getSqlStatements(view.state))
})
]}
/>
)
}
See editor.tsx or editor-example.tsx to get more details.