Feature: add drizzle (#264)
Some checks failed
CI / build-test (macos-14) (push) Has been cancelled
CI / build-test (ubuntu-24.04) (push) Has been cancelled
CI / build-test (windows-latest) (push) Has been cancelled
JSR Publish / publish (push) Has been cancelled
NPM Package Publish / publish-npm (push) Has been cancelled

* feat: add drizzle orm

* feat: update drizzle configuration and schema management

- Added a check for DB_FILE_NAME in drizzle.config.ts to ensure it's set.
- Updated package.json to change the package name to @kksh/drizzle and added exports for schema and relations.
- Enhanced README.md with instructions for using the schema generation.
- Refactored schema.ts for improved readability and organization of imports.

* add tauri-plugin-sql

* feat: add database select and execute commands

- Introduced `select` and `execute` functions in the database module to facilitate querying and executing SQL commands.
- Updated the Tauri plugin to expose these commands, allowing for database interactions from the frontend.
- Added corresponding permissions for the new commands in the permissions configuration.
- Enhanced the database library with JSON value handling for query parameters.

* fix: sqlite select command

* drizzle ORM verified working

* refactor: clean up database module by removing unused SelectQueryResult type and disabling eslint for explicit any usage

* pnpm lock update

* Update enum definition for type safety

- Changed enum to use 'as const' for better type inference
- Ensured more robust handling of extension publish sources

* reimplemented most db command functions with ORM (migrate from tauri command invoke

* fixed searchExtensionData orm function

* Refactor ORM commands and searchExtensionData function for improved readability and consistency

- Reformatted import statements for better organization.
- Cleaned up whitespace and indentation in searchExtensionData function.
- Enhanced readability of SQL conditions and query building logic.
- Disabled eslint for explicit any usage in the troubleshooters page.

* Fix test assertions in database module to use array indexing for results

format rust code

* update deno lock

* move drizzle from desktop to drizzle package

* update pnpm version and lock

* refactor: migrate db tauri commands to drizzle

* refactor: remove unused extension and command CRUD operations from db module
This commit is contained in:
Huakun 2025-04-01 06:15:10 -04:00 committed by GitHub
parent bf51fdadbc
commit bb9a46935c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 3966 additions and 910 deletions

View file

@ -17,6 +17,7 @@
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@inlang/paraglide-sveltekit": "0.16.0",
"@kksh/drizzle": "workspace:*",
"@kksh/extension": "workspace:*",
"@kksh/svelte5": "^0.1.15",
"@kksh/ui": "workspace:*",
@ -27,9 +28,11 @@
"@tauri-apps/api": "^2.3.0",
"@tauri-apps/plugin-autostart": "^2.2.0",
"@tauri-apps/plugin-shell": "^2.2.0",
"@tauri-apps/plugin-sql": "^2.2.0",
"@tauri-apps/plugin-stronghold": "^2.2.0",
"@tauri-store/svelte": "^2.1.1",
"dompurify": "^3.2.4",
"drizzle-orm": "^0.40.1",
"eslint": "^9.21.0",
"fuse.js": "^7.1.0",
"gsap": "^3.12.7",
@ -37,7 +40,7 @@
"lz-string": "^1.5.0",
"pretty-bytes": "^6.1.1",
"semver": "^7.7.1",
"svelte-inspect-value": "^0.3.0",
"svelte-inspect-value": "^0.5.0",
"svelte-sonner": "^0.3.28",
"sveltekit-superforms": "^2.23.1",
"tauri-plugin-clipboard-api": "^2.1.11",

View file

@ -58,6 +58,7 @@ uuid = "1.14.0"
obfstr = { workspace = true }
base64 = { workspace = true }
tauri-plugin-stronghold = "2.2.0"
tauri-plugin-sql = "2"
[target."cfg(target_os = \"macos\")".dependencies]

View file

@ -108,6 +108,11 @@ pub fn run() {
.build(),
)
.plugin(tauri_plugin_cli::init())
.plugin(
tauri_plugin_sql::Builder::default()
// .add_migrations("sqlite:mydatabase.db", migrations)
.build(),
)
.plugin(tauri_plugin_user_input::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_shell::init())

View file

@ -242,6 +242,23 @@ export const rawBuiltinCmds: BuiltinCmd[] = [
},
keywords: ["extension", "troubleshooter"]
},
{
name: "ORM Troubleshooter",
icon: {
type: IconEnum.Iconify,
value: "material-symbols:database"
},
description: "",
flags: {
developer: true,
dev: true
},
function: async () => {
appState.clearSearchTerm()
goto(i18n.resolveRoute("/app/troubleshooters/orm"))
},
keywords: ["extension", "troubleshooter", "database", "orm"]
},
{
name: "Create Quicklink",
icon: {

View file

@ -7,10 +7,11 @@ import { decideKkrpcSerialization } from "@/utils/kkrpc"
import { sleep } from "@/utils/time"
import { trimSlash } from "@/utils/url"
import { constructExtensionSupportDir } from "@kksh/api"
import { db, spawnExtensionFileServer } from "@kksh/api/commands"
import { spawnExtensionFileServer } from "@kksh/api/commands"
import type { HeadlessCommand } from "@kksh/api/headless"
import { CustomUiCmd, ExtPackageJsonExtra, HeadlessCmd, TemplateUiCmd } from "@kksh/api/models"
import { constructJarvisServerAPIWithPermissions, type IApp } from "@kksh/api/ui"
import { db } from "@kksh/drizzle"
import { launchNewExtWindow, loadExtensionManifestFromDisk } from "@kksh/extension"
import type { IKunkunFullServerAPI } from "@kunkunapi/src/api/server"
import { convertFileSrc } from "@tauri-apps/api/core"

View file

View file

@ -0,0 +1,60 @@
// /* eslint-disable @typescript-eslint/no-explicit-any */
// import { db as dbCmd } from "@kksh/api/commands"
// import * as schema from "@kksh/drizzle/schema"
// import { error } from "@tauri-apps/plugin-log"
// import { drizzle } from "drizzle-orm/sqlite-proxy"
// /**
// * Loads the sqlite database via the Tauri Proxy.
// */
// // export const sqlite = await Database.load("sqlite:test.db");
// /**
// * The drizzle database instance.
// */
// export const db = drizzle<typeof schema>(
// async (sql, params, method) => {
// let rows: any = []
// let results = []
// console.log({
// sql,
// params,
// method
// })
// console.log(sql)
// // If the query is a SELECT, use the select method
// if (isSelectQuery(sql)) {
// rows = await dbCmd.select(sql, params).catch((e) => {
// error("SQL Error:", e)
// return []
// })
// } else {
// // Otherwise, use the execute method
// rows = await dbCmd.execute(sql, params).catch((e) => {
// error("SQL Error:", e)
// return []
// })
// return { rows: [] }
// }
// rows = rows.map((row: any) => {
// return Object.values(row)
// })
// // If the method is "all", return all rows
// results = method === "all" ? rows : rows[0]
// return { rows: results }
// },
// // Pass the schema to the drizzle instance
// { schema: schema, logger: true }
// )
// /**
// * Checks if the given SQL query is a SELECT query.
// * @param sql The SQL query to check.
// * @returns True if the query is a SELECT query, false otherwise.
// */
// function isSelectQuery(sql: string): boolean {
// const selectRegex = /^\s*SELECT\b/i
// return selectRegex.test(sql)
// }

View file

@ -1,5 +1,5 @@
import { db } from "@kksh/api/commands"
import type { CustomUiCmd, ExtPackageJsonExtra, HeadlessCmd, TemplateUiCmd } from "@kksh/api/models"
import { db } from "@kksh/drizzle"
import * as extAPI from "@kksh/extension"
import * as path from "@tauri-apps/api/path"
import Fuse from "fuse.js"

View file

@ -12,6 +12,7 @@
<svelte:window on:keydown={handleKeyDown} />
<div class="fixed h-12 w-full" data-tauri-drag-region></div>
<Layouts.Center class="min-h-screen py-5">
<Error.RawErrorJSONPreset
title="Error"

View file

@ -31,6 +31,7 @@
SystemCmds
} from "@kksh/ui/main"
import { cn } from "@kksh/ui/utils"
import { Ext } from "@kunkunapi/src/models/extension"
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
import { getCurrentWindow, Window } from "@tauri-apps/api/window"
import { platform } from "@tauri-apps/plugin-os"
@ -45,6 +46,7 @@
} from "lucide-svelte"
import { onMount } from "svelte"
import { Inspect } from "svelte-inspect-value"
import * as v from "valibot"
const win = getCurrentWindow()
let inputEle: HTMLInputElement | null = $state(null)
@ -114,6 +116,7 @@
<Inspect name="devStoreExtCmds" value={$devStoreExtCmds} />
<Inspect name="$appState.searchTerm" value={$appState.searchTerm} />
-->
<Command.Root
class={cn("h-screen rounded-lg shadow-md")}
bind:value={$appState.highlightedCmd}

View file

@ -3,8 +3,9 @@
import { goHome } from "@/utils/route"
import { listenToNewClipboardItem, listenToWindowFocus } from "@/utils/tauri-events"
import Icon from "@iconify/svelte"
import { ClipboardContentType, db } from "@kksh/api/commands"
import { ClipboardContentType } from "@kksh/api/commands"
import { SearchModeEnum, SQLSortOrderEnum, type ExtData } from "@kksh/api/models"
import { db } from "@kksh/drizzle"
import { Button, Command, Resizable } from "@kksh/svelte5"
import { Constants } from "@kksh/ui"
import { CustomCommandInput, GlobalCommandPaletteFooter } from "@kksh/ui/main"

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { cn } from "@/utils"
import { db } from "@kksh/api/commands"
import type { ExtData } from "@kksh/api/models"
import { db } from "@kksh/drizzle"
import { Resizable, Separator } from "@kksh/svelte5"
import { convertFileSrc } from "@tauri-apps/api/core"
import DOMPurify from "dompurify"

View file

@ -10,7 +10,6 @@
import { positionToCssStyleString, positionToTailwindClasses } from "@/utils/style"
import { sleep } from "@/utils/time"
import { isInMainWindow } from "@/utils/window"
import { db } from "@kksh/api/commands"
import { CustomPosition, ThemeColor, type Position } from "@kksh/api/models"
import {
constructJarvisServerAPIWithPermissions,
@ -19,6 +18,7 @@
type IUiCustom
} from "@kksh/api/ui"
import { toast, type IUiCustomServer1, type IUiCustomServer2 } from "@kksh/api/ui/custom"
import { db } from "@kksh/drizzle"
import { Button } from "@kksh/svelte5"
import { cn } from "@kksh/ui/utils"
import type { IKunkunFullServerAPI } from "@kunkunapi/src/api/server"

View file

@ -1,8 +1,7 @@
import { KunkunIframeExtParams } from "@/cmds/ext"
import { i18n } from "@/i18n"
import { appState } from "@/stores/appState"
import { db, unregisterExtensionWindow } from "@kksh/api/commands"
import type { Ext as ExtInfoInDB, ExtPackageJsonExtra } from "@kksh/api/models"
import { db } from "@kksh/drizzle"
import { loadExtensionManifestFromDisk } from "@kksh/extension"
import { error as svError } from "@sveltejs/kit"
import { join } from "@tauri-apps/api/path"

View file

@ -13,7 +13,6 @@
} from "@/utils/tauri-events.js"
import { sleep } from "@/utils/time.js"
import { isInMainWindow } from "@/utils/window.js"
import { db } from "@kksh/api/commands"
import {
constructJarvisServerAPIWithPermissions,
type IApp,
@ -29,6 +28,7 @@
type IComponent,
type TemplateUiCommand
} from "@kksh/api/ui/template"
import { db } from "@kksh/drizzle"
import { Button, Form } from "@kksh/svelte5"
import { LoadingBar } from "@kksh/ui"
import { Templates } from "@kksh/ui/extension"

