@ragestudio/scylla-odm 0.22.2 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/batch/index.d.ts +3 -3
- package/batch/index.d.ts.map +1 -1
- package/client.d.ts +6 -5
- package/client.d.ts.map +1 -1
- package/client.js +11 -12
- package/client.js.map +1 -1
- package/cql_gen/create_table.d.ts +1 -1
- package/cql_gen/create_table.d.ts.map +1 -1
- package/document/index.d.ts +3 -3
- package/document/index.d.ts.map +1 -1
- package/driver/LICENSE.txt +177 -0
- package/driver/NOTICE.txt +67 -0
- package/driver/auth/index.d.ts +37 -0
- package/driver/auth/index.js +37 -0
- package/driver/auth/no-auth-provider.js +73 -0
- package/driver/auth/plain-text-auth-provider.js +81 -0
- package/driver/auth/provider.js +77 -0
- package/driver/client-options.js +442 -0
- package/driver/client.js +1267 -0
- package/driver/concurrent/index.d.ts +49 -0
- package/driver/concurrent/index.js +366 -0
- package/driver/connection.js +1034 -0
- package/driver/control-connection.js +1282 -0
- package/driver/encoder.js +2316 -0
- package/driver/errors.js +223 -0
- package/driver/execution-options.js +612 -0
- package/driver/execution-profile.js +274 -0
- package/driver/host-connection-pool.js +587 -0
- package/driver/host.js +699 -0
- package/driver/index.d.ts +387 -0
- package/driver/index.js +81 -0
- package/driver/mapping/cache.js +214 -0
- package/driver/mapping/doc-info-adapter.js +171 -0
- package/driver/mapping/index.d.ts +219 -0
- package/driver/mapping/index.js +57 -0
- package/driver/mapping/mapper.js +225 -0
- package/driver/mapping/mapping-handler.js +641 -0
- package/driver/mapping/model-batch-item.js +215 -0
- package/driver/mapping/model-batch-mapper.js +141 -0
- package/driver/mapping/model-mapper.js +315 -0
- package/driver/mapping/model-mapping-info.js +225 -0
- package/driver/mapping/object-selector.js +417 -0
- package/driver/mapping/q.js +156 -0
- package/driver/mapping/query-generator.js +556 -0
- package/driver/mapping/result-mapper.js +123 -0
- package/driver/mapping/result.js +139 -0
- package/driver/mapping/table-mappings.js +133 -0
- package/driver/mapping/tree.js +160 -0
- package/driver/metadata/aggregate.js +79 -0
- package/driver/metadata/client-state.js +119 -0
- package/driver/metadata/data-collection.js +182 -0
- package/driver/metadata/event-debouncer.js +174 -0
- package/driver/metadata/index.d.ts +276 -0
- package/driver/metadata/index.js +1156 -0
- package/driver/metadata/materialized-view.js +49 -0
- package/driver/metadata/schema-function.js +98 -0
- package/driver/metadata/schema-index.js +166 -0
- package/driver/metadata/schema-parser.js +1399 -0
- package/driver/metadata/table-metadata.js +77 -0
- package/driver/operation-state.js +206 -0
- package/driver/policies/address-resolution.js +145 -0
- package/driver/policies/index.d.ts +241 -0
- package/driver/policies/index.js +110 -0
- package/driver/policies/load-balancing.js +970 -0
- package/driver/policies/reconnection.js +166 -0
- package/driver/policies/retry.js +326 -0
- package/driver/policies/speculative-execution.js +150 -0
- package/driver/policies/timestamp-generation.js +176 -0
- package/driver/prepare-handler.js +347 -0
- package/driver/promise-utils.js +191 -0
- package/driver/readers.js +624 -0
- package/driver/request-execution.js +644 -0
- package/driver/request-handler.js +332 -0
- package/driver/requests.js +618 -0
- package/driver/stream-id-stack.js +209 -0
- package/driver/streams.js +745 -0
- package/driver/token.js +325 -0
- package/driver/tokenizer.js +631 -0
- package/driver/types/big-decimal.js +282 -0
- package/driver/types/duration.js +576 -0
- package/driver/types/index.d.ts +486 -0
- package/driver/types/index.js +733 -0
- package/driver/types/inet-address.js +262 -0
- package/driver/types/integer.js +818 -0
- package/driver/types/local-date.js +280 -0
- package/driver/types/local-time.js +299 -0
- package/driver/types/mutable-long.js +385 -0
- package/driver/types/protocol-version.js +391 -0
- package/driver/types/result-set.js +287 -0
- package/driver/types/result-stream.js +164 -0
- package/driver/types/row.js +85 -0
- package/driver/types/time-uuid.js +414 -0
- package/driver/types/tuple.js +103 -0
- package/driver/types/uuid.js +160 -0
- package/driver/types/vector.js +130 -0
- package/driver/types/version-number.js +153 -0
- package/driver/utils.js +1485 -0
- package/driver/writers.js +350 -0
- package/global.d.ts +1 -1
- package/global.d.ts.map +1 -1
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +6 -6
- package/index.js.map +1 -1
- package/migrate/index.d.ts +1 -1
- package/migrate/index.d.ts.map +1 -1
- package/migrate/index.js +1 -1
- package/migrate/index.js.map +1 -1
- package/model/index.d.ts +6 -6
- package/model/index.d.ts.map +1 -1
- package/model/index.js +10 -10
- package/model/index.js.map +1 -1
- package/operations/countAll.d.ts +1 -1
- package/operations/countAll.d.ts.map +1 -1
- package/operations/delete.d.ts +3 -4
- package/operations/delete.d.ts.map +1 -1
- package/operations/delete.js +1 -1
- package/operations/delete.js.map +1 -1
- package/operations/find.d.ts +2 -2
- package/operations/find.d.ts.map +1 -1
- package/operations/find.js +1 -1
- package/operations/find.js.map +1 -1
- package/operations/findOne.d.ts +2 -2
- package/operations/findOne.d.ts.map +1 -1
- package/operations/findOne.js +1 -1
- package/operations/findOne.js.map +1 -1
- package/operations/insert.d.ts +3 -3
- package/operations/insert.d.ts.map +1 -1
- package/operations/insert.js +2 -2
- package/operations/insert.js.map +1 -1
- package/operations/sync.d.ts +1 -1
- package/operations/sync.d.ts.map +1 -1
- package/operations/sync.js +1 -1
- package/operations/sync.js.map +1 -1
- package/operations/tableExists.d.ts +1 -1
- package/operations/tableExists.d.ts.map +1 -1
- package/operations/update.d.ts +3 -3
- package/operations/update.d.ts.map +1 -1
- package/operations/update.js +2 -2
- package/operations/update.js.map +1 -1
- package/package.json +4 -12
- package/schema/index.d.ts +1 -1
- package/schema/index.d.ts.map +1 -1
- package/types.d.ts +4 -4
- package/types.d.ts.map +1 -1
- package/utils/queryParser.d.ts +1 -1
- package/utils/queryParser.d.ts.map +1 -1
- package/utils/queryParser.js +1 -1
- package/utils/queryParser.js.map +1 -1
- package/utils/typeChecker.d.ts +1 -1
- package/utils/typeChecker.d.ts.map +1 -1
- package/utils/typeChecker.js +1 -1
- package/utils/typeChecker.js.map +1 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import errors from "../errors.js"
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Represents a CQL query operator, like >=, IN, <, ...
|
|
23
|
+
* @ignore
|
|
24
|
+
*/
|
|
25
|
+
class QueryOperator {
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new instance of <code>QueryOperator</code>.
|
|
28
|
+
* @param {String} key
|
|
29
|
+
* @param value
|
|
30
|
+
* @param [hasChildValues]
|
|
31
|
+
* @param [isInOperator]
|
|
32
|
+
*/
|
|
33
|
+
constructor(key, value, hasChildValues, isInOperator) {
|
|
34
|
+
/**
|
|
35
|
+
* The CQL key representing the operator
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
this.key = key
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The value to be used as parameter.
|
|
42
|
+
*/
|
|
43
|
+
this.value = value
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Determines whether a query operator can have child values or operators (AND, OR)
|
|
47
|
+
*/
|
|
48
|
+
this.hasChildValues = hasChildValues
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Determines whether this instance represents CQL "IN" operator.
|
|
52
|
+
*/
|
|
53
|
+
this.isInOperator = isInOperator
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Represents a CQL assignment operation, like col = col + x.
|
|
59
|
+
* @ignore
|
|
60
|
+
*/
|
|
61
|
+
class QueryAssignment {
|
|
62
|
+
constructor(sign, value, inverted) {
|
|
63
|
+
/**
|
|
64
|
+
* Gets the sign of the assignment operation.
|
|
65
|
+
*/
|
|
66
|
+
this.sign = sign
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Gets the value to be assigned.
|
|
70
|
+
*/
|
|
71
|
+
this.value = value
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Determines whether the assignment should be inverted (prepends), e.g: col = x + col
|
|
75
|
+
* @type {boolean}
|
|
76
|
+
*/
|
|
77
|
+
this.inverted = !!inverted
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Contains functions that represents operators in a query.
|
|
83
|
+
* @alias module:mapping~q
|
|
84
|
+
* @type {Object}
|
|
85
|
+
* @property {function} in_ Represents the CQL operator "IN".
|
|
86
|
+
* @property {function} gt Represents the CQL operator greater than ">".
|
|
87
|
+
* @property {function} gte Represents the CQL operator greater than or equals to ">=" .
|
|
88
|
+
* @property {function} lt Represents the CQL operator less than "<" .
|
|
89
|
+
* @property {function} lte Represents the CQL operator less than or equals to "<=" .
|
|
90
|
+
* @property {function} notEq Represents the CQL operator not equals to "!=" .
|
|
91
|
+
* @property {function} and When applied to a property, it represents two CQL conditions on the same column separated
|
|
92
|
+
* by the logical AND operator, e.g: "col1 >= x col < y"
|
|
93
|
+
* @property {function} incr Represents the CQL increment assignment used for counters, e.g: "col = col + x"
|
|
94
|
+
* @property {function} decr Represents the CQL decrement assignment used for counters, e.g: "col = col - x"
|
|
95
|
+
* @property {function} append Represents the CQL append assignment used for collections, e.g: "col = col + x"
|
|
96
|
+
* @property {function} prepend Represents the CQL prepend assignment used for lists, e.g: "col = x + col"
|
|
97
|
+
* @property {function} remove Represents the CQL remove assignment used for collections, e.g: "col = col - x"
|
|
98
|
+
*/
|
|
99
|
+
const q = {
|
|
100
|
+
in_: function in_(arr) {
|
|
101
|
+
if (!Array.isArray(arr)) {
|
|
102
|
+
throw new errors.ArgumentError(
|
|
103
|
+
"IN operator supports only Array values",
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
return new QueryOperator("IN", arr, false, true)
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
gt: function gt(value) {
|
|
110
|
+
return new QueryOperator(">", value)
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
gte: function gte(value) {
|
|
114
|
+
return new QueryOperator(">=", value)
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
lt: function lt(value) {
|
|
118
|
+
return new QueryOperator("<", value)
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
lte: function lte(value) {
|
|
122
|
+
return new QueryOperator("<=", value)
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
notEq: function notEq(value) {
|
|
126
|
+
return new QueryOperator("!=", value)
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
and: function (condition1, condition2) {
|
|
130
|
+
return new QueryOperator("AND", [condition1, condition2], true)
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
incr: function incr(value) {
|
|
134
|
+
return new QueryAssignment("+", value)
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
decr: function decr(value) {
|
|
138
|
+
return new QueryAssignment("-", value)
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
append: function append(value) {
|
|
142
|
+
return new QueryAssignment("+", value)
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
prepend: function prepend(value) {
|
|
146
|
+
return new QueryAssignment("+", value, true)
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
remove: function remove(value) {
|
|
150
|
+
return new QueryAssignment("-", value)
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { q, QueryAssignment, QueryOperator }
|
|
155
|
+
|
|
156
|
+
export default { q, QueryAssignment, QueryOperator }
|
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import vm from "vm"
|
|
20
|
+
import { QueryOperator, QueryAssignment } from "./q.js"
|
|
21
|
+
import types from "../types/index.js"
|
|
22
|
+
const dataTypes = types.dataTypes
|
|
23
|
+
|
|
24
|
+
const vmFileName = "gen-param-getter"
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Provides methods to generate a query and parameter handlers.
|
|
28
|
+
* @ignore
|
|
29
|
+
*/
|
|
30
|
+
class QueryGenerator {
|
|
31
|
+
/**
|
|
32
|
+
* Gets the SELECT query given the doc.
|
|
33
|
+
* @param {String} tableName
|
|
34
|
+
* @param {String} keyspace
|
|
35
|
+
* @param {Array} propertiesInfo
|
|
36
|
+
* @param {Array} fieldsInfo
|
|
37
|
+
* @param {Array} orderByColumns
|
|
38
|
+
* @param {Number|undefined} limit
|
|
39
|
+
* @return {string}
|
|
40
|
+
*/
|
|
41
|
+
static getSelect(
|
|
42
|
+
tableName,
|
|
43
|
+
keyspace,
|
|
44
|
+
propertiesInfo,
|
|
45
|
+
fieldsInfo,
|
|
46
|
+
orderByColumns,
|
|
47
|
+
limit,
|
|
48
|
+
) {
|
|
49
|
+
let query = "SELECT "
|
|
50
|
+
query +=
|
|
51
|
+
fieldsInfo.length > 0
|
|
52
|
+
? fieldsInfo.map((p) => `"${p.columnName}"`).join(", ")
|
|
53
|
+
: "*"
|
|
54
|
+
query += ` FROM ${keyspace}.${tableName}`
|
|
55
|
+
|
|
56
|
+
if (propertiesInfo.length > 0) {
|
|
57
|
+
query += " WHERE "
|
|
58
|
+
query += QueryGenerator._getConditionWithOperators(propertiesInfo)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (orderByColumns.length > 0) {
|
|
62
|
+
query += " ORDER BY "
|
|
63
|
+
query += orderByColumns
|
|
64
|
+
.map((order) => `"${order[0]}" ${order[1]}`)
|
|
65
|
+
.join(", ")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof limit === "number") {
|
|
69
|
+
query += " LIMIT ?"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return query
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static selectParamsGetter(propertiesInfo, limit) {
|
|
76
|
+
let scriptText =
|
|
77
|
+
"(function getParametersSelect(doc, docInfo, mappingInfo) {\n"
|
|
78
|
+
scriptText += " return ["
|
|
79
|
+
|
|
80
|
+
scriptText += QueryGenerator._valueGetterExpression(propertiesInfo)
|
|
81
|
+
|
|
82
|
+
if (typeof limit === "number") {
|
|
83
|
+
if (propertiesInfo.length > 0) {
|
|
84
|
+
scriptText += ", "
|
|
85
|
+
}
|
|
86
|
+
scriptText += `docInfo['limit']`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Finish return statement
|
|
90
|
+
scriptText += "];\n})"
|
|
91
|
+
|
|
92
|
+
const script = new vm.Script(scriptText, { filename: vmFileName })
|
|
93
|
+
return script.runInThisContext()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets the INSERT query and function to obtain the parameters, given the doc.
|
|
98
|
+
* @param {TableMetadata} table
|
|
99
|
+
* @param {String} keyspace
|
|
100
|
+
* @param {Array} propertiesInfo
|
|
101
|
+
* @param {Object} docInfo
|
|
102
|
+
* @param {Boolean|undefined} ifNotExists
|
|
103
|
+
* @return {{query: String, paramsGetter: Function, isIdempotent: Boolean}}
|
|
104
|
+
*/
|
|
105
|
+
static getInsert(table, keyspace, propertiesInfo, docInfo, ifNotExists) {
|
|
106
|
+
const ttl = docInfo && docInfo.ttl
|
|
107
|
+
|
|
108
|
+
// Not all columns are contained in the table
|
|
109
|
+
const filteredPropertiesInfo = propertiesInfo.filter(
|
|
110
|
+
(pInfo) => table.columnsByName[pInfo.columnName] !== undefined,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
query: QueryGenerator._getInsertQuery(
|
|
115
|
+
table.name,
|
|
116
|
+
keyspace,
|
|
117
|
+
filteredPropertiesInfo,
|
|
118
|
+
ifNotExists,
|
|
119
|
+
ttl,
|
|
120
|
+
),
|
|
121
|
+
paramsGetter: QueryGenerator._insertParamsGetter(
|
|
122
|
+
filteredPropertiesInfo,
|
|
123
|
+
docInfo,
|
|
124
|
+
),
|
|
125
|
+
isIdempotent: !ifNotExists,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Gets the query for an insert statement.
|
|
131
|
+
* @param {String} tableName
|
|
132
|
+
* @param {String} keyspace
|
|
133
|
+
* @param {Array} propertiesInfo
|
|
134
|
+
* @param {Boolean} ifNotExists
|
|
135
|
+
* @param {Number|undefined} ttl
|
|
136
|
+
* @return {String}
|
|
137
|
+
*/
|
|
138
|
+
static _getInsertQuery(
|
|
139
|
+
tableName,
|
|
140
|
+
keyspace,
|
|
141
|
+
propertiesInfo,
|
|
142
|
+
ifNotExists,
|
|
143
|
+
ttl,
|
|
144
|
+
) {
|
|
145
|
+
let query = `INSERT INTO ${keyspace}.${tableName} (`
|
|
146
|
+
query += propertiesInfo
|
|
147
|
+
.map((pInfo) => `"${pInfo.columnName}"`)
|
|
148
|
+
.join(", ")
|
|
149
|
+
query += ") VALUES ("
|
|
150
|
+
query += propertiesInfo.map(() => "?").join(", ")
|
|
151
|
+
query += ")"
|
|
152
|
+
|
|
153
|
+
if (ifNotExists === true) {
|
|
154
|
+
query += " IF NOT EXISTS"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (typeof ttl === "number") {
|
|
158
|
+
query += " USING TTL ?"
|
|
159
|
+
}
|
|
160
|
+
return query
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static _insertParamsGetter(propertiesInfo, docInfo) {
|
|
164
|
+
let scriptText =
|
|
165
|
+
"(function getParametersInsert(doc, docInfo, mappingInfo) {\n"
|
|
166
|
+
scriptText += " return ["
|
|
167
|
+
|
|
168
|
+
scriptText += QueryGenerator._valueGetterExpression(propertiesInfo)
|
|
169
|
+
|
|
170
|
+
if (docInfo && typeof docInfo.ttl === "number") {
|
|
171
|
+
scriptText += `, docInfo['ttl']`
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Finish return statement
|
|
175
|
+
scriptText += "];\n})"
|
|
176
|
+
|
|
177
|
+
const script = new vm.Script(scriptText, { filename: vmFileName })
|
|
178
|
+
return script.runInThisContext()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Gets the UPDATE query and function to obtain the parameters, given the doc.
|
|
183
|
+
* @param {TableMetadata} table
|
|
184
|
+
* @param {String} keyspace
|
|
185
|
+
* @param {Array} propertiesInfo
|
|
186
|
+
* @param {Object} docInfo
|
|
187
|
+
* @param {Array} when
|
|
188
|
+
* @param {Boolean|undefined} ifExists
|
|
189
|
+
* @return {{query: String, paramsGetter: Function, isIdempotent: Boolean, isCounter}}
|
|
190
|
+
*/
|
|
191
|
+
static getUpdate(table, keyspace, propertiesInfo, docInfo, when, ifExists) {
|
|
192
|
+
const ttl = docInfo && docInfo.ttl
|
|
193
|
+
const primaryKeys = new Set(
|
|
194
|
+
table.partitionKeys.concat(table.clusteringKeys).map((c) => c.name),
|
|
195
|
+
)
|
|
196
|
+
let isIdempotent = true
|
|
197
|
+
let isCounter = false
|
|
198
|
+
|
|
199
|
+
// Not all columns are contained in the table
|
|
200
|
+
const filteredPropertiesInfo = propertiesInfo.filter((pInfo) => {
|
|
201
|
+
const column = table.columnsByName[pInfo.columnName]
|
|
202
|
+
if (column === undefined) {
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
column.type.code === dataTypes.list &&
|
|
208
|
+
pInfo.value instanceof QueryAssignment
|
|
209
|
+
) {
|
|
210
|
+
// Its not idempotent when list append/prepend
|
|
211
|
+
isIdempotent = false
|
|
212
|
+
} else if (column.type.code === dataTypes.counter) {
|
|
213
|
+
// Any update on a counter table is not idempotent
|
|
214
|
+
isIdempotent = false
|
|
215
|
+
isCounter = true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return true
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
query: QueryGenerator._getUpdateQuery(
|
|
223
|
+
table.name,
|
|
224
|
+
keyspace,
|
|
225
|
+
primaryKeys,
|
|
226
|
+
filteredPropertiesInfo,
|
|
227
|
+
when,
|
|
228
|
+
ifExists,
|
|
229
|
+
ttl,
|
|
230
|
+
),
|
|
231
|
+
isIdempotent: isIdempotent && when.length === 0 && !ifExists,
|
|
232
|
+
paramsGetter: QueryGenerator._updateParamsGetter(
|
|
233
|
+
primaryKeys,
|
|
234
|
+
filteredPropertiesInfo,
|
|
235
|
+
when,
|
|
236
|
+
ttl,
|
|
237
|
+
),
|
|
238
|
+
isCounter,
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Gets the query for an UPDATE statement.
|
|
244
|
+
* @param {String} tableName
|
|
245
|
+
* @param {String} keyspace
|
|
246
|
+
* @param {Set} primaryKeys
|
|
247
|
+
* @param {Array} propertiesInfo
|
|
248
|
+
* @param {Object} when
|
|
249
|
+
* @param {Boolean} ifExists
|
|
250
|
+
* @param {Number|undefined} ttl
|
|
251
|
+
*/
|
|
252
|
+
static _getUpdateQuery(
|
|
253
|
+
tableName,
|
|
254
|
+
keyspace,
|
|
255
|
+
primaryKeys,
|
|
256
|
+
propertiesInfo,
|
|
257
|
+
when,
|
|
258
|
+
ifExists,
|
|
259
|
+
ttl,
|
|
260
|
+
) {
|
|
261
|
+
let query = `UPDATE ${keyspace}.${tableName} `
|
|
262
|
+
|
|
263
|
+
if (typeof ttl === "number") {
|
|
264
|
+
query += "USING TTL ? "
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
query += "SET "
|
|
268
|
+
|
|
269
|
+
query += propertiesInfo
|
|
270
|
+
.filter((p) => !primaryKeys.has(p.columnName))
|
|
271
|
+
.map((p) => {
|
|
272
|
+
if (p.value instanceof QueryAssignment) {
|
|
273
|
+
if (p.value.inverted) {
|
|
274
|
+
// e.g: prepend "col1 = ? + col1"
|
|
275
|
+
return `"${p.columnName}" = ? ${p.value.sign} "${p.columnName}"`
|
|
276
|
+
}
|
|
277
|
+
// e.g: increment "col1 = col1 + ?"
|
|
278
|
+
return `"${p.columnName}" = "${p.columnName}" ${p.value.sign} ?`
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return `"${p.columnName}" = ?`
|
|
282
|
+
})
|
|
283
|
+
.join(", ")
|
|
284
|
+
|
|
285
|
+
query += " WHERE "
|
|
286
|
+
query += propertiesInfo
|
|
287
|
+
.filter((p) => primaryKeys.has(p.columnName))
|
|
288
|
+
.map((p) => `"${p.columnName}" = ?`)
|
|
289
|
+
.join(" AND ")
|
|
290
|
+
|
|
291
|
+
if (ifExists === true) {
|
|
292
|
+
query += " IF EXISTS"
|
|
293
|
+
} else if (when.length > 0) {
|
|
294
|
+
query += " IF " + QueryGenerator._getConditionWithOperators(when)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return query
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Returns a function to obtain the parameter values from a doc for an UPDATE statement.
|
|
302
|
+
* @param {Set} primaryKeys
|
|
303
|
+
* @param {Array} propertiesInfo
|
|
304
|
+
* @param {Array} when
|
|
305
|
+
* @param {Number|undefined} ttl
|
|
306
|
+
* @returns {Function}
|
|
307
|
+
*/
|
|
308
|
+
static _updateParamsGetter(primaryKeys, propertiesInfo, when, ttl) {
|
|
309
|
+
let scriptText =
|
|
310
|
+
"(function getParametersUpdate(doc, docInfo, mappingInfo) {\n"
|
|
311
|
+
scriptText += " return ["
|
|
312
|
+
|
|
313
|
+
if (typeof ttl === "number") {
|
|
314
|
+
scriptText += `docInfo['ttl'], `
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Assignment clause
|
|
318
|
+
scriptText += QueryGenerator._assignmentGetterExpression(
|
|
319
|
+
propertiesInfo.filter((p) => !primaryKeys.has(p.columnName)),
|
|
320
|
+
)
|
|
321
|
+
scriptText += ", "
|
|
322
|
+
|
|
323
|
+
// Where clause
|
|
324
|
+
scriptText += QueryGenerator._valueGetterExpression(
|
|
325
|
+
propertiesInfo.filter((p) => primaryKeys.has(p.columnName)),
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
// Condition clause
|
|
329
|
+
if (when.length > 0) {
|
|
330
|
+
scriptText +=
|
|
331
|
+
", " +
|
|
332
|
+
QueryGenerator._valueGetterExpression(when, "docInfo.when")
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Finish return statement
|
|
336
|
+
scriptText += "];\n})"
|
|
337
|
+
|
|
338
|
+
const script = new vm.Script(scriptText, { filename: vmFileName })
|
|
339
|
+
return script.runInThisContext()
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Gets the DELETE query and function to obtain the parameters, given the doc.
|
|
344
|
+
* @param {TableMetadata} table
|
|
345
|
+
* @param {String} keyspace
|
|
346
|
+
* @param {Array} propertiesInfo
|
|
347
|
+
* @param {Object} docInfo
|
|
348
|
+
* @param {Array} when
|
|
349
|
+
* @param {Boolean|undefined} ifExists
|
|
350
|
+
* @return {{query: String, paramsGetter: Function, isIdempotent}}
|
|
351
|
+
*/
|
|
352
|
+
static getDelete(table, keyspace, propertiesInfo, docInfo, when, ifExists) {
|
|
353
|
+
const deleteOnlyColumns = docInfo && docInfo.deleteOnlyColumns
|
|
354
|
+
const primaryKeys = new Set(
|
|
355
|
+
table.partitionKeys.concat(table.clusteringKeys).map((c) => c.name),
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
const filteredPropertiesInfo = propertiesInfo.filter(
|
|
359
|
+
(pInfo) => table.columnsByName[pInfo.columnName] !== undefined,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
query: QueryGenerator._getDeleteQuery(
|
|
364
|
+
table.name,
|
|
365
|
+
keyspace,
|
|
366
|
+
primaryKeys,
|
|
367
|
+
filteredPropertiesInfo,
|
|
368
|
+
when,
|
|
369
|
+
ifExists,
|
|
370
|
+
deleteOnlyColumns,
|
|
371
|
+
),
|
|
372
|
+
paramsGetter: QueryGenerator._deleteParamsGetter(
|
|
373
|
+
primaryKeys,
|
|
374
|
+
filteredPropertiesInfo,
|
|
375
|
+
when,
|
|
376
|
+
),
|
|
377
|
+
isIdempotent: when.length === 0 && !ifExists,
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Gets the query for an UPDATE statement.
|
|
383
|
+
* @param {String} tableName
|
|
384
|
+
* @param {String} keyspace
|
|
385
|
+
* @param {Set} primaryKeys
|
|
386
|
+
* @param {Array} propertiesInfo
|
|
387
|
+
* @param {Array} when
|
|
388
|
+
* @param {Boolean} ifExists
|
|
389
|
+
* @param {Boolean} deleteOnlyColumns
|
|
390
|
+
* @private
|
|
391
|
+
* @return {String}
|
|
392
|
+
*/
|
|
393
|
+
static _getDeleteQuery(
|
|
394
|
+
tableName,
|
|
395
|
+
keyspace,
|
|
396
|
+
primaryKeys,
|
|
397
|
+
propertiesInfo,
|
|
398
|
+
when,
|
|
399
|
+
ifExists,
|
|
400
|
+
deleteOnlyColumns,
|
|
401
|
+
) {
|
|
402
|
+
let query = "DELETE"
|
|
403
|
+
|
|
404
|
+
if (deleteOnlyColumns) {
|
|
405
|
+
const columnsToDelete = propertiesInfo
|
|
406
|
+
.filter((p) => !primaryKeys.has(p.columnName))
|
|
407
|
+
.map((p) => `"${p.columnName}"`)
|
|
408
|
+
.join(", ")
|
|
409
|
+
|
|
410
|
+
if (columnsToDelete !== "") {
|
|
411
|
+
query += " " + columnsToDelete
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
query += ` FROM ${keyspace}.${tableName} WHERE `
|
|
416
|
+
query += propertiesInfo
|
|
417
|
+
.filter((p) => primaryKeys.has(p.columnName))
|
|
418
|
+
.map((p) => `"${p.columnName}" = ?`)
|
|
419
|
+
.join(" AND ")
|
|
420
|
+
|
|
421
|
+
if (ifExists === true) {
|
|
422
|
+
query += " IF EXISTS"
|
|
423
|
+
} else if (when.length > 0) {
|
|
424
|
+
query += " IF " + QueryGenerator._getConditionWithOperators(when)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return query
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Returns a function to obtain the parameter values from a doc for an UPDATE statement.
|
|
431
|
+
* @param {Set} primaryKeys
|
|
432
|
+
* @param {Array} propertiesInfo
|
|
433
|
+
* @param {Array} when
|
|
434
|
+
* @returns {Function}
|
|
435
|
+
*/
|
|
436
|
+
static _deleteParamsGetter(primaryKeys, propertiesInfo, when) {
|
|
437
|
+
let scriptText =
|
|
438
|
+
"(function getParametersDelete(doc, docInfo, mappingInfo) {\n"
|
|
439
|
+
scriptText += " return ["
|
|
440
|
+
|
|
441
|
+
// Where clause
|
|
442
|
+
scriptText += QueryGenerator._valueGetterExpression(
|
|
443
|
+
propertiesInfo.filter((p) => primaryKeys.has(p.columnName)),
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
// Condition clause
|
|
447
|
+
if (when.length > 0) {
|
|
448
|
+
scriptText +=
|
|
449
|
+
", " +
|
|
450
|
+
QueryGenerator._valueGetterExpression(when, "docInfo.when")
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Finish return statement
|
|
454
|
+
scriptText += "];\n})"
|
|
455
|
+
|
|
456
|
+
const script = new vm.Script(scriptText, { filename: vmFileName })
|
|
457
|
+
return script.runInThisContext()
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Gets a string containing the doc properties to get.
|
|
462
|
+
* @param {Array} propertiesInfo
|
|
463
|
+
* @param {String} [objectName='doc']
|
|
464
|
+
* @return {string}
|
|
465
|
+
* @private
|
|
466
|
+
*/
|
|
467
|
+
static _valueGetterExpression(propertiesInfo, objectName) {
|
|
468
|
+
objectName = objectName || "doc"
|
|
469
|
+
|
|
470
|
+
return propertiesInfo
|
|
471
|
+
.map((p) =>
|
|
472
|
+
QueryGenerator._valueGetterSingle(
|
|
473
|
+
`${objectName}['${p.propertyName}']`,
|
|
474
|
+
p.propertyName,
|
|
475
|
+
p.value,
|
|
476
|
+
p.fromModel,
|
|
477
|
+
),
|
|
478
|
+
)
|
|
479
|
+
.join(", ")
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
static _valueGetterSingle(prefix, propName, value, fromModelFn) {
|
|
483
|
+
let valueGetter = prefix
|
|
484
|
+
|
|
485
|
+
if (value instanceof QueryOperator) {
|
|
486
|
+
if (value.hasChildValues) {
|
|
487
|
+
return (
|
|
488
|
+
`${QueryGenerator._valueGetterSingle(`${prefix}.value[0]`, propName, value.value[0], fromModelFn)}` +
|
|
489
|
+
`, ${QueryGenerator._valueGetterSingle(`${prefix}.value[1]`, propName, value.value[1], fromModelFn)}`
|
|
490
|
+
)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
valueGetter = `${prefix}.value`
|
|
494
|
+
|
|
495
|
+
if (value.isInOperator && fromModelFn) {
|
|
496
|
+
// Transform each individual value
|
|
497
|
+
return `${valueGetter}.map(v => ${QueryGenerator._getMappingFunctionCall(propName, "v")})`
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return !fromModelFn
|
|
502
|
+
? valueGetter
|
|
503
|
+
: QueryGenerator._getMappingFunctionCall(propName, valueGetter)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Gets a string containing the doc properties to SET, considering QueryAssignment instances.
|
|
508
|
+
* @param {Array} propertiesInfo
|
|
509
|
+
* @param {String} [prefix='doc']
|
|
510
|
+
* @return {string}
|
|
511
|
+
* @private
|
|
512
|
+
*/
|
|
513
|
+
static _assignmentGetterExpression(propertiesInfo, prefix) {
|
|
514
|
+
prefix = prefix || "doc"
|
|
515
|
+
|
|
516
|
+
return propertiesInfo
|
|
517
|
+
.map((p) => {
|
|
518
|
+
const valueGetter = `${prefix}['${p.propertyName}']${p.value instanceof QueryAssignment ? ".value" : ""}`
|
|
519
|
+
if (p.fromModel) {
|
|
520
|
+
return QueryGenerator._getMappingFunctionCall(
|
|
521
|
+
p.propertyName,
|
|
522
|
+
valueGetter,
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
return valueGetter
|
|
526
|
+
})
|
|
527
|
+
.join(", ")
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
static _getConditionWithOperators(propertiesInfo) {
|
|
531
|
+
return propertiesInfo
|
|
532
|
+
.map((p) =>
|
|
533
|
+
QueryGenerator._getSingleCondition(p.columnName, p.value),
|
|
534
|
+
)
|
|
535
|
+
.join(" AND ")
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
static _getMappingFunctionCall(propName, valueGetter) {
|
|
539
|
+
return `mappingInfo.getFromModelFn('${propName}')(${valueGetter})`
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
static _getSingleCondition(columnName, value) {
|
|
543
|
+
if (value instanceof QueryOperator) {
|
|
544
|
+
if (value.hasChildValues) {
|
|
545
|
+
return (
|
|
546
|
+
`${QueryGenerator._getSingleCondition(columnName, value.value[0])}` +
|
|
547
|
+
` ${value.key} ${QueryGenerator._getSingleCondition(columnName, value.value[1])}`
|
|
548
|
+
)
|
|
549
|
+
}
|
|
550
|
+
return `"${columnName}" ${value.key} ?`
|
|
551
|
+
}
|
|
552
|
+
return `"${columnName}" = ?`
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export default QueryGenerator
|