Merge pull request #653 from LinuxSuRen/feat/iotdb

feat: add iotdb support
This commit is contained in:
Rick 2025-03-27 17:17:37 +08:00 committed by GitHub
commit 34eeb2a253
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 650 additions and 598 deletions

View File

@ -6,13 +6,14 @@ import type { Pair } from './types'
import { ElMessage } from 'element-plus'
import { Codemirror } from 'vue-codemirror'
import HistoryInput from '../components/HistoryInput.vue'
import type { Ref } from 'vue'
const stores = ref([] as Store[])
const stores: Ref<Store[]> = ref([])
const kind = ref('')
const store = ref('')
const sqlQuery = ref('')
const queryResult = ref([] as any[])
const queryResultAsJSON= ref('')
const queryResultAsJSON = ref('')
const columns = ref([] as string[])
const queryTip = ref('')
const loadingStores = ref(true)
@ -20,7 +21,10 @@ const dataFormat = ref('table')
const dataFormatOptions = ['table', 'json']
const queryDataMeta = ref({} as QueryDataMeta)
const tablesTree = ref([])
interface TreeItem {
label: string
}
const tablesTree = ref([] as TreeItem[])
watch(store, (s) => {
kind.value = ''
stores.value.forEach((e: Store) => {
@ -60,6 +64,7 @@ const queryTables = () => {
watch(kind, (k) => {
switch (k) {
case 'atest-store-orm':
case 'atest-store-iotdb':
queryTip.value = 'Enter SQL query'
executeQuery()
break;
@ -144,6 +149,7 @@ const executeQuery = async () => {
const data = await API.DataQueryAsync(store.value, kind.value, queryDataMeta.value.currentDatabase, sqlQuery.value);
switch (kind.value) {
case 'atest-store-orm':
case 'atest-store-iotdb':
ormDataHandler(data)
success = true
break;
@ -172,60 +178,64 @@ const executeQuery = async () => {
</script>
<template>
<div>
<el-container style="height: calc(100vh - 50px);">
<el-aside v-if="kind === 'atest-store-orm'">
<el-scrollbar>
<el-select v-model="queryDataMeta.currentDatabase" placeholder="Select database" @change="queryTables" filterable>
<el-option v-for="item in queryDataMeta.databases" :key="item" :label="item"
:value="item"></el-option>
</el-select>
<el-tree :data="tablesTree" node-key="label" @node-click="queryDataFromTable" highlight-current draggable/>
</el-scrollbar>
</el-aside>
<el-container>
<el-header>
<el-form @submit.prevent="executeQuery">
<el-row :gutter="10">
<el-col :span="4">
<el-form-item>
<el-select v-model="store" placeholder="Select store" filterable :loading="loadingStores">
<el-option v-for="item in stores" :key="item.name" :label="item.name"
:value="item.name" :disabled="!item.ready" :kind="item.kind.name"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item>
<HistoryInput :placeholder="queryTip" :callback="executeQuery" v-model="sqlQuery"/>
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item>
<el-button type="primary" @click="executeQuery">Execute</el-button>
</el-form-item>
</el-col>
<el-col :span="2">
<el-select v-model="dataFormat" placeholder="Select data format">
<el-option v-for="item in dataFormatOptions" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-col>
</el-row>
</el-form>
</el-header>
<el-main>
<div style="display: flex; gap: 8px;">
<el-tag type="primary" v-if="queryResult.length > 0">{{ queryResult.length }} rows</el-tag>
<el-tag type="primary" v-if="queryDataMeta.duration">{{ queryDataMeta.duration }}</el-tag>
<el-tag type="primary" v-for="label in queryDataMeta.labels">{{ label.value }}</el-tag>
</div>
<el-table :data="queryResult" stripe v-if="dataFormat === 'table'">
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col" sortable/>
</el-table>
<Codemirror v-else-if="dataFormat === 'json'"
v-model="queryResultAsJSON"/>
</el-main>
</el-container>
</el-container>
</div>
<div>
<el-container style="height: calc(100vh - 50px);">
<el-aside v-if="kind === 'atest-store-orm' || kind === 'atest-store-iotdb'">
<el-scrollbar>
<el-select v-model="queryDataMeta.currentDatabase" placeholder="Select database"
@change="queryTables" filterable>
<el-option v-for="item in queryDataMeta.databases" :key="item" :label="item"
:value="item"></el-option>
</el-select>
<el-tree :data="tablesTree" node-key="label" @node-click="queryDataFromTable" highlight-current
draggable />
</el-scrollbar>
</el-aside>
<el-container>
<el-header>
<el-form @submit.prevent="executeQuery">
<el-row :gutter="10">
<el-col :span="4">
<el-form-item>
<el-select v-model="store" placeholder="Select store" filterable
:loading="loadingStores">
<el-option v-for="item in stores" :key="item.name" :label="item.name"
:value="item.name" :disabled="!item.ready"
:kind="item.kind.name"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item>
<HistoryInput :placeholder="queryTip" :callback="executeQuery" v-model="sqlQuery" />
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item>
<el-button type="primary" @click="executeQuery">Execute</el-button>
</el-form-item>
</el-col>
<el-col :span="2">
<el-select v-model="dataFormat" placeholder="Select data format">
<el-option v-for="item in dataFormatOptions" :key="item" :label="item"
:value="item"></el-option>
</el-select>
</el-col>
</el-row>
</el-form>
</el-header>
<el-main>
<div style="display: flex; gap: 8px;">
<el-tag type="primary" v-if="queryResult.length > 0">{{ queryResult.length }} rows</el-tag>
<el-tag type="primary" v-if="queryDataMeta.duration">{{ queryDataMeta.duration }}</el-tag>
<el-tag type="primary" v-for="label in queryDataMeta.labels">{{ label.value }}</el-tag>
</div>
<el-table :data="queryResult" stripe v-if="dataFormat === 'table'">
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col" sortable />
</el-table>
<Codemirror v-else-if="dataFormat === 'json'" v-model="queryResultAsJSON" />
</el-main>
</el-container>
</el-container>
</div>
</template>

View File

@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {SupportedExtension, SupportedExtensions} from "../store";
import { SupportedExtension, SupportedExtensions } from "../store";
describe("SupportedExtensions", () => {
test('length check', () => {
const extensions = SupportedExtensions()
expect(extensions.length).toBe(6)
expect(extensions.length).toBe(7)
})
for (const extension of SupportedExtensions()) {

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,11 @@ const storeExtensions = [
}],
link: 'https://github.com/LinuxSuRen/atest-ext-store-orm'
},
{
name: 'atest-store-iotdb',
params: [],
link: 'https://github.com/LinuxSuRen/atest-ext-store-iotdb'
},
{
name: 'atest-store-etcd',
params: [],

View File

@ -8,6 +8,7 @@ Ports in extensions:
| Store | [git](https://github.com/LinuxSuRen/atest-ext-store-git) | 4074 |
| Store | [mongodb](https://github.com/LinuxSuRen/atest-ext-store-mongodb) | 4075 |
| Store | [redis](https://github.com/LinuxSuRen/atest-ext-store-redis) | |
| Store | [iotdb](https://github.com/LinuxSuRen/atest-ext-store-iotdb) | |
| Monitor | [docker-monitor](https://github.com/LinuxSuRen/atest-ext-monitor-docker) | |
| Agent | [collector](https://github.com/LinuxSuRen/atest-ext-collector) | |
| Secret | [Vault](https://github.com/LinuxSuRen/api-testing-vault-extension) | |
@ -20,6 +21,7 @@ Ports in extensions:
* Finally, add the extension's name into function [SupportedExtensions](../console/atest-ui/src/views/store.ts).
## Naming conventions
Please follow the following conventions if you want to add a new store extension:
`store-xxx`

View File

@ -1157,6 +1157,9 @@ func (s *server) GetStores(ctx context.Context, in *Empty) (reply *Stores, err e
}
for _, item := range stores {
grpcStore := ToGRPCStore(item)
if item.Disabled {
continue
}
storeStatus, sErr := s.VerifyStore(ctx, &SimpleQuery{Name: item.Name})
grpcStore.Ready = sErr == nil && storeStatus.Ready