Merge branch 'develop' of github.com:Budibase/budibase into plugins-dev-experience
This commit is contained in:
commit
fffa5754f3
|
@ -69,6 +69,13 @@ jobs:
|
|||
env:
|
||||
KUBECONFIG_FILE: '${{ secrets.RELEASE_KUBECONFIG }}'
|
||||
|
||||
- name: Re roll the services
|
||||
uses: actions-hub/kubectl@master
|
||||
env:
|
||||
KUBE_CONFIG: ${{ secrets.RELEASE_KUBECONFIG }}
|
||||
with:
|
||||
args: rollout restart deployment proxy-service -n budibase && kubectl rollout restart deployment app-service -n budibase && kubectl rollout restart deployment worker-service -n budibase
|
||||
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v4.0.0
|
||||
with:
|
||||
|
|
|
@ -121,6 +121,13 @@ jobs:
|
|||
env:
|
||||
KUBECONFIG_FILE: '${{ secrets.RELEASE_KUBECONFIG }}'
|
||||
|
||||
- name: Re roll the services
|
||||
uses: actions-hub/kubectl@master
|
||||
env:
|
||||
KUBE_CONFIG: ${{ secrets.RELEASE_KUBECONFIG }}
|
||||
with:
|
||||
args: rollout restart deployment proxy-service -n budibase && kubectl rollout restart deployment app-service -n budibase && kubectl rollout restart deployment worker-service -n budibase
|
||||
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v4.0.0
|
||||
with:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "1.2.39-alpha.5",
|
||||
"@budibase/types": "1.2.39-alpha.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-sdk": "2.1030.0",
|
||||
"bcrypt": "5.0.1",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||
"@budibase/string-templates": "1.2.39-alpha.5",
|
||||
"@budibase/string-templates": "1.2.39-alpha.7",
|
||||
"@spectrum-css/actionbutton": "^1.0.1",
|
||||
"@spectrum-css/actiongroup": "^1.0.1",
|
||||
"@spectrum-css/avatar": "^3.0.2",
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
$: toggleOption = makeToggleOption(selectedLookupMap, value)
|
||||
|
||||
const getFieldText = (value, map, placeholder) => {
|
||||
if (value?.length) {
|
||||
if (Array.isArray(value) && value.length > 0) {
|
||||
if (!map) {
|
||||
return ""
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
|||
|
||||
const getSelectedLookupMap = value => {
|
||||
let map = {}
|
||||
if (value?.length) {
|
||||
if (Array.isArray(value) && value.length > 0) {
|
||||
value.forEach(option => {
|
||||
if (option) {
|
||||
map[option] = true
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -69,10 +69,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.2.39-alpha.5",
|
||||
"@budibase/client": "1.2.39-alpha.5",
|
||||
"@budibase/frontend-core": "1.2.39-alpha.5",
|
||||
"@budibase/string-templates": "1.2.39-alpha.5",
|
||||
"@budibase/bbui": "1.2.39-alpha.7",
|
||||
"@budibase/client": "1.2.39-alpha.7",
|
||||
"@budibase/frontend-core": "1.2.39-alpha.7",
|
||||
"@budibase/string-templates": "1.2.39-alpha.7",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -167,6 +167,7 @@
|
|||
{/if}
|
||||
<HideAutocolumnButton bind:hideAutocolumns />
|
||||
<ImportButton
|
||||
disabled={$tables.selected?._id === "ta_users"}
|
||||
tableId={$tables.selected?._id}
|
||||
on:updaterows={onUpdateRows}
|
||||
/>
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
import ImportModal from "../modals/ImportModal.svelte"
|
||||
|
||||
export let tableId
|
||||
export let disabled
|
||||
|
||||
let modal
|
||||
</script>
|
||||
|
||||
<ActionButton icon="DataUpload" size="S" quiet on:click={modal.show}>
|
||||
<ActionButton icon="DataUpload" size="S" quiet on:click={modal.show} {disabled}>
|
||||
Import
|
||||
</ActionButton>
|
||||
<Modal bind:this={modal}>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
Body,
|
||||
Button,
|
||||
Combobox,
|
||||
Multiselect,
|
||||
DatePicker,
|
||||
DrawerContent,
|
||||
Icon,
|
||||
|
@ -97,6 +98,16 @@
|
|||
if (expression.noValue) {
|
||||
expression.value = null
|
||||
}
|
||||
if (
|
||||
operator === Constants.OperatorOptions.In.value &&
|
||||
!Array.isArray(expression.value)
|
||||
) {
|
||||
if (expression.value) {
|
||||
expression.value = [expression.value]
|
||||
} else {
|
||||
expression.value = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getFieldOptions = field => {
|
||||
|
@ -169,7 +180,13 @@
|
|||
/>
|
||||
{:else if ["string", "longform", "number", "formula"].includes(filter.type)}
|
||||
<Input disabled={filter.noValue} bind:value={filter.value} />
|
||||
{:else if ["options", "array"].includes(filter.type)}
|
||||
{:else if filter.type === "array" || (filter.type === "options" && filter.operator === "oneOf")}
|
||||
<Multiselect
|
||||
disabled={filter.noValue}
|
||||
options={getFieldOptions(filter.field)}
|
||||
bind:value={filter.value}
|
||||
/>
|
||||
{:else if filter.type === "options"}
|
||||
<Combobox
|
||||
disabled={filter.noValue}
|
||||
options={getFieldOptions(filter.field)}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.2.39-alpha.5",
|
||||
"@budibase/frontend-core": "1.2.39-alpha.5",
|
||||
"@budibase/string-templates": "1.2.39-alpha.5",
|
||||
"@budibase/bbui": "1.2.39-alpha.7",
|
||||
"@budibase/frontend-core": "1.2.39-alpha.7",
|
||||
"@budibase/string-templates": "1.2.39-alpha.7",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.2.39-alpha.5",
|
||||
"@budibase/bbui": "1.2.39-alpha.7",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -39,13 +39,17 @@ export const OperatorOptions = {
|
|||
label: "Contains",
|
||||
},
|
||||
NotContains: {
|
||||
value: "notEqual",
|
||||
value: "notContains",
|
||||
label: "Does Not Contain",
|
||||
},
|
||||
In: {
|
||||
value: "oneOf",
|
||||
label: "Is in",
|
||||
},
|
||||
ContainsAny: {
|
||||
value: "containsAny",
|
||||
label: "Has any",
|
||||
},
|
||||
}
|
||||
|
||||
// Cookie names
|
||||
|
|
|
@ -32,9 +32,9 @@ export const getValidOperatorsForType = type => {
|
|||
} else if (type === "number") {
|
||||
return numOps
|
||||
} else if (type === "options") {
|
||||
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
||||
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty, Op.In]
|
||||
} else if (type === "array") {
|
||||
return [Op.Contains, Op.NotContains, Op.Empty, Op.NotEmpty]
|
||||
return [Op.Contains, Op.NotContains, Op.Empty, Op.NotEmpty, Op.ContainsAny]
|
||||
} else if (type === "boolean") {
|
||||
return [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty]
|
||||
} else if (type === "longform") {
|
||||
|
@ -96,6 +96,7 @@ export const buildLuceneQuery = filter => {
|
|||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {},
|
||||
containsAny: {},
|
||||
}
|
||||
if (Array.isArray(filter)) {
|
||||
filter.forEach(expression => {
|
||||
|
@ -128,6 +129,13 @@ export const buildLuceneQuery = filter => {
|
|||
if (type === "boolean") {
|
||||
value = `${value}`?.toLowerCase() === "true"
|
||||
}
|
||||
if (
|
||||
["contains", "notContains", "containsAny"].includes(operator) &&
|
||||
type === "array" &&
|
||||
typeof value === "string"
|
||||
) {
|
||||
value = value.split(",")
|
||||
}
|
||||
if (operator.startsWith("range")) {
|
||||
const minint =
|
||||
SqlNumberTypeRangeMap[externalType]?.min || Number.MIN_SAFE_INTEGER
|
||||
|
@ -244,6 +252,18 @@ export const runLuceneQuery = (docs, query) => {
|
|||
return !testValue?.includes(docValue)
|
||||
})
|
||||
|
||||
const containsAny = match("containsAny", (docValue, testValue) => {
|
||||
return !docValue?.includes(...testValue)
|
||||
})
|
||||
|
||||
const contains = match("contains", (docValue, testValue) => {
|
||||
return !testValue?.every(item => docValue?.includes(item))
|
||||
})
|
||||
|
||||
const notContains = match("notContains", (docValue, testValue) => {
|
||||
return testValue?.every(item => docValue?.includes(item))
|
||||
})
|
||||
|
||||
// Match a document against all criteria
|
||||
const docMatch = doc => {
|
||||
return (
|
||||
|
@ -254,7 +274,10 @@ export const runLuceneQuery = (docs, query) => {
|
|||
notEqualMatch(doc) &&
|
||||
emptyMatch(doc) &&
|
||||
notEmptyMatch(doc) &&
|
||||
oneOf(doc)
|
||||
oneOf(doc) &&
|
||||
contains(doc) &&
|
||||
containsAny(doc) &&
|
||||
notContains(doc)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -77,11 +77,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "1.2.39-alpha.5",
|
||||
"@budibase/client": "1.2.39-alpha.5",
|
||||
"@budibase/pro": "1.2.39-alpha.5",
|
||||
"@budibase/string-templates": "1.2.39-alpha.5",
|
||||
"@budibase/types": "1.2.39-alpha.5",
|
||||
"@budibase/backend-core": "1.2.39-alpha.7",
|
||||
"@budibase/client": "1.2.39-alpha.7",
|
||||
"@budibase/pro": "1.2.39-alpha.7",
|
||||
"@budibase/string-templates": "1.2.39-alpha.7",
|
||||
"@budibase/types": "1.2.39-alpha.7",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -21,6 +21,8 @@ class QueryBuilder {
|
|||
notEmpty: {},
|
||||
oneOf: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
containsAny: {},
|
||||
...base,
|
||||
}
|
||||
this.limit = 50
|
||||
|
@ -126,6 +128,16 @@ class QueryBuilder {
|
|||
return this
|
||||
}
|
||||
|
||||
addNotContains(key, value) {
|
||||
this.query.notContains[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addContainsAny(key, value) {
|
||||
this.query.containsAny[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocesses a value before going into a lucene search.
|
||||
* Transforms strings to lowercase and wraps strings and bools in quotes.
|
||||
|
@ -171,11 +183,29 @@ class QueryBuilder {
|
|||
return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
||||
}
|
||||
|
||||
const contains = (key, value) => {
|
||||
if (!value && value !== 0) {
|
||||
const contains = (key, value, mode = "AND") => {
|
||||
if (Array.isArray(value) && value.length === 0) {
|
||||
return null
|
||||
}
|
||||
return `${key}:${builder.preprocess(value, { escape: true })}`
|
||||
if (!Array.isArray(value)) {
|
||||
return `${key}:${value}`
|
||||
}
|
||||
let statement = `${builder.preprocess(value[0], { escape: true })}`
|
||||
for (let i = 1; i < value.length; i++) {
|
||||
statement += ` ${mode} ${builder.preprocess(value[i], {
|
||||
escape: true,
|
||||
})}`
|
||||
}
|
||||
return `${key}:(${statement})`
|
||||
}
|
||||
|
||||
const notContains = (key, value) => {
|
||||
const allPrefix = allOr === "" ? "*:* AND" : ""
|
||||
return allPrefix + "NOT " + contains(key, value)
|
||||
}
|
||||
|
||||
const containsAny = (key, value) => {
|
||||
return contains(key, value, "OR")
|
||||
}
|
||||
|
||||
const oneOf = (key, value) => {
|
||||
|
@ -278,6 +308,12 @@ class QueryBuilder {
|
|||
if (this.query.contains) {
|
||||
build(this.query.contains, contains)
|
||||
}
|
||||
if (this.query.notContains) {
|
||||
build(this.query.notContains, notContains)
|
||||
}
|
||||
if (this.query.containsAny) {
|
||||
build(this.query.containsAny, containsAny)
|
||||
}
|
||||
// make sure table ID is always added as an AND
|
||||
if (tableId) {
|
||||
query = `(${query})`
|
||||
|
|
|
@ -129,9 +129,10 @@ describe("internal search", () => {
|
|||
const response = await search.paginatedSearch({
|
||||
contains: {
|
||||
"column": "a",
|
||||
"colArr": [1, 2, 3],
|
||||
},
|
||||
}, PARAMS)
|
||||
checkLucene(response, `*:* AND column:a`, PARAMS)
|
||||
checkLucene(response, `*:* AND column:a AND colArr:(1 AND 2 AND 3)`, PARAMS)
|
||||
})
|
||||
|
||||
it("test multiple of same column", async () => {
|
||||
|
@ -154,4 +155,22 @@ describe("internal search", () => {
|
|||
}, PARAMS)
|
||||
checkLucene(response, `*:* AND 1\\:column:"a"`, PARAMS)
|
||||
})
|
||||
|
||||
it("test containsAny query", async () => {
|
||||
const response = await search.paginatedSearch({
|
||||
containsAny: {
|
||||
"column": ["a", "b", "c"]
|
||||
},
|
||||
}, PARAMS)
|
||||
checkLucene(response, `*:* AND column:(a OR b OR c)`, PARAMS)
|
||||
})
|
||||
|
||||
it("test notContains query", async () => {
|
||||
const response = await search.paginatedSearch({
|
||||
notContains: {
|
||||
"column": ["a", "b", "c"]
|
||||
},
|
||||
}, PARAMS)
|
||||
checkLucene(response, `*:* AND NOT column:(a AND b AND c)`, PARAMS)
|
||||
})
|
||||
})
|
|
@ -159,6 +159,61 @@ class InternalBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
const contains = (mode: object, any: boolean = false) => {
|
||||
const fnc = allOr ? "orWhere" : "where"
|
||||
const rawFnc = `${fnc}Raw`
|
||||
const not = mode === filters?.notContains ? "NOT " : ""
|
||||
function stringifyArray(value: Array<any>, quoteStyle = '"'): string {
|
||||
for (let i in value) {
|
||||
if (typeof value[i] === "string") {
|
||||
value[i] = `${quoteStyle}${value[i]}${quoteStyle}`
|
||||
}
|
||||
}
|
||||
return `[${value.join(",")}]`
|
||||
}
|
||||
if (this.client === SqlClient.POSTGRES) {
|
||||
iterate(mode, (key: string, value: Array<any>) => {
|
||||
const wrap = any ? "" : "'"
|
||||
const containsOp = any ? "\\?| array" : "@>"
|
||||
const fieldNames = key.split(/\./g)
|
||||
const tableName = fieldNames[0]
|
||||
const columnName = fieldNames[1]
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](
|
||||
`${not}"${tableName}"."${columnName}"::jsonb ${containsOp} ${wrap}${stringifyArray(
|
||||
value,
|
||||
any ? "'" : '"'
|
||||
)}${wrap}`
|
||||
)
|
||||
})
|
||||
} else if (this.client === SqlClient.MY_SQL) {
|
||||
const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS"
|
||||
iterate(mode, (key: string, value: Array<any>) => {
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](
|
||||
`${not}${jsonFnc}(${key}, '${stringifyArray(value)}')`
|
||||
)
|
||||
})
|
||||
} else {
|
||||
const andOr = mode === filters?.containsAny ? " OR " : " AND "
|
||||
iterate(mode, (key: string, value: Array<any>) => {
|
||||
let statement = ""
|
||||
for (let i in value) {
|
||||
if (typeof value[i] === "string") {
|
||||
value[i] = `%"${value[i]}"%`
|
||||
} else {
|
||||
value[i] = `%${value[i]}%`
|
||||
}
|
||||
statement +=
|
||||
(statement ? andOr : "") +
|
||||
`LOWER(${likeKey(this.client, key)}) LIKE ?`
|
||||
}
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](`${not}(${statement})`, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (!filters) {
|
||||
return query
|
||||
}
|
||||
|
@ -229,32 +284,13 @@ class InternalBuilder {
|
|||
})
|
||||
}
|
||||
if (filters.contains) {
|
||||
const fnc = allOr ? "orWhere" : "where"
|
||||
const rawFnc = `${fnc}Raw`
|
||||
if (this.client === SqlClient.POSTGRES) {
|
||||
iterate(filters.contains, (key: string, value: any) => {
|
||||
const fieldNames = key.split(/\./g)
|
||||
const tableName = fieldNames[0]
|
||||
const columnName = fieldNames[1]
|
||||
if (typeof value === "string") {
|
||||
value = `"${value}"`
|
||||
contains(filters.contains)
|
||||
}
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](
|
||||
`"${tableName}"."${columnName}"::jsonb @> '[${value}]'`
|
||||
)
|
||||
})
|
||||
} else if (this.client === SqlClient.MY_SQL) {
|
||||
iterate(filters.contains, (key: string, value: any) => {
|
||||
if (typeof value === "string") {
|
||||
value = `"${value}"`
|
||||
}
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](`JSON_CONTAINS(${key}, '${value}')`)
|
||||
})
|
||||
} else {
|
||||
iterate(filters.contains, like)
|
||||
if (filters.notContains) {
|
||||
contains(filters.notContains)
|
||||
}
|
||||
if (filters.containsAny) {
|
||||
contains(filters.containsAny, true)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
|
|
@ -240,18 +240,18 @@ describe("SQL query builder", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it("should use like expression for MS-SQL when filter is contains", () => {
|
||||
it("should use AND like expression for MS-SQL when filter is contains", () => {
|
||||
const query = new Sql(SqlClient.MS_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
contains: {
|
||||
age: 20,
|
||||
name: "John"
|
||||
age: [20, 25],
|
||||
name: ["John", "Mary"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", "%John%"],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where LOWER(${TABLE_NAME}.age) LIKE @p1 and LOWER(${TABLE_NAME}.name) LIKE @p2) as [${TABLE_NAME}]`
|
||||
bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER(${TABLE_NAME}.age) LIKE @p1 AND LOWER(${TABLE_NAME}.age) LIKE @p2) and (LOWER(${TABLE_NAME}.name) LIKE @p3 AND LOWER(${TABLE_NAME}.name) LIKE @p4)) as [${TABLE_NAME}]`
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -259,14 +259,14 @@ describe("SQL query builder", () => {
|
|||
const query = new Sql(SqlClient.MY_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
contains: {
|
||||
age: 20,
|
||||
name: "John"
|
||||
age: [20],
|
||||
name: ["John"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10],
|
||||
sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_CONTAINS(${TABLE_NAME}.age, '20') and JSON_CONTAINS(${TABLE_NAME}.name, '"John"') limit ?) as \`${TABLE_NAME}\``
|
||||
sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_CONTAINS(${TABLE_NAME}.age, '[20]') and JSON_CONTAINS(${TABLE_NAME}.name, '["John"]') limit ?) as \`${TABLE_NAME}\``
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -274,8 +274,8 @@ describe("SQL query builder", () => {
|
|||
const query = new Sql(SqlClient.POSTGRES, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
contains: {
|
||||
age: 20,
|
||||
name: "John"
|
||||
age: [20],
|
||||
name: ["John"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
@ -284,4 +284,94 @@ describe("SQL query builder", () => {
|
|||
sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"`
|
||||
})
|
||||
})
|
||||
|
||||
it("should use NOT like expression for MS-SQL when filter is notContains", () => {
|
||||
const query = new Sql(SqlClient.MS_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
notContains: {
|
||||
age: [20],
|
||||
name: ["John"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", `%"John"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where NOT (LOWER(${TABLE_NAME}.age) LIKE @p1) and NOT (LOWER(${TABLE_NAME}.name) LIKE @p2)) as [${TABLE_NAME}]`
|
||||
})
|
||||
})
|
||||
|
||||
it("should use NOT JSON_CONTAINS expression for MySQL when filter is notContains", () => {
|
||||
const query = new Sql(SqlClient.MY_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
notContains: {
|
||||
age: [20],
|
||||
name: ["John"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10],
|
||||
sql: `select * from (select * from \`${TABLE_NAME}\` where NOT JSON_CONTAINS(${TABLE_NAME}.age, '[20]') and NOT JSON_CONTAINS(${TABLE_NAME}.name, '["John"]') limit ?) as \`${TABLE_NAME}\``
|
||||
})
|
||||
})
|
||||
|
||||
it("should use jsonb operator NOT expression for PostgreSQL when filter is notContains", () => {
|
||||
const query = new Sql(SqlClient.POSTGRES, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
notContains: {
|
||||
age: [20],
|
||||
name: ["John"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10],
|
||||
sql: `select * from (select * from \"${TABLE_NAME}\" where NOT \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and NOT \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"`
|
||||
})
|
||||
})
|
||||
|
||||
it("should use OR like expression for MS-SQL when filter is containsAny", () => {
|
||||
const query = new Sql(SqlClient.MS_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
containsAny: {
|
||||
age: [20, 25],
|
||||
name: ["John", "Mary"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER(${TABLE_NAME}.age) LIKE @p1 OR LOWER(${TABLE_NAME}.age) LIKE @p2) and (LOWER(${TABLE_NAME}.name) LIKE @p3 OR LOWER(${TABLE_NAME}.name) LIKE @p4)) as [${TABLE_NAME}]`
|
||||
})
|
||||
})
|
||||
|
||||
it("should use JSON_OVERLAPS expression for MySQL when filter is containsAny", () => {
|
||||
const query = new Sql(SqlClient.MY_SQL, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
containsAny: {
|
||||
age: [20, 25],
|
||||
name: ["John", "Mary"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10],
|
||||
sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_OVERLAPS(${TABLE_NAME}.age, '[20,25]') and JSON_OVERLAPS(${TABLE_NAME}.name, '["John","Mary"]') limit ?) as \`${TABLE_NAME}\``
|
||||
})
|
||||
})
|
||||
|
||||
it("should use ?| operator expression for PostgreSQL when filter is containsAny", () => {
|
||||
const query = new Sql(SqlClient.POSTGRES, 10)._query(generateReadJson({
|
||||
filters: {
|
||||
containsAny: {
|
||||
age: [20, 25],
|
||||
name: ["John", "Mary"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
expect(query).toEqual({
|
||||
bindings: [10],
|
||||
sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb ?| array [20,25] and \"${TABLE_NAME}\".\"name\"::jsonb ?| array ['John','Mary'] limit $1) as \"${TABLE_NAME}\"`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1094,12 +1094,12 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.2.39-alpha.5.tgz#fbadac10657e44fb05641a43aa8d9481b86418e9"
|
||||
integrity sha512-bZPmKqWUnQ+OVwf2z35WXPfPuxwuL0vlZJNyTgLX7hdhjYfPB4LA0vMftPbvtRFO9k6SdB0XpBOJCm2u5k5KsQ==
|
||||
"@budibase/backend-core@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.2.39-alpha.7.tgz#79c2b3c1b02b6e5c9a42f5bf7e76ea6b2498a971"
|
||||
integrity sha512-1UVfEetO3sbfa7tC7rOXTWrYjpaTZtYpijZMz1CtdOYJKzCimHVbIWWCmEO8BgSOejtWTvIARjoqCfy6oWFM6w==
|
||||
dependencies:
|
||||
"@budibase/types" "1.2.39-alpha.5"
|
||||
"@budibase/types" "1.2.39-alpha.7"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-sdk "2.1030.0"
|
||||
bcrypt "5.0.1"
|
||||
|
@ -1178,13 +1178,13 @@
|
|||
svelte-flatpickr "^3.2.3"
|
||||
svelte-portal "^1.0.0"
|
||||
|
||||
"@budibase/pro@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.2.39-alpha.5.tgz#cd652a06bf691ae00c2bf8cd9351e46b684939a5"
|
||||
integrity sha512-6M0Mj+AbJi+HpFRJJD1bZDwuWlCq1I3m8vrG4A3Rm/VnJigb1Zi7XTMlwzgCiUaWvowstiJVGHG6Af0Mix4zdQ==
|
||||
"@budibase/pro@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.2.39-alpha.7.tgz#e913b91168f73859ffc78824dc7bd2c4cb7514ef"
|
||||
integrity sha512-HHlAoH4A35p/5nepHVtQ79IrGAG4U3fPzaX6/gz0Ws/tutYRS8vfvGG0OCXom9mBy8X1xcO/X8+KPrHi0oVpQg==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "1.2.39-alpha.5"
|
||||
"@budibase/types" "1.2.39-alpha.5"
|
||||
"@budibase/backend-core" "1.2.39-alpha.7"
|
||||
"@budibase/types" "1.2.39-alpha.7"
|
||||
"@koa/router" "8.0.8"
|
||||
joi "17.6.0"
|
||||
node-fetch "^2.6.1"
|
||||
|
@ -1207,10 +1207,10 @@
|
|||
svelte-apexcharts "^1.0.2"
|
||||
svelte-flatpickr "^3.1.0"
|
||||
|
||||
"@budibase/types@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.2.39-alpha.5.tgz#632ef72b248d105cb69f4a133d78d3a293e5404e"
|
||||
integrity sha512-MgJayPh6t7VGB6ErUwM0sJmJoxG91h3z24fWSE+q3bbH2MKbnkpuNCbOh1wlKyFWqzdRofuFpJGK/O9zWXvRwg==
|
||||
"@budibase/types@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.2.39-alpha.7.tgz#d68d5c83d7368a7a5596c0fa70dea3cc1f8629f0"
|
||||
integrity sha512-R5zOze0jD68M6zbEMRCCy46jBjbktcD9cb/U0YPbaHSQNILPgmrsEdXEhHK7JGByfLtPsmPVd9ccDGWV9kaqNw==
|
||||
|
||||
"@bull-board/api@3.7.0":
|
||||
version "3.7.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
|
|
@ -31,7 +31,13 @@ export interface SearchFilters {
|
|||
[key: string]: any[]
|
||||
}
|
||||
contains?: {
|
||||
[key: string]: any
|
||||
[key: string]: any[]
|
||||
}
|
||||
notContains?: {
|
||||
[key: string]: any[]
|
||||
}
|
||||
containsAny?: {
|
||||
[key: string]: any[]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "1.2.39-alpha.5",
|
||||
"version": "1.2.39-alpha.7",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -35,10 +35,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "1.2.39-alpha.5",
|
||||
"@budibase/pro": "1.2.39-alpha.5",
|
||||
"@budibase/string-templates": "1.2.39-alpha.5",
|
||||
"@budibase/types": "1.2.39-alpha.5",
|
||||
"@budibase/backend-core": "1.2.39-alpha.7",
|
||||
"@budibase/pro": "1.2.39-alpha.7",
|
||||
"@budibase/string-templates": "1.2.39-alpha.7",
|
||||
"@budibase/types": "1.2.39-alpha.7",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -291,12 +291,12 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.2.39-alpha.5.tgz#fbadac10657e44fb05641a43aa8d9481b86418e9"
|
||||
integrity sha512-bZPmKqWUnQ+OVwf2z35WXPfPuxwuL0vlZJNyTgLX7hdhjYfPB4LA0vMftPbvtRFO9k6SdB0XpBOJCm2u5k5KsQ==
|
||||
"@budibase/backend-core@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.2.39-alpha.7.tgz#79c2b3c1b02b6e5c9a42f5bf7e76ea6b2498a971"
|
||||
integrity sha512-1UVfEetO3sbfa7tC7rOXTWrYjpaTZtYpijZMz1CtdOYJKzCimHVbIWWCmEO8BgSOejtWTvIARjoqCfy6oWFM6w==
|
||||
dependencies:
|
||||
"@budibase/types" "1.2.39-alpha.5"
|
||||
"@budibase/types" "1.2.39-alpha.7"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-sdk "2.1030.0"
|
||||
bcrypt "5.0.1"
|
||||
|
@ -325,21 +325,21 @@
|
|||
uuid "8.3.2"
|
||||
zlib "1.0.5"
|
||||
|
||||
"@budibase/pro@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.2.39-alpha.5.tgz#cd652a06bf691ae00c2bf8cd9351e46b684939a5"
|
||||
integrity sha512-6M0Mj+AbJi+HpFRJJD1bZDwuWlCq1I3m8vrG4A3Rm/VnJigb1Zi7XTMlwzgCiUaWvowstiJVGHG6Af0Mix4zdQ==
|
||||
"@budibase/pro@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.2.39-alpha.7.tgz#e913b91168f73859ffc78824dc7bd2c4cb7514ef"
|
||||
integrity sha512-HHlAoH4A35p/5nepHVtQ79IrGAG4U3fPzaX6/gz0Ws/tutYRS8vfvGG0OCXom9mBy8X1xcO/X8+KPrHi0oVpQg==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "1.2.39-alpha.5"
|
||||
"@budibase/types" "1.2.39-alpha.5"
|
||||
"@budibase/backend-core" "1.2.39-alpha.7"
|
||||
"@budibase/types" "1.2.39-alpha.7"
|
||||
"@koa/router" "8.0.8"
|
||||
joi "17.6.0"
|
||||
node-fetch "^2.6.1"
|
||||
|
||||
"@budibase/types@1.2.39-alpha.5":
|
||||
version "1.2.39-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.2.39-alpha.5.tgz#632ef72b248d105cb69f4a133d78d3a293e5404e"
|
||||
integrity sha512-MgJayPh6t7VGB6ErUwM0sJmJoxG91h3z24fWSE+q3bbH2MKbnkpuNCbOh1wlKyFWqzdRofuFpJGK/O9zWXvRwg==
|
||||
"@budibase/types@1.2.39-alpha.7":
|
||||
version "1.2.39-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.2.39-alpha.7.tgz#d68d5c83d7368a7a5596c0fa70dea3cc1f8629f0"
|
||||
integrity sha512-R5zOze0jD68M6zbEMRCCy46jBjbktcD9cb/U0YPbaHSQNILPgmrsEdXEhHK7JGByfLtPsmPVd9ccDGWV9kaqNw==
|
||||
|
||||
"@cspotcode/source-map-consumer@0.8.0":
|
||||
version "0.8.0"
|
||||
|
|
Loading…
Reference in New Issue