duckdb-wasm

94 阅读1分钟

新建react项目,添加依赖: "@duckdb/duckdb-wasm": "^1.14.1",

app.tsx:


import * as duckdb from "@duckdb/duckdb-wasm";

export function App() {
  async function test() {
    console.log('hello')
    const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();

    // Select a bundle based on browser checks
    const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);

    const worker_url = URL.createObjectURL(
      new Blob([`importScripts("${bundle.mainWorker!}");`], { type: 'text/javascript' })
    );

    // Instantiate the asynchronus version of DuckDB-wasm
    const worker = new Worker(worker_url);
    const logger = new duckdb.ConsoleLogger();
    const db = new duckdb.AsyncDuckDB(logger, worker);
    await db.instantiate(bundle.mainModule, bundle.pthreadWorker);

    const conn = await db.connect(); // Connect to db

    let q = await conn.query(`SELECT * FROM 'https://shell.duckdb.org/data/tpch/0_01/parquet/orders.parquet' LIMIT 10;`); // Returns v = 101
    console.log("Query result (Arrow Table):", q);

    console.log('Query result copy (JSON):', JSON.parse(JSON.stringify(q.toArray())));
    console.log('');
    URL.revokeObjectURL(worker_url);
    await conn.close();
    await db.terminate();
    await worker.terminate();
   
  }
  test()
  // const element = document.getElementById("root");
  // ReactDOM.render(
  //     <React.StrictMode>
  //         <Shell />
  //     </React.StrictMode>,
  //     element
  // );
  return (
    <div>
      <h1>hello from localhost</h1>
    </div>
  )
}
export default App

参考github.com/rob-blackbo…

www.modb.pro/db/17517921…

observablehq.com/documentati…

list组件 www.zhihu.com/tardis/bd/a…

import * as duckdb from '@duckdb/duckdb-wasm'
import { Input, Card, Table, Spin, Button, Space, Alert } from 'antd'
import { useState } from 'react'
import Highlight from 'react-highlight'
import hljs from 'highlight.js'
import sql from 'highlight.js/lib/languages/sql'
import 'highlight.js/styles/vs.css'
const { TextArea } = Input
hljs.registerLanguage('javascript', sql)
export function App() {
  const [loading, setLoading] = useState(false)
  const [dataSource, setDataSource] = useState([])
  const [columns, setColumns] = useState([])
  const [inputValue, setInputValue] = useState(
    "SELECT * FROM 'https://shell.duckdb.org/data/tpch/0_01/parquet/orders.parquet' LIMIT 10",
  )
  const myHtmlContent = '<h1>Hello, World!</h1><p>This is some HTML content.</p>';
  const [errorText, setErrorText] = useState('')
  const highlightCode = hljs.highlight(inputValue, { language: 'sql' }).value
  async function duckdbSearch() {
    const sql = inputValue
    try {
      // 基于浏览器选择bundle
      const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles()
      const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES)
      const worker_url = URL.createObjectURL(
        new Blob([`importScripts("${bundle.mainWorker}");`], {
          type: 'text/javascript',
        }),
      )

      // 实例化异步DuckDB-wasm
      const worker = new Worker(worker_url)
      const logger = new duckdb.ConsoleLogger()
      const db = new duckdb.AsyncDuckDB(logger, worker)
      await db.instantiate(bundle.mainModule, bundle.pthreadWorker)

      // 连接,查询
      const conn = await db.connect()
      let res = await conn.query(sql)

      // 处理返回数据格式
      if (res.numCols && res.numRows) {
        const items = JSON.parse(JSON.stringify(res.toArray()))
        console.log('items', items)
        const col = Object.keys(items[0]).map((key) => {
          return {
            title: key,
            dataIndex: key,
            key: key,
            width: `${100 / res.numCols}%`,
          }
        })
        const data = items.map((item, index) => {
          return {
            ...item,
            key: index,
          }
        })
        setColumns(col)
        setDataSource(data)
        console.log('---------col', col)
      }

      setLoading(false)

      // 关闭连接
      URL.revokeObjectURL(worker_url)
      await conn.close()
      await db.terminate()
      await worker.terminate()
    } catch (error) {
      setLoading(false)
      setErrorText(error.toString())
    }
  }
  return (
    <div>
      <Card title="Card" size="small">
        <Space
          direction="vertical"
          size="middle"
          style={{
            display: 'flex',
          }}
        >
          <span>{highlightCode}</span>
          <pre><code className="language-sql">{inputValue}</code></pre>
          <pre dangerouslySetInnerHTML={{__html: highlightCode}}></pre>
          {/* <Highlight languageName="sql" style={{whiteSpace:'pre-wrap'}}>{inputValue} </Highlight> */}
          <TextArea
            size='large'
            defaultValue="default"
            placeholder="在此处键入sql语句"
            autoSize
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
          >
          </TextArea>
          {/* <textarea value={inputValue}></textarea> */}
          <Button
            type="primary"
            loading={loading}
            onClick={() => {
              setLoading(true)
              duckdbSearch()
            }}
          >
            {'> '}Execute
          </Button>
            <Spin spinning={loading}>
              {!errorText && (
                <Table
                  dataSource={dataSource}
                  columns={columns}
                  bordered
                  pagination={false}
                  scroll={{
                    y: 300,
                  }}
                />
              )}
              {errorText && (
                <Alert
                  message="Error"
                  description={errorText}
                  type="error"
                  showIcon
                />
              )}
            </Spin>
        </Space>
      </Card>
    </div>
  )
}
export default App