budibase/packages/server/src/integrations/redis.ts

195 lines
4.2 KiB
TypeScript
Raw Normal View History

import {
ConnectionInfo,
DatasourceFeature,
DatasourceFieldType,
Integration,
QueryType,
} from "@budibase/types"
2022-03-31 16:44:06 +02:00
import Redis from "ioredis"
2022-03-31 11:56:16 +02:00
interface RedisConfig {
host: string
port: number
username: string
password?: string
db?: number
}
2022-03-31 11:56:16 +02:00
const SCHEMA: Integration = {
docs: "https://redis.io/docs/",
description:
"Redis is a caching tool, providing powerful key-value store capabilities.",
friendlyName: "Redis",
type: "Non-relational",
2023-05-24 10:50:51 +02:00
features: {
[DatasourceFeature.CONNECTION_CHECKING]: true,
},
datasource: {
host: {
2023-06-28 16:16:47 +02:00
type: DatasourceFieldType.STRING,
required: true,
default: "localhost",
},
port: {
2023-06-28 16:16:47 +02:00
type: DatasourceFieldType.NUMBER,
required: true,
default: 6379,
},
username: {
2023-06-28 16:16:47 +02:00
type: DatasourceFieldType.STRING,
required: false,
},
password: {
2023-06-28 16:16:47 +02:00
type: DatasourceFieldType.PASSWORD,
required: false,
2022-03-31 11:56:16 +02:00
},
db: {
2023-06-28 16:16:47 +02:00
type: DatasourceFieldType.NUMBER,
required: false,
display: "DB",
default: 0,
},
},
query: {
create: {
type: QueryType.FIELDS,
fields: {
key: {
type: DatasourceFieldType.STRING,
required: true,
2022-03-31 16:44:06 +02:00
},
value: {
type: DatasourceFieldType.STRING,
required: true,
},
ttl: {
type: DatasourceFieldType.NUMBER,
2022-03-31 16:44:06 +02:00
},
},
},
read: {
readable: true,
type: QueryType.FIELDS,
fields: {
key: {
type: DatasourceFieldType.STRING,
required: true,
2022-03-31 16:44:06 +02:00
},
},
},
delete: {
type: QueryType.FIELDS,
fields: {
key: {
type: DatasourceFieldType.STRING,
required: true,
},
2022-03-31 11:56:16 +02:00
},
},
command: {
readable: true,
displayName: "Redis Command",
type: QueryType.JSON,
},
},
}
2022-03-31 11:56:16 +02:00
class RedisIntegration {
private readonly config: RedisConfig
2023-05-15 10:16:06 +02:00
private client
2022-03-31 16:44:06 +02:00
constructor(config: RedisConfig) {
this.config = config
this.client = new Redis({
host: this.config.host,
port: this.config.port,
username: this.config.username,
password: this.config.password,
db: this.config.db,
})
}
2022-03-31 16:44:06 +02:00
2023-05-15 10:16:06 +02:00
async testConnection() {
const response: ConnectionInfo = {
connected: false,
}
2023-05-15 10:16:06 +02:00
try {
await this.client.ping()
response.connected = true
2023-05-15 10:16:06 +02:00
} catch (e: any) {
response.error = e.message as string
2023-05-15 10:16:06 +02:00
} finally {
await this.disconnect()
}
return response
2023-05-15 10:16:06 +02:00
}
async disconnect() {
return this.client.quit()
}
2022-03-31 11:56:16 +02:00
async redisContext(query: Function) {
try {
return await query()
} catch (err) {
throw new Error(`Redis error: ${err}`)
} finally {
await this.disconnect()
2022-03-31 16:44:06 +02:00
}
}
2022-03-31 16:44:06 +02:00
async create(query: { key: string; value: string; ttl: number }) {
return this.redisContext(async () => {
const response = await this.client.set(query.key, query.value)
if (query.ttl) {
await this.client.expire(query.key, query.ttl)
}
return response
})
}
2022-03-31 16:44:06 +02:00
async read(query: { key: string }) {
return this.redisContext(async () => {
return await this.client.get(query.key)
})
}
2022-03-31 16:44:06 +02:00
async delete(query: { key: string }) {
return this.redisContext(async () => {
return await this.client.del(query.key)
})
2022-03-31 11:56:16 +02:00
}
async command(query: { json: string }) {
return this.redisContext(async () => {
// commands split line by line
const commands = query.json.trim().split("\n")
let pipelineCommands = []
// process each command separately
for (let command of commands) {
const tokenised = command.trim().split(" ")
// Pipeline only accepts lower case commands
tokenised[0] = tokenised[0].toLowerCase()
pipelineCommands.push(tokenised)
}
const pipeline = this.client.pipeline(pipelineCommands)
const result = await pipeline.exec()
2023-06-01 12:10:39 +02:00
return result?.map((output: any) => {
if (typeof output === "string") {
return output
} else if (Array.isArray(output)) {
return output[1]
}
})
})
2022-03-31 11:56:16 +02:00
}
}
export default {
schema: SCHEMA,
integration: RedisIntegration,
}