mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-07-03 06:51:29 +00:00
reimplemented most db command functions with ORM (migrate from tauri command invoke
This commit is contained in:
parent
dda783b9f6
commit
9757b6975c
@ -39,7 +39,7 @@
|
|||||||
"lz-string": "^1.5.0",
|
"lz-string": "^1.5.0",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"semver": "^7.7.1",
|
"semver": "^7.7.1",
|
||||||
"svelte-inspect-value": "^0.3.0",
|
"svelte-inspect-value": "^0.5.0",
|
||||||
"svelte-sonner": "^0.3.28",
|
"svelte-sonner": "^0.3.28",
|
||||||
"sveltekit-superforms": "^2.23.1",
|
"sveltekit-superforms": "^2.23.1",
|
||||||
"tauri-plugin-clipboard-api": "^2.1.11",
|
"tauri-plugin-clipboard-api": "^2.1.11",
|
||||||
|
@ -242,6 +242,23 @@ export const rawBuiltinCmds: BuiltinCmd[] = [
|
|||||||
},
|
},
|
||||||
keywords: ["extension", "troubleshooter"]
|
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",
|
name: "Create Quicklink",
|
||||||
icon: {
|
icon: {
|
||||||
|
343
apps/desktop/src/lib/orm/cmds.ts
Normal file
343
apps/desktop/src/lib/orm/cmds.ts
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
import * as relations from "@kksh/drizzle/relations"
|
||||||
|
import * as schema from "@kksh/drizzle/schema"
|
||||||
|
import { CmdType, Ext, ExtCmd, ExtData, SearchMode, SearchModeEnum, SQLSortOrder, SQLSortOrderEnum } from "@kunkunapi/src/models"
|
||||||
|
import * as orm from "drizzle-orm"
|
||||||
|
import type { SelectedFields } from "drizzle-orm/sqlite-core"
|
||||||
|
import * as v from "valibot"
|
||||||
|
import { db } from "./database"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Built-in Extensions */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Extension CRUD */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
export async function getUniqueExtensionByIdentifier(identifier: string): Promise<Ext | undefined> {
|
||||||
|
const ext = await db
|
||||||
|
.select()
|
||||||
|
.from(schema.extensions)
|
||||||
|
.where(orm.eq(schema.extensions.identifier, identifier))
|
||||||
|
.get()
|
||||||
|
return v.parse(v.optional(Ext), ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function when you expect the extension to exist. Such as builtin extensions.
|
||||||
|
* @param identifier
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getExtensionByIdentifierExpectExists(identifier: string): Promise<Ext> {
|
||||||
|
return getUniqueExtensionByIdentifier(identifier).then((ext) => {
|
||||||
|
if (!ext) {
|
||||||
|
throw new Error(`Unexpexted Error: Extension ${identifier} not found`)
|
||||||
|
}
|
||||||
|
return ext
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllExtensions(): Promise<Ext[]> {
|
||||||
|
const exts = await db.select().from(schema.extensions).all()
|
||||||
|
return v.parse(v.array(Ext), exts)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There can be duplicate extensions with the same identifier. Store and Dev extensions can have the same identifier.
|
||||||
|
* But install path must be unique.
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
export async function getUniqueExtensionByPath(path: string) {
|
||||||
|
const ext = await db
|
||||||
|
.select()
|
||||||
|
.from(schema.extensions)
|
||||||
|
.where(orm.eq(schema.extensions.path, path))
|
||||||
|
.get()
|
||||||
|
return v.parse(Ext, ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllExtensionsByIdentifier(identifier: string): Promise<Ext[]> {
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(schema.extensions)
|
||||||
|
.where(orm.eq(schema.extensions.identifier, identifier))
|
||||||
|
.all()
|
||||||
|
.then((exts) => v.parse(v.array(Ext), exts))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteExtensionByPath(path: string): Promise<void> {
|
||||||
|
return db
|
||||||
|
.delete(schema.extensions)
|
||||||
|
.where(orm.eq(schema.extensions.path, path))
|
||||||
|
.run()
|
||||||
|
.then(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteExtensionByExtId(extId: number): Promise<void> {
|
||||||
|
return db
|
||||||
|
.delete(schema.extensions)
|
||||||
|
.where(orm.eq(schema.extensions.extId, extId))
|
||||||
|
.run()
|
||||||
|
.then(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Extension Command CRUD */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// export async function getExtensionWithCmdsByIdentifier(identifier: string): Promise<ExtWithCmds> {
|
||||||
|
// const ext = await db
|
||||||
|
// .select({
|
||||||
|
// ...schema.extensions,
|
||||||
|
// commands: relations.commandsRelations
|
||||||
|
// })
|
||||||
|
// .from(schema.extensions)
|
||||||
|
// .leftJoin(schema.commands, orm.eq(schema.extensions.extId, schema.commands.extId))
|
||||||
|
// .where(orm.eq(schema.extensions.identifier, identifier))
|
||||||
|
// .get()
|
||||||
|
|
||||||
|
// // return v.parse(v.nullable(ExtWithCmds), ext);
|
||||||
|
// }
|
||||||
|
|
||||||
|
export async function getCmdById(cmdId: number): Promise<ExtCmd> {
|
||||||
|
const cmd = await db
|
||||||
|
.select()
|
||||||
|
.from(schema.commands)
|
||||||
|
.where(orm.eq(schema.commands.cmdId, cmdId))
|
||||||
|
.get()
|
||||||
|
return v.parse(ExtCmd, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllCmds(): Promise<ExtCmd[]> {
|
||||||
|
const cmds = await db.select().from(schema.commands).all()
|
||||||
|
return v.parse(v.array(ExtCmd), cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCommandsByExtId(extId: number) {
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(schema.commands)
|
||||||
|
.where(orm.eq(schema.commands.extId, extId))
|
||||||
|
.all()
|
||||||
|
.then((cmds) => v.parse(v.array(ExtCmd), cmds))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteCmdById(cmdId: number) {
|
||||||
|
return db
|
||||||
|
.delete(schema.commands)
|
||||||
|
.where(orm.eq(schema.commands.cmdId, cmdId))
|
||||||
|
.run()
|
||||||
|
.then(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateCmdByID(data: {
|
||||||
|
cmdId: number
|
||||||
|
name: string
|
||||||
|
cmdType: CmdType
|
||||||
|
data: string
|
||||||
|
alias?: string
|
||||||
|
hotkey?: string
|
||||||
|
enabled: boolean
|
||||||
|
}) {
|
||||||
|
return db
|
||||||
|
.update(schema.commands)
|
||||||
|
.set({
|
||||||
|
name: data.name,
|
||||||
|
type: data.cmdType,
|
||||||
|
data: data.data,
|
||||||
|
alias: data.alias, // optional
|
||||||
|
hotkey: data.hotkey, // optional
|
||||||
|
enabled: data.enabled
|
||||||
|
// in drizzle schema, use integer({ mode: 'boolean' }) for boolean sqlite
|
||||||
|
// enabled: data.enabled ? String(data.enabled) : undefined
|
||||||
|
})
|
||||||
|
.where(orm.eq(schema.commands.cmdId, data.cmdId))
|
||||||
|
.run()
|
||||||
|
.then(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Extension Data CRUD */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
export const ExtDataField = v.union([v.literal("data"), v.literal("search_text")])
|
||||||
|
export type ExtDataField = v.InferOutput<typeof ExtDataField>
|
||||||
|
|
||||||
|
function convertRawExtDataToExtData(rawData?: {
|
||||||
|
createdAt: string
|
||||||
|
updatedAt: string
|
||||||
|
data: null | string
|
||||||
|
searchText?: null | string
|
||||||
|
dataId: number
|
||||||
|
extId: number
|
||||||
|
dataType: string
|
||||||
|
}): ExtData | undefined {
|
||||||
|
if (!rawData) {
|
||||||
|
return rawData
|
||||||
|
}
|
||||||
|
const parsedRes = v.safeParse(ExtData, {
|
||||||
|
...rawData,
|
||||||
|
createdAt: new Date(rawData.createdAt),
|
||||||
|
updatedAt: new Date(rawData.updatedAt),
|
||||||
|
data: rawData.data ?? undefined,
|
||||||
|
searchText: rawData.searchText ?? undefined
|
||||||
|
})
|
||||||
|
if (parsedRes.success) {
|
||||||
|
return parsedRes.output
|
||||||
|
} else {
|
||||||
|
console.error("Extension Data Parse Failure", parsedRes.issues)
|
||||||
|
throw new Error("Fail to parse extension data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createExtensionData(data: {
|
||||||
|
extId: number
|
||||||
|
dataType: string
|
||||||
|
data: string
|
||||||
|
searchText?: string
|
||||||
|
}) {
|
||||||
|
return db.insert(schema.extensionData).values(data).run()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExtensionDataById(dataId: number, fields?: ExtDataField[]) {
|
||||||
|
const _fields = fields ?? []
|
||||||
|
const selectQuery: SelectedFields = {
|
||||||
|
dataId: schema.extensionData.dataId,
|
||||||
|
extId: schema.extensionData.extId,
|
||||||
|
dataType: schema.extensionData.dataType,
|
||||||
|
metadata: schema.extensionData.metadata,
|
||||||
|
createdAt: schema.extensionData.createdAt,
|
||||||
|
updatedAt: schema.extensionData.updatedAt
|
||||||
|
// data: schema.extensionData.data,
|
||||||
|
// searchText: schema.extensionData.searchText
|
||||||
|
}
|
||||||
|
if (_fields.includes("data")) {
|
||||||
|
selectQuery["data"] = schema.extensionData.data
|
||||||
|
}
|
||||||
|
if (_fields.includes("search_text")) {
|
||||||
|
selectQuery["searchText"] = schema.extensionData.searchText
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
.select(selectQuery)
|
||||||
|
.from(schema.extensionData)
|
||||||
|
.where(orm.eq(schema.extensionData.dataId, dataId))
|
||||||
|
.get()
|
||||||
|
.then((rawData) => {
|
||||||
|
console.log("Raw Data", rawData)
|
||||||
|
// @ts-expect-error - rawData is unknown, but will be safe parsed with valibot
|
||||||
|
return convertRawExtDataToExtData(rawData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function searchExtensionData(searchParams: {
|
||||||
|
extId: number
|
||||||
|
searchMode: SearchMode
|
||||||
|
dataId?: number
|
||||||
|
dataType?: string
|
||||||
|
searchText?: string
|
||||||
|
afterCreatedAt?: string
|
||||||
|
beforeCreatedAt?: string
|
||||||
|
limit?: number
|
||||||
|
offset?: number
|
||||||
|
orderByCreatedAt?: SQLSortOrder
|
||||||
|
orderByUpdatedAt?: SQLSortOrder
|
||||||
|
fields?: ExtDataField[]
|
||||||
|
}): Promise<ExtData[]> {
|
||||||
|
const fields = v.parse(v.optional(v.array(ExtDataField), []), searchParams.fields)
|
||||||
|
const _fields = fields ?? []
|
||||||
|
|
||||||
|
// Build the select query based on fields
|
||||||
|
const selectQuery: SelectedFields = {
|
||||||
|
dataId: schema.extensionData.dataId,
|
||||||
|
extId: schema.extensionData.extId,
|
||||||
|
dataType: schema.extensionData.dataType,
|
||||||
|
createdAt: schema.extensionData.createdAt,
|
||||||
|
updatedAt: schema.extensionData.updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_fields.includes("data")) {
|
||||||
|
selectQuery["data"] = schema.extensionData.data
|
||||||
|
}
|
||||||
|
if (_fields.includes("search_text")) {
|
||||||
|
selectQuery["searchText"] = schema.extensionData.searchText
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the query
|
||||||
|
const query = db.select(selectQuery).from(schema.extensionData)
|
||||||
|
|
||||||
|
// Add conditions
|
||||||
|
const conditions = [orm.eq(schema.extensionData.extId, searchParams.extId)]
|
||||||
|
|
||||||
|
if (searchParams.dataId) {
|
||||||
|
conditions.push(orm.eq(schema.extensionData.dataId, searchParams.dataId))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.dataType) {
|
||||||
|
conditions.push(orm.eq(schema.extensionData.dataType, searchParams.dataType))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.searchText) {
|
||||||
|
switch (searchParams.searchMode) {
|
||||||
|
case SearchModeEnum.ExactMatch:
|
||||||
|
conditions.push(orm.eq(schema.extensionData.searchText, searchParams.searchText))
|
||||||
|
break
|
||||||
|
case SearchModeEnum.Like:
|
||||||
|
conditions.push(orm.like(schema.extensionData.searchText, `%${searchParams.searchText}%`))
|
||||||
|
break
|
||||||
|
case SearchModeEnum.FTS:
|
||||||
|
// For FTS, we need to use a raw SQL query since Drizzle doesn't support MATCH directly
|
||||||
|
conditions.push(orm.sql`${schema.extensionDataFts.searchText} MATCH ${searchParams.searchText}`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.afterCreatedAt) {
|
||||||
|
conditions.push(orm.gt(schema.extensionData.createdAt, searchParams.afterCreatedAt))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.beforeCreatedAt) {
|
||||||
|
conditions.push(orm.lt(schema.extensionData.createdAt, searchParams.beforeCreatedAt))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ordering
|
||||||
|
if (searchParams.orderByCreatedAt) {
|
||||||
|
query.orderBy(
|
||||||
|
searchParams.orderByCreatedAt === SQLSortOrderEnum.Asc
|
||||||
|
? orm.asc(schema.extensionData.createdAt)
|
||||||
|
: orm.desc(schema.extensionData.createdAt)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.orderByUpdatedAt) {
|
||||||
|
query.orderBy(
|
||||||
|
searchParams.orderByUpdatedAt === SQLSortOrderEnum.Asc
|
||||||
|
? orm.asc(schema.extensionData.updatedAt)
|
||||||
|
: orm.desc(schema.extensionData.updatedAt)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add limit and offset
|
||||||
|
if (searchParams.limit) {
|
||||||
|
query.limit(searchParams.limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.offset) {
|
||||||
|
query.offset(searchParams.offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute query and convert results
|
||||||
|
const results = await query.where(orm.and(...conditions)).all()
|
||||||
|
return results.map((rawData) => {
|
||||||
|
// @ts-expect-error - rawData is unknown, but will be safe parsed with valibot
|
||||||
|
return convertRawExtDataToExtData(rawData)
|
||||||
|
}).filter((item): item is ExtData => item !== undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
// export async function getNCommands(n: number):
|
||||||
|
// export function createExtension(ext: {
|
||||||
|
// identifier: string
|
||||||
|
// version: string
|
||||||
|
// enabled?: boolean
|
||||||
|
// path?: string
|
||||||
|
// data?: any
|
||||||
|
// }) {
|
||||||
|
// return invoke<void>(generateJarvisPluginCommand("create_extension"), ext)
|
||||||
|
// }
|
@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import { db as dbCmd } from "@kksh/api/commands"
|
||||||
import * as schema from "@kksh/drizzle/schema"
|
import * as schema from "@kksh/drizzle/schema"
|
||||||
import * as dbCmd from "@kunkunapi/src/commands/db"
|
import { error } from "@tauri-apps/plugin-log"
|
||||||
import { drizzle } from "drizzle-orm/sqlite-proxy"
|
import { drizzle } from "drizzle-orm/sqlite-proxy"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,21 +16,22 @@ export const db = drizzle<typeof schema>(
|
|||||||
async (sql, params, method) => {
|
async (sql, params, method) => {
|
||||||
let rows: any = []
|
let rows: any = []
|
||||||
let results = []
|
let results = []
|
||||||
// console.log({
|
console.log({
|
||||||
// sql,
|
sql,
|
||||||
// params,
|
params,
|
||||||
// method
|
method
|
||||||
// })
|
})
|
||||||
|
console.log(sql)
|
||||||
// If the query is a SELECT, use the select method
|
// If the query is a SELECT, use the select method
|
||||||
if (isSelectQuery(sql)) {
|
if (isSelectQuery(sql)) {
|
||||||
rows = await dbCmd.select(sql, params).catch((e) => {
|
rows = await dbCmd.select(sql, params).catch((e) => {
|
||||||
console.error("SQL Error:", e)
|
error("SQL Error:", e)
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, use the execute method
|
// Otherwise, use the execute method
|
||||||
rows = await dbCmd.execute(sql, params).catch((e) => {
|
rows = await dbCmd.execute(sql, params).catch((e) => {
|
||||||
console.error("SQL Error:", e)
|
error("SQL Error:", e)
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
return { rows: [] }
|
return { rows: [] }
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import { systemCommands, systemCommandsFiltered } from "@/cmds/system"
|
import { systemCommands, systemCommandsFiltered } from "@/cmds/system"
|
||||||
import AppsCmds from "@/components/main/AppsCmds.svelte"
|
import AppsCmds from "@/components/main/AppsCmds.svelte"
|
||||||
import { i18n } from "@/i18n"
|
import { i18n } from "@/i18n"
|
||||||
|
import { getUniqueExtensionByIdentifier } from "@/orm/cmds"
|
||||||
import { db } from "@/orm/database"
|
import { db } from "@/orm/database"
|
||||||
import * as m from "@/paraglide/messages"
|
import * as m from "@/paraglide/messages"
|
||||||
import {
|
import {
|
||||||
@ -32,6 +33,7 @@
|
|||||||
SystemCmds
|
SystemCmds
|
||||||
} from "@kksh/ui/main"
|
} from "@kksh/ui/main"
|
||||||
import { cn } from "@kksh/ui/utils"
|
import { cn } from "@kksh/ui/utils"
|
||||||
|
import { Ext } from "@kunkunapi/src/models/extension"
|
||||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
|
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"
|
||||||
import { getCurrentWindow, Window } from "@tauri-apps/api/window"
|
import { getCurrentWindow, Window } from "@tauri-apps/api/window"
|
||||||
import { platform } from "@tauri-apps/plugin-os"
|
import { platform } from "@tauri-apps/plugin-os"
|
||||||
@ -46,6 +48,7 @@
|
|||||||
} from "lucide-svelte"
|
} from "lucide-svelte"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { Inspect } from "svelte-inspect-value"
|
import { Inspect } from "svelte-inspect-value"
|
||||||
|
import * as v from "valibot"
|
||||||
|
|
||||||
const win = getCurrentWindow()
|
const win = getCurrentWindow()
|
||||||
let inputEle: HTMLInputElement | null = $state(null)
|
let inputEle: HTMLInputElement | null = $state(null)
|
||||||
|
123
apps/desktop/src/routes/app/troubleshooters/orm/+page.svelte
Normal file
123
apps/desktop/src/routes/app/troubleshooters/orm/+page.svelte
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
getAllCmds,
|
||||||
|
getAllExtensions,
|
||||||
|
getExtensionDataById,
|
||||||
|
getUniqueExtensionByIdentifier,
|
||||||
|
getUniqueExtensionByPath,
|
||||||
|
searchExtensionData,
|
||||||
|
updateCmdByID
|
||||||
|
} from "@/orm/cmds"
|
||||||
|
import * as schema from "@kksh/drizzle/schema"
|
||||||
|
import { Button, Input } from "@kksh/svelte5"
|
||||||
|
import { CmdTypeEnum, Ext } from "@kunkunapi/src/models/extension"
|
||||||
|
import { SearchModeEnum } from "@kunkunapi/src/models/sql"
|
||||||
|
import { db } from "$lib/orm/database"
|
||||||
|
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("")
|
||||||
|
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>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Input class="" bind:value={searchText} placeholder="Search Text" />
|
||||||
|
<Button
|
||||||
|
class=""
|
||||||
|
onclick={async () => {
|
||||||
|
const _data = await searchExtensionData({
|
||||||
|
extId: 1,
|
||||||
|
searchMode: SearchModeEnum.FTS,
|
||||||
|
searchText: searchText,
|
||||||
|
limit: 10
|
||||||
|
})
|
||||||
|
console.log(_data)
|
||||||
|
data = _data
|
||||||
|
inspectTitle = "Search Results"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Search Extension Data
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Inspect name={inspectTitle} value={data} />
|
||||||
|
</main>
|
@ -6,6 +6,7 @@
|
|||||||
import { Constants } from "@kksh/ui"
|
import { Constants } from "@kksh/ui"
|
||||||
import { ArrowLeftIcon } from "lucide-svelte"
|
import { ArrowLeftIcon } from "lucide-svelte"
|
||||||
import AppWindow from "lucide-svelte/icons/app-window"
|
import AppWindow from "lucide-svelte/icons/app-window"
|
||||||
|
import DB from "lucide-svelte/icons/database"
|
||||||
import Loader from "lucide-svelte/icons/loader"
|
import Loader from "lucide-svelte/icons/loader"
|
||||||
import Network from "lucide-svelte/icons/network"
|
import Network from "lucide-svelte/icons/network"
|
||||||
|
|
||||||
@ -25,6 +26,11 @@
|
|||||||
title: m.troubleshooters_sidebar_mdns_debugger_title(),
|
title: m.troubleshooters_sidebar_mdns_debugger_title(),
|
||||||
url: i18n.resolveRoute("/app/troubleshooters/mdns-debugger"),
|
url: i18n.resolveRoute("/app/troubleshooters/mdns-debugger"),
|
||||||
icon: Network
|
icon: Network
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "ORM",
|
||||||
|
url: i18n.resolveRoute("/app/troubleshooters/orm"),
|
||||||
|
icon: DB
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
let currentItem = $state(items.find((item) => window.location.pathname === item.url))
|
let currentItem = $state(items.find((item) => window.location.pathname === item.url))
|
||||||
|
@ -18,8 +18,11 @@ export const Ext = v.object({
|
|||||||
extId: v.number(),
|
extId: v.number(),
|
||||||
identifier: v.string(),
|
identifier: v.string(),
|
||||||
version: v.string(),
|
version: v.string(),
|
||||||
enabled: v.boolean(),
|
enabled: v.pipe(
|
||||||
installed_at: v.string(),
|
v.number(),
|
||||||
|
v.transform((input) => Boolean(input))
|
||||||
|
),
|
||||||
|
installedAt: v.string(),
|
||||||
path: v.optional(v.nullable(v.string())),
|
path: v.optional(v.nullable(v.string())),
|
||||||
data: v.optional(v.any())
|
data: v.optional(v.any())
|
||||||
})
|
})
|
||||||
@ -46,7 +49,10 @@ export const ExtCmd = v.object({
|
|||||||
data: v.string(),
|
data: v.string(),
|
||||||
alias: v.optional(v.nullable(v.string())),
|
alias: v.optional(v.nullable(v.string())),
|
||||||
hotkey: v.optional(v.nullable(v.string())),
|
hotkey: v.optional(v.nullable(v.string())),
|
||||||
enabled: v.boolean()
|
enabled: v.pipe(
|
||||||
|
v.number(),
|
||||||
|
v.transform((input) => Boolean(input))
|
||||||
|
)
|
||||||
})
|
})
|
||||||
export type ExtCmd = v.InferOutput<typeof ExtCmd>
|
export type ExtCmd = v.InferOutput<typeof ExtCmd>
|
||||||
|
|
||||||
|
@ -11,3 +11,25 @@ bunx drizzle-kit pull
|
|||||||
We are using sqlite with fts5, which drizzle doesn't support yet, so pushing the schema will destroy the existing schema.
|
We are using sqlite with fts5, which drizzle doesn't support yet, so pushing the schema will destroy the existing schema.
|
||||||
|
|
||||||
We only use pulled schema to generate sql queries.
|
We only use pulled schema to generate sql queries.
|
||||||
|
|
||||||
|
## Update Schema
|
||||||
|
|
||||||
|
After `drizzle-kit pull` the schema may have problem with JSON type and boolean type.
|
||||||
|
|
||||||
|
Will need to manually update the following
|
||||||
|
|
||||||
|
### JSON
|
||||||
|
|
||||||
|
```diff lang="ts"
|
||||||
|
+ data: text({ mode: "json" }).notNull(),
|
||||||
|
+ metadata: text({ mode: "json" }),
|
||||||
|
- data: numeric().notNull(),
|
||||||
|
- metadata: numeric(),
|
||||||
|
```
|
||||||
|
|
||||||
|
### Boolean
|
||||||
|
|
||||||
|
```diff lang="ts"
|
||||||
|
+ enabled: integer({ mode: "boolean" }),
|
||||||
|
- enabled: numeric().default(sql`(TRUE)`),
|
||||||
|
```
|
||||||
|
@ -29,7 +29,8 @@ export const commands = sqliteTable("commands", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.references(() => extensions.extId, { onDelete: "cascade" }),
|
.references(() => extensions.extId, { onDelete: "cascade" }),
|
||||||
name: text().notNull(),
|
name: text().notNull(),
|
||||||
enabled: numeric().default(sql`(TRUE)`),
|
enabled: integer({ mode: "boolean" }),
|
||||||
|
// enabled: numeric().default(sql`(TRUE)`),
|
||||||
alias: text(),
|
alias: text(),
|
||||||
hotkey: text(),
|
hotkey: text(),
|
||||||
type: text().notNull(),
|
type: text().notNull(),
|
||||||
@ -42,8 +43,10 @@ export const extensionData = sqliteTable("extension_data", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.references(() => extensions.extId, { onDelete: "cascade" }),
|
.references(() => extensions.extId, { onDelete: "cascade" }),
|
||||||
dataType: text("data_type").notNull(),
|
dataType: text("data_type").notNull(),
|
||||||
data: numeric().notNull(),
|
// data: text({ mode: "json" }).notNull(),
|
||||||
metadata: numeric(),
|
// metadata: text({ mode: "json" }),
|
||||||
|
data: text("data").notNull(),
|
||||||
|
metadata: text("metadata"),
|
||||||
searchText: text("search_text"),
|
searchText: text("search_text"),
|
||||||
createdAt: numeric("created_at").default(sql`(CURRENT_TIMESTAMP)`),
|
createdAt: numeric("created_at").default(sql`(CURRENT_TIMESTAMP)`),
|
||||||
updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`)
|
updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`)
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
"remark-math": "^6.0.0",
|
"remark-math": "^6.0.0",
|
||||||
"shiki-magic-move": "^0.5.2",
|
"shiki-magic-move": "^0.5.2",
|
||||||
"svelte-exmarkdown": "^4.0.3",
|
"svelte-exmarkdown": "^4.0.3",
|
||||||
"svelte-inspect-value": "^0.3.0",
|
"svelte-inspect-value": "^0.5.0",
|
||||||
"svelte-motion": "^0.12.2",
|
"svelte-motion": "^0.12.2",
|
||||||
"valibot": "^1.0.0"
|
"valibot": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@ -279,8 +279,8 @@ importers:
|
|||||||
specifier: ^7.7.1
|
specifier: ^7.7.1
|
||||||
version: 7.7.1
|
version: 7.7.1
|
||||||
svelte-inspect-value:
|
svelte-inspect-value:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.5.0
|
||||||
version: 0.3.0(svelte@5.20.5)
|
version: 0.5.0(svelte@5.20.5)
|
||||||
svelte-sonner:
|
svelte-sonner:
|
||||||
specifier: ^0.3.28
|
specifier: ^0.3.28
|
||||||
version: 0.3.28(svelte@5.20.5)
|
version: 0.3.28(svelte@5.20.5)
|
||||||
@ -1290,8 +1290,8 @@ importers:
|
|||||||
specifier: ^4.0.3
|
specifier: ^4.0.3
|
||||||
version: 4.0.3(svelte@5.20.5)
|
version: 4.0.3(svelte@5.20.5)
|
||||||
svelte-inspect-value:
|
svelte-inspect-value:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.5.0
|
||||||
version: 0.3.0(svelte@5.20.5)
|
version: 0.5.0(svelte@5.20.5)
|
||||||
svelte-motion:
|
svelte-motion:
|
||||||
specifier: ^0.12.2
|
specifier: ^0.12.2
|
||||||
version: 0.12.2(svelte@5.20.5)
|
version: 0.12.2(svelte@5.20.5)
|
||||||
@ -11715,8 +11715,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^5.1.3
|
svelte: ^5.1.3
|
||||||
|
|
||||||
svelte-inspect-value@0.3.0:
|
svelte-inspect-value@0.5.0:
|
||||||
resolution: {integrity: sha512-nHv+7+FRePs86sgL2I8jlbSrs8/uJmHJ2uxnMk9tVipWdZYYcmGhsmU+7U8lm/1RAZFS63/xSKdceMDyE09y0A==}
|
resolution: {integrity: sha512-ZWbu/TZl/gGAPe8Xjmg0YvERSpEC+q07HV8m0xhp51auTNh8mjaf07bcmcl0coBb0wnJqcAB4uWJ1GDdtGQrQw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^5.19.0
|
svelte: ^5.19.0
|
||||||
|
|
||||||
@ -25530,7 +25530,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
svelte-inspect-value@0.3.0(svelte@5.20.5):
|
svelte-inspect-value@0.5.0(svelte@5.20.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
esm-env: 1.2.2
|
esm-env: 1.2.2
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user