UNPKG

@nozbe/watermelondb

Version:

Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast

384 lines (370 loc) 11.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.asc = exports.and = void 0; exports.between = between; exports.column = column; exports.desc = void 0; exports.eq = eq; exports.experimentalJoinTables = experimentalJoinTables; exports.experimentalNestedJoin = experimentalNestedJoin; exports.gt = gt; exports.gte = gte; exports.includes = includes; exports.like = like; exports.lt = lt; exports.lte = lte; exports.notEq = notEq; exports.notIn = notIn; exports.notLike = notLike; exports.on = void 0; exports.oneOf = oneOf; exports.or = void 0; exports.sanitizeLikeString = sanitizeLikeString; exports.skip = skip; exports.sortBy = sortBy; exports.take = take; exports.unsafeLokiExpr = unsafeLokiExpr; exports.unsafeLokiTransform = unsafeLokiTransform; exports.unsafeSqlExpr = unsafeSqlExpr; exports.unsafeSqlQuery = unsafeSqlQuery; exports.weakGt = weakGt; exports.where = where; var _invariant = _interopRequireDefault(require("../utils/common/invariant")); var _checkName = _interopRequireDefault(require("../utils/fp/checkName")); var _arrayOrSpread = _interopRequireDefault(require("../utils/fp/arrayOrSpread")); /* eslint-disable no-use-before-define */ // don't import whole `utils` to keep worker size small // Note: These operators are designed to match SQLite semantics // to ensure that iOS, Android, web, and Query observation yield exactly the same results // // - `true` and `false` are equal to `1` and `0` // (JS uses true/false, but SQLite uses 1/0) // - `null`, `undefined`, and missing fields are equal // (SQLite queries return null, but newly created records might lack fields) // - You can only compare columns to values/other columns of the same type // (e.g. string to int comparisons are not allowed) // - numeric comparisons (<, <=, >, >=, between) with null on either side always return false // e.g. `null < 2 == false` // - `null` on the right-hand-side of IN/NOT IN is not allowed // e.g. `Q.in([null, 'foo', 'bar'])` // - `null` on the left-hand-side of IN/NOT IN will always return false // e.g. `null NOT IN (1, 2, 3) == false` // Equals (weakly) // Note: // - (null == undefined) == true // - (1 == true) == true // - (0 == false) == true function eq(valueOrColumn) { return { operator: 'eq', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Not equal (weakly) // Note: // - (null != undefined) == false // - (1 != true) == false // - (0 != false) == false function notEq(valueOrColumn) { return { operator: 'notEq', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Greater than (SQLite semantics) // Note: // - (5 > null) == false function gt(valueOrColumn) { return { operator: 'gt', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Greater than or equal (SQLite semantics) // Note: // - (5 >= null) == false function gte(valueOrColumn) { return { operator: 'gte', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Greater than (JavaScript semantics) // Note: // - (5 > null) == true function weakGt(valueOrColumn) { return { operator: 'weakGt', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Less than (SQLite semantics) // Note: // - (null < 5) == false function lt(valueOrColumn) { return { operator: 'lt', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Less than or equal (SQLite semantics) // Note: // - (null <= 5) == false function lte(valueOrColumn) { return { operator: 'lte', right: _valueOrColumn(valueOrColumn), type: comparisonSymbol }; } // Value in a set (SQLite IN semantics) // Note: // - `null` in `values` is not allowed! function oneOf(values) { (0, _invariant.default)(Array.isArray(values), "argument passed to oneOf() is not an array"); Object.freeze(values); // even in production, because it's an easy mistake to make return { operator: 'oneOf', right: { values: values }, type: comparisonSymbol }; } // Value not in a set (SQLite NOT IN semantics) // Note: // - `null` in `values` is not allowed! // - (null NOT IN (1, 2, 3)) == false function notIn(values) { (0, _invariant.default)(Array.isArray(values), "argument passed to notIn() is not an array"); Object.freeze(values); // even in production, because it's an easy mistake to make return { operator: 'notIn', right: { values: values }, type: comparisonSymbol }; } // Number is between two numbers (greater than or equal left, and less than or equal right) function between(left, right) { (0, _invariant.default)('number' === typeof left && 'number' === typeof right, 'Values passed to Q.between() are not numbers'); return { operator: 'between', right: { values: [left, right] }, type: comparisonSymbol }; } function like(value) { (0, _invariant.default)('string' === typeof value, 'Value passed to Q.like() is not a string'); return { operator: 'like', right: { value: value }, type: comparisonSymbol }; } function notLike(value) { (0, _invariant.default)('string' === typeof value, 'Value passed to Q.notLike() is not a string'); return { operator: 'notLike', right: { value: value }, type: comparisonSymbol }; } var nonLikeSafeRegexp = /[^a-zA-Z0-9]/g; function sanitizeLikeString(value) { (0, _invariant.default)('string' === typeof value, 'Value passed to Q.sanitizeLikeString() is not a string'); return value.replace(nonLikeSafeRegexp, '_'); } function includes(value) { (0, _invariant.default)('string' === typeof value, 'Value passed to Q.includes() is not a string'); return { operator: 'includes', right: { value: value }, type: comparisonSymbol }; } function column(name) { (0, _invariant.default)('string' === typeof name, 'Name passed to Q.column() is not a string'); return { column: (0, _checkName.default)(name), type: columnSymbol }; } function _valueOrComparison(arg) { if (null === arg || 'object' !== typeof arg) { return _valueOrComparison(eq(arg)); } (0, _invariant.default)(arg.type === comparisonSymbol, 'Invalid Comparison passed to Query builder. You seem to be passing unsanitized user data to Query builder!'); var { operator: operator, right: right } = arg; return { operator: operator, right: right }; } function where(left, valueOrComparison) { return { type: 'where', left: (0, _checkName.default)(left), comparison: _valueOrComparison(valueOrComparison) }; } function unsafeSqlExpr(sql) { if ('production' !== process.env.NODE_ENV) { (0, _invariant.default)('string' === typeof sql, 'Value passed to Q.unsafeSqlExpr is not a string'); } return { type: 'sql', expr: sql }; } function unsafeLokiExpr(expr) { if ('production' !== process.env.NODE_ENV) { (0, _invariant.default)(expr && 'object' === typeof expr && !Array.isArray(expr), 'Value passed to Q.unsafeLokiExpr is not an object'); } return { type: 'loki', expr: expr }; } function unsafeLokiTransform(fn) { return { type: 'lokiTransform', function: fn }; } var and = exports.and = function (...args) { var clauses = (0, _arrayOrSpread.default)(args, 'Q.and()', 'Where'); validateConditions(clauses); return { type: 'and', conditions: clauses }; }; var or = exports.or = function (...args) { var clauses = (0, _arrayOrSpread.default)(args, 'Q.or()', 'Where'); validateConditions(clauses); return { type: 'or', conditions: clauses }; }; var asc = exports.asc = 'asc'; var desc = exports.desc = 'desc'; function sortBy(sortColumn, sortOrder = asc) { (0, _invariant.default)('asc' === sortOrder || 'desc' === sortOrder, "Invalid sortOrder argument received in Q.sortBy (valid: asc, desc)"); return { type: 'sortBy', sortColumn: (0, _checkName.default)(sortColumn), sortOrder: sortOrder }; } function take(count) { (0, _invariant.default)('number' === typeof count, 'Value passed to Q.take() is not a number'); return { type: 'take', count: count }; } function skip(count) { (0, _invariant.default)('number' === typeof count, 'Value passed to Q.skip() is not a number'); return { type: 'skip', count: count }; } // Note: we have to write out three separate meanings of OnFunction because of a Babel bug // (it will remove the parentheses, changing the meaning of the flow type) // Use: on('tableName', 'left_column', 'right_value') // or: on('tableName', 'left_column', gte(10)) // or: on('tableName', where('left_column', 'value'))) // or: on('tableName', or(...)) // or: on('tableName', [where(...), where(...)]) var _on = exports.on = function (table, leftOrClauseOrList, valueOrComparison) { if ('string' === typeof leftOrClauseOrList) { (0, _invariant.default)(valueOrComparison !== undefined, 'illegal `undefined` passed to Q.on'); return _on(table, [where(leftOrClauseOrList, valueOrComparison)]); } var clauseOrList = leftOrClauseOrList; if (Array.isArray(clauseOrList)) { var conditions = clauseOrList; validateConditions(conditions); return { type: 'on', table: (0, _checkName.default)(table), conditions: conditions }; } else if (clauseOrList && 'and' === clauseOrList.type) { return _on(table, clauseOrList.conditions); } return _on(table, [clauseOrList]); }; function experimentalJoinTables(tables) { (0, _invariant.default)(Array.isArray(tables), 'experimentalJoinTables expected an array'); return { type: 'joinTables', tables: tables.map(_checkName.default) }; } function experimentalNestedJoin(from, to) { return { type: 'nestedJoinTable', from: (0, _checkName.default)(from), to: (0, _checkName.default)(to) }; } function unsafeSqlQuery(sql, values = []) { if ('production' !== process.env.NODE_ENV) { (0, _invariant.default)('string' === typeof sql, 'Value passed to Q.unsafeSqlQuery is not a string'); (0, _invariant.default)(Array.isArray(values), 'Placeholder values passed to Q.unsafeSqlQuery are not an array'); } return { type: 'sqlQuery', sql: sql, values: values }; } var columnSymbol = Symbol('Q.column'); var comparisonSymbol = Symbol('QueryComparison'); function _valueOrColumn(arg) { if (null === arg || 'object' !== typeof arg) { (0, _invariant.default)(arg !== undefined, 'Cannot compare to undefined in a Query. Did you mean null?'); return { value: arg }; } if ('string' === typeof arg.column) { (0, _invariant.default)(arg.type === columnSymbol, 'Invalid { column: } object passed to Watermelon query. You seem to be passing unsanitized user data to Query builder!'); return { column: arg.column }; } throw new Error("Invalid value passed to query"); } var acceptableClauses = ['where', 'and', 'or', 'on', 'sql', 'loki']; var isAcceptableClause = function (clause) { return acceptableClauses.includes(clause.type); }; var validateConditions = function (clauses) { if ('production' !== process.env.NODE_ENV) { (0, _invariant.default)(clauses.every(isAcceptableClause), 'Q.and(), Q.or(), Q.on() can only contain: Q.where, Q.and, Q.or, Q.on, Q.unsafeSqlExpr, Q.unsafeLokiExpr clauses'); } };