View file

@ -1,7 +1,7 @@
import { KunkunTemplateExtParams } from "@/cmds/ext"
import { i18n } from "@/i18n"
import { db, unregisterExtensionWindow } from "@kksh/api/commands"
import type { Ext as ExtInfoInDB, ExtPackageJsonExtra } from "@kksh/api/models"
import type { ExtPackageJsonExtra } from "@kksh/api/models"
import { db } from "@kksh/drizzle"
import { loadExtensionManifestFromDisk } from "@kksh/extension"
import { error as sbError, error as svError } from "@sveltejs/kit"
import { join } from "@tauri-apps/api/path"

View file

@ -1,6 +1,6 @@
<script lang="ts">
import * as m from "@/paraglide/messages"
import { db } from "@kksh/api/commands"
import { db } from "@kksh/drizzle"
import { loadExtensionManifestFromDisk } from "@kksh/extension"
import { Button, Dialog, Table } from "@kksh/svelte5"
import { join } from "@tauri-apps/api/path"

View file

@ -0,0 +1,124 @@
<script lang="ts">
import {
getAllCmds,
getAllExtensions,
getExtensionDataById,
getUniqueExtensionByIdentifier,
getUniqueExtensionByPath,
searchExtensionData,
updateCmdByID
} from "@kksh/drizzle/api"
import * as schema from "@kksh/drizzle/schema"
import { Button, Input } from "@kksh/svelte5"
import { CmdTypeEnum, Ext } from "@kunkunapi/src/models/extension"
import { SearchModeEnum, SQLSortOrderEnum } from "@kunkunapi/src/models/sql"
// import * as orm from "drizzle-orm"
import { Inspect } from "svelte-inspect-value"
import { toast } from "svelte-sonner"
import * as v from "valibot"
let searchText = $state("")
/* eslint-disable */
let data: any = $state(null)
let inspectTitle = $state("")
</script>
<main class="container space-y-2">
<Button
onclick={async () => {
getAllCmds()
.then((cmds) => {
console.log(cmds)
data = cmds
inspectTitle = "All Commands"
})
.catch((e) => {
console.error(e)
toast.error("Failed to get all commands", {
description: "See console for more details"
})
})
}}
>
Get All Commands
</Button>
<Button
onclick={() => {
getAllExtensions()
.then((exts) => {
data = exts
inspectTitle = "All Extensions"
})
.catch((e) => {
console.error(e)
toast.error("Failed to get all extensions", {
description: "See console for more details"
})
})
}}
>
Get All Extensions
</Button>
<Button
onclick={async () => {
// get all extensions with path not null
const exts = await getAllExtensions()
for (const ext of exts) {
if (ext.path === null) continue
const _ext = await getUniqueExtensionByIdentifier(ext.identifier)
console.log(_ext)
if (ext.path) {
const __ext = await getUniqueExtensionByPath(ext.path)
console.log(__ext)
}
}
// data = exts
}}
>
Get Unique Extension By Identifier and Path
</Button>
<!-- <Button
onclick={async () => {
updateCmdByID({
cmdId: 1,
name: "google",
cmdType: CmdTypeEnum.QuickLink,
data: `{"link":"https://google.com/search?query={argument}","icon":{"type":"remote-url","value":"https://google.com/favicon.ico","invert":false}}`,
enabled: true
})
}}
>
Update Command By ID
</Button> -->
<Button
onclick={async () => {
const _data = await getExtensionDataById(1, ["search_text", "data"])
data = _data
inspectTitle = "Extension Data"
}}
>
Get Extension Data By ID
</Button>
<form
class="flex gap-1"
onsubmit={async (e) => {
e.preventDefault()
const _data = await searchExtensionData({
extId: 1,
searchMode: SearchModeEnum.FTS,
searchText: searchText,
orderByCreatedAt: SQLSortOrderEnum.Desc,
limit: 10,
fields: ["search_text", "data"]
})
console.log(_data)
data = _data
inspectTitle = "Search Results"
}}
>
<Input class="" bind:value={searchText} placeholder="Search Text" />
<Button class="" type="submit">Search Extension Data</Button>
</form>
<Inspect name={inspectTitle} value={data} expandLevel={2} />
</main>

View file

@ -6,6 +6,7 @@
import { Constants } from "@kksh/ui"
import { ArrowLeftIcon } from "lucide-svelte"
import AppWindow from "lucide-svelte/icons/app-window"
import DB from "lucide-svelte/icons/database"
import Loader from "lucide-svelte/icons/loader"
import Network from "lucide-svelte/icons/network"
@ -25,6 +26,11 @@
title: m.troubleshooters_sidebar_mdns_debugger_title(),
url: i18n.resolveRoute("/app/troubleshooters/mdns-debugger"),
icon: Network
},
{
title: "ORM",
url: i18n.resolveRoute("/app/troubleshooters/orm"),
icon: DB
}
]
let currentItem = $state(items.find((item) => window.location.pathname === item.url))