2022-08-11 14:50:05 +02:00
|
|
|
import { 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
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
interface RedisConfig {
|
|
|
|
host: string
|
|
|
|
port: number
|
|
|
|
username: string
|
|
|
|
password?: string
|
|
|
|
}
|
2022-03-31 11:56:16 +02:00
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
const SCHEMA: Integration = {
|
|
|
|
docs: "https://redis.io/docs/",
|
|
|
|
description: "",
|
|
|
|
friendlyName: "Redis",
|
|
|
|
type: "Non-relational",
|
|
|
|
datasource: {
|
|
|
|
host: {
|
|
|
|
type: "string",
|
|
|
|
required: true,
|
|
|
|
default: "localhost",
|
|
|
|
},
|
|
|
|
port: {
|
|
|
|
type: "number",
|
|
|
|
required: true,
|
|
|
|
default: 6379,
|
|
|
|
},
|
|
|
|
username: {
|
|
|
|
type: "string",
|
|
|
|
required: false,
|
|
|
|
},
|
|
|
|
password: {
|
|
|
|
type: "password",
|
|
|
|
required: false,
|
2022-03-31 11:56:16 +02:00
|
|
|
},
|
2022-08-12 18:03:06 +02:00
|
|
|
},
|
|
|
|
query: {
|
|
|
|
create: {
|
|
|
|
type: QueryType.FIELDS,
|
|
|
|
fields: {
|
|
|
|
key: {
|
|
|
|
type: DatasourceFieldType.STRING,
|
|
|
|
required: true,
|
2022-03-31 16:44:06 +02:00
|
|
|
},
|
2022-08-12 18:03:06 +02:00
|
|
|
value: {
|
|
|
|
type: DatasourceFieldType.STRING,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
ttl: {
|
|
|
|
type: DatasourceFieldType.NUMBER,
|
2022-03-31 16:44:06 +02:00
|
|
|
},
|
|
|
|
},
|
2022-08-12 18:03:06 +02:00
|
|
|
},
|
|
|
|
read: {
|
|
|
|
readable: true,
|
|
|
|
type: QueryType.FIELDS,
|
|
|
|
fields: {
|
|
|
|
key: {
|
|
|
|
type: DatasourceFieldType.STRING,
|
|
|
|
required: true,
|
2022-03-31 16:44:06 +02:00
|
|
|
},
|
|
|
|
},
|
2022-08-12 18:03:06 +02:00
|
|
|
},
|
|
|
|
delete: {
|
|
|
|
type: QueryType.FIELDS,
|
|
|
|
fields: {
|
|
|
|
key: {
|
|
|
|
type: DatasourceFieldType.STRING,
|
|
|
|
required: true,
|
|
|
|
},
|
2022-03-31 11:56:16 +02:00
|
|
|
},
|
|
|
|
},
|
2022-08-12 18:03:06 +02:00
|
|
|
command: {
|
|
|
|
readable: true,
|
|
|
|
displayName: "Redis Command",
|
|
|
|
type: QueryType.JSON,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2022-03-31 11:56:16 +02:00
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
class RedisIntegration {
|
|
|
|
private readonly config: RedisConfig
|
|
|
|
private client: any
|
2022-03-31 16:44:06 +02:00
|
|
|
|
2022-08-12 18:03: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,
|
|
|
|
})
|
|
|
|
}
|
2022-03-31 16:44:06 +02:00
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
async disconnect() {
|
2023-03-27 20:38:49 +02:00
|
|
|
return this.client.quit()
|
2022-08-12 18:03:06 +02:00
|
|
|
}
|
2022-03-31 11:56:16 +02:00
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
async redisContext(query: Function) {
|
|
|
|
try {
|
|
|
|
return await query()
|
|
|
|
} catch (err) {
|
|
|
|
throw new Error(`Redis error: ${err}`)
|
|
|
|
} finally {
|
2022-09-07 13:40:45 +02:00
|
|
|
await this.disconnect()
|
2022-03-31 16:44:06 +02:00
|
|
|
}
|
2022-08-12 18:03:06 +02:00
|
|
|
}
|
2022-03-31 16:44:06 +02:00
|
|
|
|
2022-08-12 18:03: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
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
async read(query: { key: string }) {
|
|
|
|
return this.redisContext(async () => {
|
2022-09-07 13:40:45 +02:00
|
|
|
return await this.client.get(query.key)
|
2022-08-12 18:03:06 +02:00
|
|
|
})
|
|
|
|
}
|
2022-03-31 16:44:06 +02:00
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
async delete(query: { key: string }) {
|
|
|
|
return this.redisContext(async () => {
|
2022-09-07 13:40:45 +02:00
|
|
|
return await this.client.del(query.key)
|
2022-08-12 18:03:06 +02:00
|
|
|
})
|
2022-03-31 11:56:16 +02:00
|
|
|
}
|
|
|
|
|
2022-08-12 18:03:06 +02:00
|
|
|
async command(query: { json: string }) {
|
|
|
|
return this.redisContext(async () => {
|
2022-09-07 13:40:45 +02:00
|
|
|
// commands split line by line
|
|
|
|
const commands = query.json.trim().split("\n")
|
|
|
|
let pipelineCommands = []
|
2022-09-02 19:35:06 +02:00
|
|
|
|
2022-09-07 13:40:45 +02:00
|
|
|
// 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)
|
2022-08-12 18:03:06 +02:00
|
|
|
}
|
2022-09-02 19:35:06 +02:00
|
|
|
|
2022-09-07 13:40:45 +02:00
|
|
|
const pipeline = this.client.pipeline(pipelineCommands)
|
|
|
|
const result = await pipeline.exec()
|
2022-09-02 19:35:06 +02:00
|
|
|
|
2022-09-07 13:40:45 +02:00
|
|
|
return result.map((output: string | string[]) => output[1])
|
2022-08-12 18:03:06 +02:00
|
|
|
})
|
2022-03-31 11:56:16 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-12 18:03:06 +02:00
|
|
|
|
|
|
|
export default {
|
|
|
|
schema: SCHEMA,
|
|
|
|
integration: RedisIntegration,
|
|
|
|
}
|