0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GraphDB Kuzu(WebAssembly)でデータをlocalStorageに読み書きしたメモ

Posted at

概要

前回はkuzuを動作させるところまで確認した。
今回はローカルストレージへの永続化、復元を試してみた

この時点のソース

ソースコード

今回はグラフ描画にCytoscapeを試している

import kuzu_wasm, { Connection, Kuzu } from '@kuzu/kuzu-wasm';
import Cytoscape from 'cytoscape';
import { useEffect, useRef, useState } from 'react';
import { CytoscapeComponent } from './shared/ui';

function App() {
  const [elements, setNElements] = useState<{ data: { id?: string; source?: string; target?: string; label?: string } }[]>([]);
  const cyref = useRef<Cytoscape.CoreLayout | null>(null);
  const conRef = useRef<Connection | null>(null);
  const kuzuRef = useRef<Kuzu | null>(null);
  const draw = async () => {
    if (!conRef.current) return;
    // Execute Cypher query
    const response = await conRef.current.execute(
      `
   MATCH (a:User)
   RETURN *;
   `,
    );
    const users = !response.table ? [] : JSON.parse(response.table.toString());
    type ID = { offset: string; table: string };
    const getId = (id: ID): string => `id_${id.table}_${id.offset}`;
    const nodes = users.map(({ a }: { a: { _ID: ID; name: string } }) => ({ data: { id: getId(a._ID), label: a.name } }));

    const relsResponse = await conRef.current.execute(
      `
   MATCH (a:User)-[r:Follows]->(b:User)
   RETURN *;
   `,
    );
    const rels = !relsResponse.table ? [] : JSON.parse(relsResponse.table.toString());

    const relsData = rels.map(
      ({ r }: { a: { _ID: ID; name: string }; r: { _ID: ID; _SRC: ID; _DST: ID; since: string }; b: { _ID: ID; name: string } }) => ({
        data: {
          source: getId(r._SRC),
          target: getId(r._DST),
          id: getId(r._ID),
          label: r.since,
        },
      }),
    );
    setNElements([...nodes, ...relsData]);
    setTimeout(() => {
      if (cyref.current) cyref.current.layout({ name: 'grid' }).run();
    }, 0);
  };
  useEffect(() => {
    (async () => {
      const kuzu = await kuzu_wasm();
      const db = await kuzu.Database();
      const conn = await kuzu.Connection(db);
      conRef.current = conn;
      kuzuRef.current = kuzu;

      kuzu.FS.writeFile('/follows.csv', await (await fetch('/data/follows.csv')).text());
      kuzu.FS.writeFile('/user.csv', await (await fetch('/data/user.csv')).text());

      // Create schema
      await conn.execute('CREATE NODE TABLE User(name STRING, age INT64, PRIMARY KEY (name))');
      await conn.execute('CREATE REL TABLE Follows(FROM User TO User, since INT64)');

      // Insert data
      await conn.execute('COPY User FROM "/user.csv"');
      await conn.execute('COPY Follows FROM "/follows.csv"');

      // Execute Cypher query
      await draw();
    })();
  }, []);
  return (
    <>
      <CytoscapeComponent
        elements={elements}
        cy={(cy) => {
          cyref.current = cy;
        }}
        layout={{ name: 'grid' }}
        wheelSensitivity={0.1}
        style={{ width: '600px', height: '600px' }}
      />
      <form
        onSubmit={async (e) => {
          e.preventDefault();
          console.log(e);
          if (!conRef.current) return;
          const form = new FormData(e.currentTarget);
          const userName = form.get('username') || '';
          if (!userName) return;
          await conRef.current.execute(`CREATE (u:User {name: '${userName}', age: 10});`);
          await draw();
          return;
        }}
      >
        <input type="text" name="username" />
        <button type="submit">ユーザ追加</button>
      </form>
      <button
        onClick={async () => {
          if (!conRef.current || !kuzuRef.current) return;
          await conRef.current.execute(`COPY (MATCH (u:User) RETURN u.*) TO '/bakcup.csv' (header=false);`);

          const contents = kuzuRef.current.FS.readFile('/bakcup.csv', { encoding: 'utf8' });
          console.log('contents', contents);
          localStorage.setItem('backup_graphdb_user', contents);
        }}
      >
        保存
      </button>
      <button
        onClick={async () => {
          if (!conRef.current || !kuzuRef.current) return;
          console.log('load', localStorage.getItem('backup_graphdb_user'));
          kuzuRef.current.FS.writeFile('/storage.csv', localStorage.getItem('backup_graphdb_user') || '');
          // 一度消してからでないとエラーになる
          await conRef.current.execute(`MATCH (u:User) DETACH DELETE u`);
          await conRef.current.execute('COPY User FROM "/storage.csv"');
          await conRef.current.execute('COPY Follows FROM "/follows.csv"');
          await draw();
        }}
      >
        復元
      </button>
    </>
  );
}

export default App;

参考

copy to csv
what-is-kuzu-wasm
VFS
VFS - readfile

アップロードサンプル
write
migrate
node.js api

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?