├── .gitignore ├── lib ├── assign.js ├── builder.js ├── compiler.js ├── formatter.js ├── index.js ├── interface.js ├── isEmpty.js ├── joinclause.js ├── methods.js ├── normalizeArr.js ├── raw.js ├── schema │ ├── builder.js │ ├── columnbuilder.js │ ├── columncompiler.js │ ├── compiler.js │ ├── helpers.js │ ├── tablebuilder.js │ └── tablecompiler.js ├── string.js └── write-stream.js ├── license.md ├── package-lock.json ├── package.json ├── readme.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | test.config.json 2 | -------------------------------------------------------------------------------- /lib/assign.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function assign(host, other) { 4 | if (!other) { 5 | return host; 6 | } 7 | Object.keys(other).forEach(function (key) { 8 | host[key] = other[key]; 9 | }); 10 | return host; 11 | }; 12 | -------------------------------------------------------------------------------- /lib/builder.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser https://github.com/tgriesser/knex/blob/e3ef628156101e749d54e220f48d416a68d223ca/lib/query/builder.js 3 | 'use strict'; 4 | 5 | var isEmpty = require('./isEmpty'); 6 | var assert = require('assert'); 7 | var debug = require('debug')('cartodb:builder'); 8 | var Raw = require('./raw'); 9 | var JoinClause = require('./joinclause'); 10 | var assign = require('./assign'); 11 | 12 | var Interface = require('./interface'); 13 | var inherits = require('inherits'); 14 | 15 | var normalizeArr = require('./normalizeArr'); 16 | 17 | inherits(QueryBuilder, Interface); 18 | // Typically called from `knex.builder`, 19 | // start a new query building chain. 20 | function QueryBuilder(client) { 21 | this.client = client; 22 | this.and = this; 23 | this._single = {}; 24 | this._statements = []; 25 | 26 | // Internal flags used in the builder. 27 | this._method = 'select'; 28 | this._joinFlag = 'inner'; 29 | this._boolFlag = 'and'; 30 | this._notFlag = false; 31 | } 32 | 33 | assign(QueryBuilder.prototype, { 34 | 35 | toString: function toString() { 36 | return this.toQuery(); 37 | }, 38 | noTransaction: function () { 39 | this._noTransaction = true; 40 | return this; 41 | }, 42 | // Convert the current query "toSQL" 43 | toSQL: function toSQL(method) { 44 | return this.client.queryCompiler(this).toSQL(method || this._method); 45 | }, 46 | // Create a shallow clone of the current query builder. 47 | // TODO: Test this!! 48 | clone: function clone() { 49 | var cloned = new this.constructor(this.client); 50 | cloned._method = this._method; 51 | cloned._single = assign({}, this._single); 52 | cloned._options = assign({}, this._options); 53 | cloned._statements = this._statements.slice(); 54 | return cloned; 55 | }, 56 | 57 | // Select 58 | // ------ 59 | 60 | // Adds a column or columns to the list of "columns" 61 | // being selected on the query. 62 | columns: function columns(column) { 63 | if (!column) { 64 | return this; 65 | } 66 | this._statements.push({ 67 | grouping: 'columns', 68 | value: normalizeArr.apply(null, arguments) 69 | }); 70 | return this; 71 | }, 72 | 73 | // Allow for a sub-select to be explicitly aliased as a column, 74 | // without needing to compile the query in a where. 75 | as: function as(column) { 76 | this._single.as = column; 77 | return this; 78 | }, 79 | 80 | // Sets the `tableName` on the query. 81 | // Alias to "from" for select and "into" for insert statements 82 | // e.g. builder.insert({a: value}).into('tableName') 83 | table: function table(tableName) { 84 | this._single.table = tableName; 85 | return this; 86 | }, 87 | 88 | // Adds a `distinct` clause to the query. 89 | distinct: function distinct() { 90 | this._statements.push({ 91 | grouping: 'columns', 92 | value: normalizeArr.apply(null, arguments), 93 | distinct: true 94 | }); 95 | return this; 96 | }, 97 | 98 | // Adds a join clause to the query, allowing for advanced joins 99 | // with an anonymous function as the second argument. 100 | // function(table, first, operator, second) 101 | join: function _join(table, first) { 102 | var join; 103 | var joinType = this._joinType(); 104 | if (typeof first === 'function') { 105 | join = new JoinClause(table, joinType); 106 | first.call(join, join); 107 | this._statements.push(join); 108 | return this; 109 | } 110 | if (joinType === 'raw') { 111 | join = new JoinClause(this.client.raw(table, first), 'raw'); 112 | this._statements.push(join); 113 | return this; 114 | } 115 | 116 | join = new JoinClause(table, joinType); 117 | if (arguments.length > 1) { 118 | join.on.apply(join, normalizeArr.apply(null, arguments).slice(1)); 119 | } 120 | this._statements.push(join); 121 | return this; 122 | }, 123 | 124 | // JOIN blocks: 125 | innerJoin: function innerJoin() { 126 | return this._joinType('inner').join.apply(this, arguments); 127 | }, 128 | leftJoin: function leftJoin() { 129 | return this._joinType('left').join.apply(this, arguments); 130 | }, 131 | leftOuterJoin: function leftOuterJoin() { 132 | return this._joinType('left outer').join.apply(this, arguments); 133 | }, 134 | rightJoin: function rightJoin() { 135 | return this._joinType('right').join.apply(this, arguments); 136 | }, 137 | rightOuterJoin: function rightOuterJoin() { 138 | return this._joinType('right outer').join.apply(this, arguments); 139 | }, 140 | outerJoin: function outerJoin() { 141 | return this._joinType('outer').join.apply(this, arguments); 142 | }, 143 | fullOuterJoin: function fullOuterJoin() { 144 | return this._joinType('full outer').join.apply(this, arguments); 145 | }, 146 | crossJoin: function crossJoin() { 147 | return this._joinType('cross').join.apply(this, arguments); 148 | }, 149 | joinRaw: function joinRaw() { 150 | return this._joinType('raw').join.apply(this, arguments); 151 | }, 152 | 153 | // The where function can be used in several ways: 154 | // The most basic is `where(key, value)`, which expands to 155 | // where key = value. 156 | where: function where(column, operator, value) { 157 | 158 | // Support "where true || where false" 159 | if (column === false || column === true) { 160 | return this.where(1, '=', column ? 1 : 0); 161 | } 162 | 163 | // Check if the column is a function, in which case it's 164 | // a where statement wrapped in parens. 165 | if (typeof column === 'function') { 166 | return this.whereWrapped(column); 167 | } 168 | 169 | // Allow a raw statement to be passed along to the query. 170 | if (column instanceof Raw && arguments.length === 1) { 171 | return this.whereRaw(column); 172 | } 173 | 174 | // Allows `where({id: 2})` syntax. 175 | if (typeof column === 'object' && !(column instanceof Raw)) { 176 | return this._objectWhere(column); 177 | } 178 | 179 | // Enable the where('key', value) syntax, only when there 180 | // are explicitly two arguments passed, so it's not possible to 181 | // do where('key', '!=') and have that turn into where key != null 182 | if (arguments.length === 2) { 183 | value = operator; 184 | operator = '='; 185 | 186 | // If the value is null, and it's a two argument query, 187 | // we assume we're going for a `whereNull`. 188 | if (value === null) { 189 | return this.whereNull(column); 190 | } 191 | } 192 | 193 | // lower case the operator for comparison purposes 194 | var checkOperator = ('' + operator).toLowerCase().trim(); 195 | 196 | // If there are 3 arguments, check whether 'in' is one of them. 197 | if (arguments.length === 3) { 198 | if (checkOperator === 'in' || checkOperator === 'not in') { 199 | return this._not(checkOperator === 'not in').whereIn(arguments[0], arguments[2]); 200 | } 201 | if (checkOperator === 'between' || checkOperator === 'not between') { 202 | return this._not(checkOperator === 'not between').whereBetween(arguments[0], arguments[2]); 203 | } 204 | } 205 | 206 | // If the value is still null, check whether they're meaning 207 | // where value is null 208 | if (value === null) { 209 | 210 | // Check for .where(key, 'is', null) or .where(key, 'is not', 'null'); 211 | if (checkOperator === 'is' || checkOperator === 'is not') { 212 | return this._not(checkOperator === 'is not').whereNull(column); 213 | } 214 | } 215 | 216 | // Push onto the where statement stack. 217 | this._statements.push({ 218 | grouping: 'where', 219 | type: 'whereBasic', 220 | column: column, 221 | operator: operator, 222 | value: value, 223 | not: this._not(), 224 | bool: this._bool() 225 | }); 226 | return this; 227 | }, 228 | // Adds an `or where` clause to the query. 229 | orWhere: function orWhere() { 230 | return this._bool('or').where.apply(this, arguments); 231 | }, 232 | 233 | // Adds an `not where` clause to the query. 234 | whereNot: function whereNot() { 235 | return this._not(true).where.apply(this, arguments); 236 | }, 237 | 238 | // Adds an `or not where` clause to the query. 239 | orWhereNot: function orWhereNot() { 240 | return this._bool('or').whereNot.apply(this, arguments); 241 | }, 242 | 243 | // Processes an object literal provided in a "where" clause. 244 | _objectWhere: function _objectWhere(obj) { 245 | var boolVal = this._bool(); 246 | var notVal = this._not() ? 'Not' : ''; 247 | for (var key in obj) { 248 | this[boolVal + 'Where' + notVal](key, obj[key]); 249 | } 250 | return this; 251 | }, 252 | 253 | // Adds a raw `where` clause to the query. 254 | whereRaw: function whereRaw(sql, bindings) { 255 | var raw = sql instanceof Raw ? sql : this.client.raw(sql, bindings); 256 | this._statements.push({ 257 | grouping: 'where', 258 | type: 'whereRaw', 259 | value: raw, 260 | bool: this._bool() 261 | }); 262 | return this; 263 | }, 264 | 265 | orWhereRaw: function orWhereRaw(sql, bindings) { 266 | return this._bool('or').whereRaw(sql, bindings); 267 | }, 268 | 269 | // Helper for compiling any advanced `where` queries. 270 | whereWrapped: function whereWrapped(callback) { 271 | this._statements.push({ 272 | grouping: 'where', 273 | type: 'whereWrapped', 274 | value: callback, 275 | not: this._not(), 276 | bool: this._bool() 277 | }); 278 | return this; 279 | }, 280 | 281 | // Helper for compiling any advanced `having` queries. 282 | havingWrapped: function havingWrapped(callback) { 283 | this._statements.push({ 284 | grouping: 'having', 285 | type: 'whereWrapped', 286 | value: callback, 287 | bool: this._bool() 288 | }); 289 | return this; 290 | }, 291 | 292 | // Adds a `where exists` clause to the query. 293 | whereExists: function whereExists(callback) { 294 | this._statements.push({ 295 | grouping: 'where', 296 | type: 'whereExists', 297 | value: callback, 298 | not: this._not(), 299 | bool: this._bool() }); 300 | return this; 301 | }, 302 | 303 | // Adds an `or where exists` clause to the query. 304 | orWhereExists: function orWhereExists(callback) { 305 | return this._bool('or').whereExists(callback); 306 | }, 307 | 308 | // Adds a `where not exists` clause to the query. 309 | whereNotExists: function whereNotExists(callback) { 310 | return this._not(true).whereExists(callback); 311 | }, 312 | 313 | // Adds a `or where not exists` clause to the query. 314 | orWhereNotExists: function orWhereNotExists(callback) { 315 | return this._bool('or').whereNotExists(callback); 316 | }, 317 | 318 | // Adds a `where in` clause to the query. 319 | whereIn: function whereIn(column, values) { 320 | if (Array.isArray(values) && isEmpty(values)) { 321 | return this.where(this._not()); 322 | } 323 | this._statements.push({ 324 | grouping: 'where', 325 | type: 'whereIn', 326 | column: column, 327 | value: values, 328 | not: this._not(), 329 | bool: this._bool() 330 | }); 331 | return this; 332 | }, 333 | 334 | // Adds a `or where in` clause to the query. 335 | orWhereIn: function orWhereIn(column, values) { 336 | return this._bool('or').whereIn(column, values); 337 | }, 338 | 339 | // Adds a `where not in` clause to the query. 340 | whereNotIn: function whereNotIn(column, values) { 341 | return this._not(true).whereIn(column, values); 342 | }, 343 | 344 | // Adds a `or where not in` clause to the query. 345 | orWhereNotIn: function orWhereNotIn(column, values) { 346 | return this._bool('or')._not(true).whereIn(column, values); 347 | }, 348 | 349 | // Adds a `where null` clause to the query. 350 | whereNull: function whereNull(column) { 351 | this._statements.push({ 352 | grouping: 'where', 353 | type: 'whereNull', 354 | column: column, 355 | not: this._not(), 356 | bool: this._bool() 357 | }); 358 | return this; 359 | }, 360 | 361 | // Adds a `or where null` clause to the query. 362 | orWhereNull: function orWhereNull(column) { 363 | return this._bool('or').whereNull(column); 364 | }, 365 | 366 | // Adds a `where not null` clause to the query. 367 | whereNotNull: function whereNotNull(column) { 368 | return this._not(true).whereNull(column); 369 | }, 370 | 371 | // Adds a `or where not null` clause to the query. 372 | orWhereNotNull: function orWhereNotNull(column) { 373 | return this._bool('or').whereNotNull(column); 374 | }, 375 | 376 | // Adds a `where between` clause to the query. 377 | whereBetween: function whereBetween(column, values) { 378 | assert(Array.isArray(values), 'The second argument to whereBetween must be an array.'); 379 | assert(values.length === 2, 'You must specify 2 values for the whereBetween clause'); 380 | this._statements.push({ 381 | grouping: 'where', 382 | type: 'whereBetween', 383 | column: column, 384 | value: values, 385 | not: this._not(), 386 | bool: this._bool() 387 | }); 388 | return this; 389 | }, 390 | 391 | // Adds a `where not between` clause to the query. 392 | whereNotBetween: function whereNotBetween(column, values) { 393 | return this._not(true).whereBetween(column, values); 394 | }, 395 | 396 | // Adds a `or where between` clause to the query. 397 | orWhereBetween: function orWhereBetween(column, values) { 398 | return this._bool('or').whereBetween(column, values); 399 | }, 400 | 401 | // Adds a `or where not between` clause to the query. 402 | orWhereNotBetween: function orWhereNotBetween(column, values) { 403 | return this._bool('or').whereNotBetween(column, values); 404 | }, 405 | 406 | // Adds a `group by` clause to the query. 407 | groupBy: function groupBy(item) { 408 | if (item instanceof Raw) { 409 | return this.groupByRaw.apply(this, arguments); 410 | } 411 | this._statements.push({ 412 | grouping: 'group', 413 | type: 'groupByBasic', 414 | value: normalizeArr.apply(null, arguments) 415 | }); 416 | return this; 417 | }, 418 | 419 | // Adds a raw `group by` clause to the query. 420 | groupByRaw: function groupByRaw(sql, bindings) { 421 | var raw = sql instanceof Raw ? sql : this.client.raw(sql, bindings); 422 | this._statements.push({ 423 | grouping: 'group', 424 | type: 'groupByRaw', 425 | value: raw 426 | }); 427 | return this; 428 | }, 429 | 430 | // Adds a `order by` clause to the query. 431 | orderBy: function orderBy(column, direction) { 432 | this._statements.push({ 433 | grouping: 'order', 434 | type: 'orderByBasic', 435 | value: column, 436 | direction: direction 437 | }); 438 | return this; 439 | }, 440 | 441 | // Add a raw `order by` clause to the query. 442 | orderByRaw: function orderByRaw(sql, bindings) { 443 | var raw = sql instanceof Raw ? sql : this.client.raw(sql, bindings); 444 | this._statements.push({ 445 | grouping: 'order', 446 | type: 'orderByRaw', 447 | value: raw 448 | }); 449 | return this; 450 | }, 451 | 452 | // Add a union statement to the query. 453 | union: function union(callbacks, wrap) { 454 | if (arguments.length === 1 || arguments.length === 2 && typeof wrap === 'boolean') { 455 | if (!Array.isArray(callbacks)) { 456 | callbacks = [callbacks]; 457 | } 458 | for (var i = 0, l = callbacks.length; i < l; i++) { 459 | this._statements.push({ 460 | grouping: 'union', 461 | clause: 'union', 462 | value: callbacks[i], 463 | wrap: wrap || false 464 | }); 465 | } 466 | } else { 467 | callbacks = normalizeArr.apply(null, arguments).slice(0, arguments.length - 1); 468 | wrap = arguments[arguments.length - 1]; 469 | if (typeof wrap !== 'boolean') { 470 | callbacks.push(wrap); 471 | wrap = false; 472 | } 473 | this.union(callbacks, wrap); 474 | } 475 | return this; 476 | }, 477 | 478 | // Adds a union all statement to the query. 479 | unionAll: function unionAll(callback, wrap) { 480 | this._statements.push({ 481 | grouping: 'union', 482 | clause: 'union all', 483 | value: callback, 484 | wrap: wrap || false 485 | }); 486 | return this; 487 | }, 488 | 489 | // Adds a `having` clause to the query. 490 | having: function having(column, operator, value) { 491 | if (column instanceof Raw && arguments.length === 1) { 492 | return this._havingRaw(column); 493 | } 494 | 495 | // Check if the column is a function, in which case it's 496 | // a having statement wrapped in parens. 497 | if (typeof column === 'function') { 498 | return this.havingWrapped(column); 499 | } 500 | 501 | this._statements.push({ 502 | grouping: 'having', 503 | type: 'havingBasic', 504 | column: column, 505 | operator: operator, 506 | value: value, 507 | bool: this._bool() 508 | }); 509 | return this; 510 | }, 511 | // Adds an `or having` clause to the query. 512 | orHaving: function orHaving() { 513 | return this._bool('or').having.apply(this, arguments); 514 | }, 515 | havingRaw: function havingRaw(sql, bindings) { 516 | return this._havingRaw(sql, bindings); 517 | }, 518 | orHavingRaw: function orHavingRaw(sql, bindings) { 519 | return this._bool('or').havingRaw(sql, bindings); 520 | }, 521 | // Adds a raw `having` clause to the query. 522 | _havingRaw: function _havingRaw(sql, bindings) { 523 | var raw = sql instanceof Raw ? sql : this.client.raw(sql, bindings); 524 | this._statements.push({ 525 | grouping: 'having', 526 | type: 'havingRaw', 527 | value: raw, 528 | bool: this._bool() 529 | }); 530 | return this; 531 | }, 532 | 533 | // Only allow a single "offset" to be set for the current query. 534 | offset: function offset(value) { 535 | this._single.offset = value; 536 | return this; 537 | }, 538 | 539 | // Only allow a single "limit" to be set for the current query. 540 | limit: function limit(value) { 541 | var val = parseInt(value, 10); 542 | if (isNaN(val)) { 543 | debug('A valid integer must be provided to limit'); 544 | } else { 545 | this._single.limit = val; 546 | } 547 | return this; 548 | }, 549 | 550 | // Retrieve the "count" result of the query. 551 | count: function count(column) { 552 | return this._aggregate('count', column || '*'); 553 | }, 554 | 555 | // Retrieve the minimum value of a given column. 556 | min: function min(column) { 557 | return this._aggregate('min', column); 558 | }, 559 | 560 | // Retrieve the maximum value of a given column. 561 | max: function max(column) { 562 | return this._aggregate('max', column); 563 | }, 564 | 565 | // Retrieve the sum of the values of a given column. 566 | sum: function sum(column) { 567 | return this._aggregate('sum', column); 568 | }, 569 | 570 | // Retrieve the average of the values of a given column. 571 | avg: function avg(column) { 572 | return this._aggregate('avg', column); 573 | }, 574 | 575 | // Increments a column's value by the specified amount. 576 | increment: function increment(column, amount) { 577 | return this._counter(column, amount); 578 | }, 579 | 580 | // Decrements a column's value by the specified amount. 581 | decrement: function decrement(column, amount) { 582 | return this._counter(column, amount, '-'); 583 | }, 584 | 585 | // Sets the values for a `select` query, informing that only the first 586 | // row should be returned (limit 1). 587 | first: function first() { 588 | var i, 589 | args = new Array(arguments.length); 590 | for (i = 0; i < args.length; i++) { 591 | args[i] = arguments[i]; 592 | } 593 | this.select.apply(this, args); 594 | this._method = 'first'; 595 | this.limit(1); 596 | return this; 597 | }, 598 | 599 | // Pluck a column from a query. 600 | pluck: function pluck(column) { 601 | this._method = 'pluck'; 602 | this._single.pluck = column; 603 | this._statements.push({ 604 | grouping: 'columns', 605 | type: 'pluck', 606 | value: column 607 | }); 608 | return this; 609 | }, 610 | 611 | // Insert & Update 612 | // ------ 613 | 614 | // Sets the values for an `insert` query. 615 | insert: function insert(values, returning) { 616 | this._method = 'insert'; 617 | if (!isEmpty(returning)) { 618 | this.returning(returning); 619 | } 620 | this._single.insert = values; 621 | return this; 622 | }, 623 | 624 | // Sets the values for an `update`, allowing for both 625 | // `.update(key, value, [returning])` and `.update(obj, [returning])` syntaxes. 626 | update: function update(values, returning) { 627 | var ret, 628 | obj = this._single.update || {}; 629 | this._method = 'update'; 630 | if (typeof values === 'string') { 631 | obj[values] = returning; 632 | if (arguments.length > 2) { 633 | ret = arguments[2]; 634 | } 635 | } else { 636 | var i = -1, 637 | keys = Object.keys(values); 638 | if (this._single.update) { 639 | debug('Update called multiple times with objects.'); 640 | } 641 | while (++i < keys.length) { 642 | obj[keys[i]] = values[keys[i]]; 643 | } 644 | ret = arguments[1]; 645 | } 646 | if (!isEmpty(ret)) { 647 | this.returning(ret); 648 | } 649 | this._single.update = obj; 650 | return this; 651 | }, 652 | 653 | // Sets the returning value for the query. 654 | returning: function returning(_returning) { 655 | this._single.returning = _returning; 656 | return this; 657 | }, 658 | 659 | // Delete 660 | // ------ 661 | 662 | // Executes a delete statement on the query; 663 | 'delete': function _delete(ret) { 664 | this._method = 'del'; 665 | if (!isEmpty(ret)) { 666 | this.returning(ret); 667 | } 668 | return this; 669 | }, 670 | 671 | // Truncates a table, ends the query chain. 672 | truncate: function truncate(tableName) { 673 | this._method = 'truncate'; 674 | if (tableName) { 675 | this._single.table = tableName; 676 | } 677 | return this; 678 | }, 679 | 680 | // Retrieves columns for the table specified by `knex(tableName)` 681 | columnInfo: function columnInfo(column) { 682 | this._method = 'columnInfo'; 683 | this._single.columnInfo = column; 684 | return this; 685 | }, 686 | 687 | // Set a lock for update constraint. 688 | forUpdate: function forUpdate() { 689 | this._single.lock = 'forUpdate'; 690 | return this; 691 | }, 692 | 693 | // Set a lock for share constraint. 694 | forShare: function forShare() { 695 | this._single.lock = 'forShare'; 696 | return this; 697 | }, 698 | 699 | // Takes a JS object of methods to call and calls them 700 | fromJS: function fromJS(obj) { 701 | Object.keys(obj).forEach(function (key) { 702 | var val = obj[key]; 703 | if (typeof this[key] !== 'function') { 704 | debug('Knex Error: unknown key ' + key); 705 | } 706 | if (Array.isArray(val)) { 707 | this[key].apply(this, val); 708 | } else { 709 | this[key](val); 710 | } 711 | }, this); 712 | return this; 713 | }, 714 | 715 | // ---------------------------------------------------------------------- 716 | 717 | // Helper for the incrementing/decrementing queries. 718 | _counter: function _counter(column, amount, symbol) { 719 | var amt = parseInt(amount, 10); 720 | if (isNaN(amt)) { 721 | amt = 1; 722 | } 723 | this._method = 'counter'; 724 | this._single.counter = { 725 | column: column, 726 | amount: amt, 727 | symbol: symbol || '+' 728 | }; 729 | return this; 730 | }, 731 | 732 | // Helper to get or set the "boolFlag" value. 733 | _bool: function _bool(val) { 734 | if (arguments.length === 1) { 735 | this._boolFlag = val; 736 | return this; 737 | } 738 | var ret = this._boolFlag; 739 | this._boolFlag = 'and'; 740 | return ret; 741 | }, 742 | 743 | // Helper to get or set the "notFlag" value. 744 | _not: function _not(val) { 745 | if (arguments.length === 1) { 746 | this._notFlag = val; 747 | return this; 748 | } 749 | var ret = this._notFlag; 750 | this._notFlag = false; 751 | return ret; 752 | }, 753 | 754 | // Helper to get or set the "joinFlag" value. 755 | _joinType: function _joinType(val) { 756 | if (arguments.length === 1) { 757 | this._joinFlag = val; 758 | return this; 759 | } 760 | var ret = this._joinFlag || 'inner'; 761 | this._joinFlag = 'inner'; 762 | return ret; 763 | }, 764 | 765 | // Helper for compiling any aggregate queries. 766 | _aggregate: function _aggregate(method, column) { 767 | this._statements.push({ 768 | grouping: 'columns', 769 | type: 'aggregate', 770 | method: method, 771 | value: column 772 | }); 773 | return this; 774 | } 775 | 776 | }); 777 | 778 | Object.defineProperty(QueryBuilder.prototype, 'or', { 779 | get: function get() { 780 | return this._bool('or'); 781 | } 782 | }); 783 | 784 | Object.defineProperty(QueryBuilder.prototype, 'not', { 785 | get: function get() { 786 | return this._not(true); 787 | } 788 | }); 789 | 790 | QueryBuilder.prototype.select = QueryBuilder.prototype.columns; 791 | QueryBuilder.prototype.column = QueryBuilder.prototype.columns; 792 | QueryBuilder.prototype.andWhereNot = QueryBuilder.prototype.whereNot; 793 | QueryBuilder.prototype.andWhere = QueryBuilder.prototype.where; 794 | QueryBuilder.prototype.andWhereRaw = QueryBuilder.prototype.whereRaw; 795 | QueryBuilder.prototype.andHaving = QueryBuilder.prototype.having; 796 | QueryBuilder.prototype.from = QueryBuilder.prototype.table; 797 | QueryBuilder.prototype.into = QueryBuilder.prototype.table; 798 | QueryBuilder.prototype.del = QueryBuilder.prototype.delete; 799 | 800 | module.exports = QueryBuilder; 801 | -------------------------------------------------------------------------------- /lib/compiler.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | // Query Compiler 4 | // ------- 5 | 'use strict'; 6 | 7 | var debug = require('debug')('cartodb:compiler'); 8 | var Raw = require('./raw'); 9 | var assign = require('./assign'); 10 | var isEmpty = require('./isEmpty'); 11 | var Formatter = require('./formatter'); 12 | 13 | // The "QueryCompiler" takes all of the query statements which 14 | // have been gathered in the "QueryBuilder" and turns them into a 15 | // properly formatted / bound query string. 16 | function QueryCompiler(client, builder) { 17 | this.client = client; 18 | this.method = builder._method || 'select'; 19 | this.options = builder._options || {}; 20 | this.single = builder._single; 21 | var grouped = this.grouped = {}; 22 | builder._statements.forEach(function (item) { 23 | if (!item.grouping) { 24 | return; 25 | } 26 | var val = item.grouping; 27 | if (!(val in grouped)) { 28 | grouped[val] = []; 29 | } 30 | grouped[val].push(item); 31 | }); 32 | this.formatter = new Formatter(client); 33 | } 34 | 35 | var components = ['columns', 'join', 'where', 'union', 'group', 'having', 'order', 'limit', 'offset', 'lock']; 36 | 37 | assign(QueryCompiler.prototype, { 38 | 39 | // Used when the insert call is empty. 40 | _emptyInsertValue: 'default values', 41 | 42 | // Collapse the builder into a single object 43 | toSQL: function toSQL(method) { 44 | method = method || this.method; 45 | var val = this[method](); 46 | var defaults = { 47 | method: method, 48 | options: assign({}, this.options), 49 | bindings: this.formatter.bindings 50 | }; 51 | if (typeof val === 'string') { 52 | val = { sql: val }; 53 | } 54 | 55 | if (method === 'select' && this.single.as) { 56 | defaults.as = this.single.as; 57 | } 58 | var out = assign(defaults, val); 59 | debug(out); 60 | return out; 61 | }, 62 | 63 | // Compiles the `select` statement, or nested sub-selects 64 | // by calling each of the component compilers, trimming out 65 | // the empties, and returning a generated query string. 66 | select: function select() { 67 | var i = -1, 68 | statements = []; 69 | while (++i < components.length) { 70 | statements.push(this[components[i]](this)); 71 | } 72 | return statements.filter(function (item) { 73 | return item; 74 | }).join(' '); 75 | }, 76 | 77 | pluck: function pluck() { 78 | return { 79 | sql: this.select(), 80 | pluck: this.single.pluck 81 | }; 82 | }, 83 | 84 | // Compiles an "insert" query, allowing for multiple 85 | // inserts using a single query statement. 86 | insert: function insert() { 87 | var insertValues = this.single.insert || []; 88 | var sql = 'insert into ' + this.tableName + ' '; 89 | 90 | if (Array.isArray(insertValues)) { 91 | if (insertValues.length === 0) { 92 | return ''; 93 | } 94 | } else if (typeof insertValues === 'object' && isEmpty(insertValues)) { 95 | return sql + this._emptyInsertValue; 96 | } 97 | 98 | var insertData = this._prepInsert(insertValues); 99 | this.__insertValues = insertData.values; 100 | if (typeof insertData === 'string') { 101 | sql += insertData; 102 | } else { 103 | if (insertData.columns.length) { 104 | sql += '(' + this.formatter.columnize(insertData.columns); 105 | sql += ') values ('; 106 | sql += this.formatter.parameterize(insertData.columns); 107 | sql += ')'; 108 | } else if (insertValues.length === 1 && insertValues[0]) { 109 | sql += this._emptyInsertValue; 110 | } else { 111 | sql = ''; 112 | } 113 | } 114 | var out = { 115 | sql: sql, 116 | bindings: insertData.values 117 | }; 118 | if (out.sql !== '') { 119 | out.returning = this.single.returning; 120 | } 121 | return out; 122 | }, 123 | 124 | // Compiles the "update" query. 125 | update: function update() { 126 | var updateData = this._prepUpdate(this.single.update); 127 | var wheres = this.where(); 128 | var returning = this.single.returning; 129 | return { 130 | sql: 'update ' + this.tableName + ' set ' + updateData.join(', ') + (wheres ? ' ' + wheres : '') + this._returning(returning), 131 | returning: returning 132 | }; 133 | }, 134 | 135 | // Compiles the columns in the query, specifying if an item was distinct. 136 | columns: function _columns() { 137 | var distinct = false; 138 | if (this.onlyUnions()) { 139 | return ''; 140 | } 141 | var columns = this.grouped.columns || []; 142 | var i = -1, 143 | sql = []; 144 | if (columns) { 145 | while (++i < columns.length) { 146 | var stmt = columns[i]; 147 | if (stmt.distinct) { 148 | distinct = true; 149 | } 150 | if (stmt.type === 'aggregate') { 151 | sql.push(this.aggregate(stmt)); 152 | } else if (stmt.value && stmt.value.length > 0) { 153 | sql.push(this.formatter.columnize(stmt.value)); 154 | } 155 | } 156 | } 157 | if (sql.length === 0) { 158 | sql = ['*']; 159 | } 160 | return 'select ' + (distinct ? 'distinct ' : '') + sql.join(', ') + (this.tableName ? ' from ' + this.tableName : ''); 161 | }, 162 | 163 | aggregate: function aggregate(stmt) { 164 | var val = stmt.value; 165 | var splitOn = val.toLowerCase().indexOf(' as '); 166 | // Allows us to speciy an alias for the aggregate types. 167 | if (splitOn !== -1) { 168 | var col = val.slice(0, splitOn); 169 | var alias = val.slice(splitOn + 4); 170 | return stmt.method + '(' + this.formatter.wrap(col) + ') as ' + this.formatter.wrap(alias); 171 | } 172 | return stmt.method + '(' + this.formatter.wrap(val) + ')'; 173 | }, 174 | 175 | // Compiles all each of the `join` clauses on the query, 176 | // including any nested join queries. 177 | join: function _join() { 178 | var sql = '', 179 | i = -1, 180 | joins = this.grouped.join; 181 | if (!joins) { 182 | return ''; 183 | } 184 | while (++i < joins.length) { 185 | var join = joins[i]; 186 | if (i > 0) { 187 | sql += ' '; 188 | } 189 | if (join.joinType === 'raw') { 190 | sql += this.formatter.unwrapRaw(join.table); 191 | } else { 192 | sql += join.joinType + ' join ' + this.formatter.wrap(join.table); 193 | var ii = -1; 194 | while (++ii < join.clauses.length) { 195 | var clause = join.clauses[ii]; 196 | sql += ' ' + (ii > 0 ? clause[0] : clause[1]) + ' '; 197 | sql += this.formatter.wrap(clause[2]); 198 | if (clause[3]) { 199 | sql += ' ' + this.formatter.operator(clause[3]); 200 | } 201 | if (clause[4]) { 202 | sql += ' ' + this.formatter.wrap(clause[4]); 203 | } 204 | } 205 | } 206 | } 207 | return sql; 208 | }, 209 | 210 | // Compiles all `where` statements on the query. 211 | where: function where() { 212 | var wheres = this.grouped.where; 213 | if (!wheres) { 214 | return undefined; 215 | } 216 | var i = -1, 217 | sql = []; 218 | while (++i < wheres.length) { 219 | var stmt = wheres[i]; 220 | var val = this[stmt.type](stmt); 221 | if (val) { 222 | if (sql.length === 0) { 223 | sql[0] = 'where'; 224 | } else { 225 | sql.push(stmt.bool); 226 | } 227 | sql.push(val); 228 | } 229 | } 230 | return sql.length > 1 ? sql.join(' ') : ''; 231 | }, 232 | 233 | group: function group() { 234 | return this._groupsOrders('group'); 235 | }, 236 | 237 | order: function order() { 238 | return this._groupsOrders('order'); 239 | }, 240 | 241 | // Compiles the `having` statements. 242 | having: function having() { 243 | var havings = this.grouped.having; 244 | if (!havings) { 245 | return ''; 246 | } 247 | var sql = ['having']; 248 | for (var i = 0, l = havings.length; i < l; i++) { 249 | var str = '', 250 | s = havings[i]; 251 | if (i !== 0) { 252 | str = s.bool + ' '; 253 | } 254 | if (s.type === 'havingBasic') { 255 | sql.push(str + this.formatter.columnize(s.column) + ' ' + this.formatter.operator(s.operator) + ' ' + this.formatter.parameter(s.value)); 256 | } else { 257 | if (s.type === 'whereWrapped') { 258 | var val = this.whereWrapped(s); 259 | if (val) { 260 | sql.push(val); 261 | } 262 | } else { 263 | sql.push(str + this.formatter.unwrapRaw(s.value)); 264 | } 265 | } 266 | } 267 | return sql.length > 1 ? sql.join(' ') : ''; 268 | }, 269 | 270 | // Compile the "union" queries attached to the main query. 271 | union: function _union() { 272 | var onlyUnions = this.onlyUnions(); 273 | var unions = this.grouped.union; 274 | if (!unions) { 275 | return ''; 276 | } 277 | var sql = ''; 278 | for (var i = 0, l = unions.length; i < l; i++) { 279 | var union = unions[i]; 280 | if (i > 0) { 281 | sql += ' '; 282 | } 283 | if (i > 0 || !onlyUnions) { 284 | sql += union.clause + ' '; 285 | } 286 | var statement = this.formatter.rawOrFn(union.value); 287 | if (statement) { 288 | if (union.wrap) { 289 | sql += '('; 290 | } 291 | sql += statement; 292 | if (union.wrap) { 293 | sql += ')'; 294 | } 295 | } 296 | } 297 | return sql; 298 | }, 299 | 300 | // If we haven't specified any columns or a `tableName`, we're assuming this 301 | // is only being used for unions. 302 | onlyUnions: function onlyUnions() { 303 | return !this.grouped.columns && this.grouped.union && !this.tableName; 304 | }, 305 | 306 | limit: function limit() { 307 | var noLimit = !this.single.limit && this.single.limit !== 0; 308 | if (noLimit) { 309 | return ''; 310 | } 311 | return 'limit ' + this.formatter.parameter(this.single.limit); 312 | }, 313 | 314 | offset: function offset() { 315 | if (!this.single.offset) { 316 | return ''; 317 | } 318 | return 'offset ' + this.formatter.parameter(this.single.offset); 319 | }, 320 | 321 | // Compiles a `delete` query. 322 | del: function del() { 323 | // Make sure tableName is processed by the formatter first. 324 | var tableName = this.tableName; 325 | var wheres = this.where(); 326 | var sql = 'delete from ' + tableName + (wheres ? ' ' + wheres : ''); 327 | var returning = this.single.returning; 328 | return { 329 | sql: sql + this._returning(returning), 330 | returning: returning 331 | }; 332 | }, 333 | 334 | // Compiles a `truncate` query. 335 | truncate: function truncate() { 336 | return 'truncate ' + this.tableName + ' restart identity'; 337 | }, 338 | 339 | // Compiles the "locks". 340 | lock: function lock() { 341 | if (this.single.lock) { 342 | if (!this.client.transacting) { 343 | debug('You are attempting to perform a "lock" command outside of a transaction.'); 344 | } else { 345 | return this[this.single.lock](); 346 | } 347 | } 348 | }, 349 | 350 | // Compile the "counter". 351 | counter: function _counter() { 352 | var counter = this.single.counter; 353 | var toUpdate = {}; 354 | toUpdate[counter.column] = this.client.raw(this.formatter.wrap(counter.column) + ' ' + (counter.symbol || '+') + ' ' + counter.amount); 355 | this.single.update = toUpdate; 356 | return this.update(); 357 | }, 358 | 359 | // Where Clause 360 | // ------ 361 | 362 | whereIn: function whereIn(statement) { 363 | if (Array.isArray(statement.column)) { 364 | return this.multiWhereIn(statement); 365 | } 366 | return this.formatter.wrap(statement.column) + ' ' + this._not(statement, 'in ') + this.wrap(this.formatter.parameterize(statement.value)); 367 | }, 368 | 369 | multiWhereIn: function multiWhereIn(statement) { 370 | var i = -1, 371 | sql = '(' + this.formatter.columnize(statement.column) + ') '; 372 | sql += this._not(statement, 'in ') + '(('; 373 | while (++i < statement.value.length) { 374 | if (i !== 0) { 375 | sql += '),('; 376 | } 377 | sql += this.formatter.parameterize(statement.value[i]); 378 | } 379 | return sql + '))'; 380 | }, 381 | 382 | whereNull: function whereNull(statement) { 383 | return this.formatter.wrap(statement.column) + ' is ' + this._not(statement, 'null'); 384 | }, 385 | 386 | // Compiles a basic "where" clause. 387 | whereBasic: function whereBasic(statement) { 388 | return this._not(statement, '') + this.formatter.wrap(statement.column) + ' ' + this.formatter.operator(statement.operator) + ' ' + this.formatter.parameter(statement.value); 389 | }, 390 | 391 | whereExists: function whereExists(statement) { 392 | return this._not(statement, 'exists') + ' (' + this.formatter.rawOrFn(statement.value) + ')'; 393 | }, 394 | 395 | whereWrapped: function whereWrapped(statement) { 396 | var val = this.formatter.rawOrFn(statement.value, 'where'); 397 | return val && this._not(statement, '') + '(' + val.slice(6) + ')' || ''; 398 | }, 399 | 400 | whereBetween: function whereBetween(statement) { 401 | return this.formatter.wrap(statement.column) + ' ' + this._not(statement, 'between') + ' ' + statement.value.map(this.formatter.parameter, this.formatter).join(' and '); 402 | }, 403 | 404 | // Compiles a "whereRaw" query. 405 | whereRaw: function whereRaw(statement) { 406 | return this.formatter.unwrapRaw(statement.value); 407 | }, 408 | 409 | wrap: function wrap(str) { 410 | if (str.charAt(0) !== '(') { 411 | return '(' + str + ')'; 412 | } 413 | return str; 414 | }, 415 | 416 | // Determines whether to add a "not" prefix to the where clause. 417 | _not: function _not(statement, str) { 418 | if (statement.not) { 419 | return 'not ' + str; 420 | } 421 | return str; 422 | }, 423 | 424 | _prepInsert: function _prepInsert(data) { 425 | var isRaw = this.formatter.rawOrFn(data); 426 | if (isRaw) { 427 | return isRaw; 428 | } 429 | if (!Array.isArray(data)) { 430 | data = data ? [data] : []; 431 | } 432 | var columns = {}; 433 | data.forEach(function (datum) { 434 | Object.keys(datum).forEach(function (key) { 435 | columns[key] = true; 436 | }); 437 | }); 438 | columns = Object.keys(columns); 439 | var values = data.map(function (datum) { 440 | var row = new Array(columns.length); 441 | columns.forEach(function (key, i) { 442 | row[i] = datum[key]; 443 | }); 444 | return row; 445 | }); 446 | return { 447 | columns: columns, 448 | values: values 449 | }; 450 | }, 451 | 452 | // "Preps" the update. 453 | _prepUpdate: function _prepUpdate(data) { 454 | var vals = []; 455 | var sorted = Object.keys(data).sort(); 456 | var i = -1; 457 | while (++i < sorted.length) { 458 | vals.push(this.formatter.wrap(sorted[i]) + ' = ' + this.formatter.parameter(data[sorted[i]])); 459 | } 460 | return vals; 461 | }, 462 | 463 | // Compiles the `order by` statements. 464 | _groupsOrders: function _groupsOrders(type) { 465 | var items = this.grouped[type]; 466 | if (!items) { 467 | return ''; 468 | } 469 | var formatter = this.formatter; 470 | var sql = items.map(function (item) { 471 | return (item.value instanceof Raw ? formatter.unwrapRaw(item.value) : formatter.columnize(item.value)) + (type === 'order' && item.type !== 'orderByRaw' ? ' ' + formatter.direction(item.direction) : ''); 472 | }); 473 | return sql.length ? type + ' by ' + sql.join(', ') : ''; 474 | }, 475 | 476 | _returning: function _returning(value) { 477 | return value ? ' returning ' + this.formatter.columnize(value) : ''; 478 | }, 479 | 480 | forUpdate: function forUpdate() { 481 | return 'for update'; 482 | }, 483 | 484 | forShare: function forShare() { 485 | return 'for share'; 486 | }, 487 | 488 | // Compiles a columnInfo query 489 | columnInfo: function columnInfo() { 490 | var column = this.single.columnInfo; 491 | return { 492 | sql: 'select * from information_schema.columns where table_name = ? and table_catalog = ?', 493 | bindings: [this.single.table, this.client.database()], 494 | output: function output(resp) { 495 | var out = resp.rows.reduce(function (columns, val) { 496 | columns[val.column_name] = { 497 | type: val.data_type, 498 | maxLength: val.character_maximum_length, 499 | nullable: val.is_nullable === 'YES', 500 | defaultValue: val.column_default 501 | }; 502 | return columns; 503 | }, {}); 504 | return column && out[column] || out; 505 | } 506 | }; 507 | } 508 | 509 | }); 510 | 511 | QueryCompiler.prototype.first = QueryCompiler.prototype.select; 512 | 513 | // Get the table name, wrapping it if necessary. 514 | // Implemented as a property to prevent ordering issues as described in #704. 515 | Object.defineProperty(QueryCompiler.prototype, 'tableName', { 516 | get: function get() { 517 | if (!this._tableName) { 518 | // Only call this.formatter.wrap() the first time this property is accessed. 519 | this._tableName = this.single.table ? this.formatter.wrap(this.single.table) : ''; 520 | } 521 | return this._tableName; 522 | } 523 | }); 524 | 525 | module.exports = QueryCompiler; 526 | -------------------------------------------------------------------------------- /lib/formatter.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | 'use strict'; 4 | 5 | var QueryBuilder = require('./builder'); 6 | var Raw = require('./raw'); 7 | var assign = require('./assign'); 8 | 9 | // Valid values for the `order by` clause generation. 10 | var orderBys = ['asc', 'desc']; 11 | 12 | // Turn this into a lookup map 13 | var operators = Object.create(null); 14 | ['=', '<', '>', '<=', '>=', '<>', '!=', 'like', 'not like', 'between', 'ilike', '&', '|', '^', '<<', '>>', 'rlike', 'regexp', 'not regexp', '~', '~*', '!~', '!~*', '#', '&&', '@>', '<@', '||'].forEach(function (key) { 15 | operators[key] = true; 16 | }); 17 | 18 | function Formatter(client) { 19 | this.client = client; 20 | this.bindings = []; 21 | } 22 | 23 | assign(Formatter.prototype, { 24 | 25 | // Accepts a string or array of columns to wrap as appropriate. 26 | columnize: function columnize(target) { 27 | var columns = typeof target === 'string' ? [target] : target; 28 | var str = '', 29 | i = -1; 30 | while (++i < columns.length) { 31 | if (i > 0) { 32 | str += ', '; 33 | } 34 | str += this.wrap(columns[i]); 35 | } 36 | return str; 37 | }, 38 | 39 | // Turns a list of values into a list of ?'s, joining them with commas unless 40 | // a "joining" value is specified (e.g. ' and ') 41 | parameterize: function parameterize(values, notSetValue) { 42 | if (typeof values === 'function') { 43 | return this.parameter(values); 44 | } 45 | values = Array.isArray(values) ? values : [values]; 46 | var str = '', 47 | i = -1; 48 | while (++i < values.length) { 49 | if (i > 0) { 50 | str += ', '; 51 | } 52 | str += this.parameter(values[i] === undefined ? notSetValue : values[i]); 53 | } 54 | return str; 55 | }, 56 | 57 | // Checks whether a value is a function... if it is, we compile it 58 | // otherwise we check whether it's a raw 59 | parameter: function parameter(value) { 60 | if (typeof value === 'function') { 61 | return this.outputQuery(this.compileCallback(value), true); 62 | } 63 | return this.unwrapRaw(value, true) || '?'; 64 | }, 65 | 66 | unwrapRaw: function unwrapRaw(value, isParameter) { 67 | var query; 68 | if (value instanceof QueryBuilder) { 69 | query = this.client.queryCompiler(value).toSQL(); 70 | if (query.bindings) { 71 | this.bindings = this.bindings.concat(query.bindings); 72 | } 73 | return this.outputQuery(query, isParameter); 74 | } 75 | if (value instanceof Raw) { 76 | query = value.toSQL(); 77 | if (query.bindings) { 78 | this.bindings = this.bindings.concat(query.bindings); 79 | } 80 | return query.sql; 81 | } 82 | if (isParameter) { 83 | this.bindings.push(value); 84 | } 85 | }, 86 | 87 | rawOrFn: function rawOrFn(value, method) { 88 | if (typeof value === 'function') { 89 | return this.outputQuery(this.compileCallback(value, method)); 90 | } 91 | return this.unwrapRaw(value) || ''; 92 | }, 93 | 94 | // Puts the appropriate wrapper around a value depending on the database 95 | // engine, unless it's a knex.raw value, in which case it's left alone. 96 | wrap: function wrap(value) { 97 | var raw; 98 | if (typeof value === 'function') { 99 | return this.outputQuery(this.compileCallback(value), true); 100 | } 101 | raw = this.unwrapRaw(value); 102 | if (raw) { 103 | return raw; 104 | } 105 | if (typeof value === 'number') { 106 | return value; 107 | } 108 | return this._wrapString(value + ''); 109 | }, 110 | 111 | alias: function alias(first, second) { 112 | return first + ' as ' + second; 113 | }, 114 | 115 | // The operator method takes a value and returns something or other. 116 | operator: function operator(value) { 117 | var raw = this.unwrapRaw(value); 118 | if (raw) { 119 | return raw; 120 | } 121 | if (operators[(value || '').toLowerCase()] !== true) { 122 | throw new TypeError('The operator "' + value + '" is not permitted'); 123 | } 124 | return value; 125 | }, 126 | 127 | // Specify the direction of the ordering. 128 | direction: function direction(value) { 129 | var raw = this.unwrapRaw(value); 130 | if (raw) { 131 | return raw; 132 | } 133 | return orderBys.indexOf((value || '').toLowerCase()) !== -1 ? value : 'asc'; 134 | }, 135 | 136 | // Compiles a callback using the query builder. 137 | compileCallback: function compileCallback(callback, method) { 138 | var client = this.client; 139 | 140 | // Build the callback 141 | var builder = client.queryBuilder(); 142 | callback.call(builder, builder); 143 | 144 | // Compile the callback, using the current formatter (to track all bindings). 145 | var compiler = client.queryCompiler(builder); 146 | compiler.formatter = this; 147 | 148 | // Return the compiled & parameterized sql. 149 | return compiler.toSQL(method || 'select'); 150 | }, 151 | 152 | // Ensures the query is aliased if necessary. 153 | outputQuery: function outputQuery(compiled, isParameter) { 154 | var sql = compiled.sql || ''; 155 | if (sql) { 156 | if (compiled.method === 'select' && (isParameter || compiled.as)) { 157 | sql = '(' + sql + ')'; 158 | if (compiled.as) { 159 | return this.alias(sql, this.wrap(compiled.as)); 160 | } 161 | } 162 | } 163 | return sql; 164 | }, 165 | 166 | // Coerce to string to prevent strange errors when it's not a string. 167 | _wrapString: function _wrapString(value) { 168 | var segments, 169 | asIndex = value.toLowerCase().indexOf(' as '); 170 | if (asIndex !== -1) { 171 | var first = value.slice(0, asIndex); 172 | var second = value.slice(asIndex + 4); 173 | return this.alias(this.wrap(first), this.wrap(second)); 174 | } 175 | var i = -1, 176 | wrapped = []; 177 | segments = value.split('.'); 178 | while (++i < segments.length) { 179 | value = segments[i]; 180 | if (i === 0 && segments.length > 1) { 181 | wrapped.push(this.wrap((value || '').trim())); 182 | } else { 183 | wrapped.push(this.client.wrapIdentifier((value || '').trim())); 184 | } 185 | } 186 | return wrapped.join('.'); 187 | } 188 | 189 | }); 190 | 191 | module.exports = Formatter; 192 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var debug = require('debug')('cartodb'); 3 | var debugUpload = require('debug')('cartodb:upload'); 4 | var qs = require('querystringparser'); 5 | var url = require('url'); 6 | var https = require('https'); 7 | var stream = require('readable-stream'); 8 | var PassThrough = stream.PassThrough; 9 | var JSONStream = require('jsonstream3'); 10 | var methods = require('./methods'); 11 | var Builder = require('./builder'); 12 | var Promise = require('bluebird'); 13 | var debugBatch = require('debug')('cartodb:batch'); 14 | var debugrs = require('debug')('cartodb:readstream'); 15 | var createWriteStream = require('./write-stream'); 16 | module.exports = function (user, key, opts) { 17 | var client = new CartoDB(user, key, opts); 18 | function cartodb(tableName) { 19 | var qb = client.queryBuilder(); 20 | return tableName ? qb.table(tableName) : qb; 21 | } 22 | cartodb.raw = function raw() { 23 | return client.raw.apply(client, arguments); 24 | }; 25 | cartodb.createWriteStream = createWriteStream(cartodb); 26 | methods.forEach(function (method) { 27 | cartodb[method] = function () { 28 | var builder = client.queryBuilder(); 29 | return builder[method].apply(builder, arguments); 30 | }; 31 | }); 32 | Object.defineProperties(cartodb, { 33 | schema: { 34 | get: function get() { 35 | return client.schemaBuilder(); 36 | } 37 | } 38 | }); 39 | return cartodb; 40 | }; 41 | 42 | function CartoDB(user, key, opts) { 43 | this.url = createBaseUrl(user, opts); 44 | this.key = key; 45 | this.isBatch = false; 46 | this.jobs = new Set(); 47 | this.exiting = false; 48 | this.jobCB = createJobCB(this) 49 | process.on('exit', ()=>{ 50 | if (this.jobs.size) { 51 | console.log('batch jobs'); 52 | for (let job of this.jobs) { 53 | console.log(job); 54 | } 55 | } 56 | }) 57 | } 58 | CartoDB.prototype.batch = function () { 59 | this.isBatch = true; 60 | return this; 61 | } 62 | CartoDB.prototype.onSuccess = function (query) { 63 | if (typeof query === 'string') { 64 | this._onSuccess = query; 65 | } else { 66 | this._onSuccess = query.toString(); 67 | } 68 | return this; 69 | } 70 | CartoDB.prototype.onError = function (query) { 71 | if (typeof query === 'string') { 72 | this._onError = query; 73 | } else { 74 | this._onError = query.toString(); 75 | } 76 | return this; 77 | } 78 | function createBaseUrl (user, opts) { 79 | if (!opts || (!opts.domain && !opts.subdomainless)) { 80 | return `https://${user}.carto.com/api/v2/sql`; 81 | } 82 | if (opts.domain) { 83 | if (opts.subdomainless) { 84 | return `https://${opts.domain}/user/${user}/api/v2/sql`; 85 | } else { 86 | return `https://${user}.${opts.domain}/api/v2/sql`; 87 | } 88 | } else if (opts.subdomainless) { 89 | return `https://carto.com/user/${user}/api/v2/sql`; 90 | } 91 | } 92 | CartoDB.prototype.request = function (sql) { 93 | var out = new PassThrough(); 94 | var query = qs.stringify({ 95 | api_key: this.key, 96 | q: sql 97 | }); 98 | var opts = url.parse(this.url); 99 | opts.method = 'POST'; 100 | opts.headers = { 101 | 'Content-Type': 'application/x-www-form-urlencoded', 102 | 'Content-Length': query.length 103 | }; 104 | makeRequest(opts, out, query); 105 | return out; 106 | }; 107 | function makeRequest(opts, out, query) { 108 | var returned = false; 109 | var retried = false; 110 | debugUpload('making request'); 111 | var req = https.request(opts, function (resp) { 112 | returned = true; 113 | if (retried) { 114 | return; 115 | } 116 | out.emit('headers', resp.headers); 117 | out.emit('code', resp.statusCode); 118 | debug('code: ' + resp.statusCode); 119 | resp.on('error', function (e) { 120 | out.emit('error', e); 121 | }); 122 | resp.pipe(out); 123 | }); 124 | req.on('error', function (e) { 125 | debugUpload('error ' + e && e.stack || e); 126 | if (returned) { 127 | debugUpload('already returned not retrying'); 128 | return; 129 | } 130 | debugUpload('going to retry'); 131 | retried = true; 132 | makeRequest(opts, out, query); 133 | }); 134 | req.end(query); 135 | } 136 | CartoDB.prototype.createReadStream = function (sql) { 137 | var out = JSONStream.parse('rows.*'); 138 | //var out = new PassThrough(); 139 | this.request(sql).on('error', function (e) { 140 | out.emit('error', e); 141 | }).on('headers', function (e) { 142 | out.emit('headers', e); 143 | }).on('code', function (e) { 144 | if (e > 299) { 145 | var data = []; 146 | this.on('data', function (d) { 147 | data.push(d); 148 | }).on('finish', function () { 149 | var err = Buffer.concat(data).toString(); 150 | debugrs(err); 151 | debugrs(sql); 152 | out.emit('error', new Error(err)); 153 | }); 154 | } else { 155 | this.pipe(out); 156 | } 157 | out.emit('code', e); 158 | }); 159 | return out; 160 | }; 161 | function quickReq(opts, data) { 162 | return new Promise(function (yes, no) { 163 | var req = https.request(opts, function (res) { 164 | var out = ''; 165 | res.on('data', function (d) { 166 | out += d.toString(); 167 | }); 168 | res.on('end', function () { 169 | var json; 170 | if (res.statusCode > 299) { 171 | return no(new Error(out)); 172 | } 173 | try { 174 | json = JSON.parse(out); 175 | } catch (e) { 176 | return no(new Error(out)); 177 | } 178 | if (json) { 179 | yes(json); 180 | } else { 181 | no(new Error(out)); 182 | } 183 | }); 184 | res.on('error', function (e) { 185 | no(e); 186 | }); 187 | }); 188 | req.on('error', function (e) { 189 | no(e); 190 | }); 191 | if (data) { 192 | req.write(data); 193 | } 194 | req.end(); 195 | }); 196 | } 197 | function get(url) { 198 | return new Promise(function (yes, no) { 199 | https.get(url, function (res) { 200 | var out = ''; 201 | res.on('data', function (d) { 202 | out += d.toString(); 203 | }); 204 | res.on('end', function () { 205 | var json; 206 | if (res.statusCode > 299) { 207 | return no(new Error(out)); 208 | } 209 | try { 210 | json = JSON.parse(out); 211 | } catch (e) { 212 | return no(new Error(out)); 213 | } 214 | if (json) { 215 | yes(json); 216 | } else { 217 | no(new Error(out)); 218 | } 219 | }); 220 | res.on('error', function (e) { 221 | no(e); 222 | }); 223 | }).on('error', no); 224 | }); 225 | } 226 | function poll(url, num) { 227 | debugBatch('polling'); 228 | return Promise.delay(50).then(function () { 229 | return get(url).then(function (resp) { 230 | debugBatch(JSON.stringify(resp)); 231 | if (resp.status === 'done') { 232 | return { 233 | ok: true 234 | }; 235 | } 236 | if (resp.status === 'pending' || resp.status === 'running') { 237 | return poll(url); 238 | } 239 | if (resp.query && resp.query.query && resp.query.query.length) { 240 | let query = resp.query.query[0]; 241 | if (query.failed_reason) { 242 | throw new Error(query.failed_reason); 243 | } 244 | } 245 | throw new Error(resp.failed_reason || `query failed with status "${resp.status}"`); 246 | }, e=> { 247 | if (e && e.code && e.code === 'ETIMEDOUT') { 248 | num = num || 0; 249 | if (num >= 3) { 250 | throw e; 251 | } 252 | return poll(url, num + 1); 253 | } 254 | throw e; 255 | }); 256 | }) 257 | } 258 | function createDelete(self, job) { 259 | let opts = url.parse(self.url + '/job/' + job + '?' + qs.stringify({ 260 | api_key: self.key 261 | })) 262 | opts.method = 'delete' 263 | return quickReq(opts) 264 | } 265 | function makeDelete(self, jobs) { 266 | return new Promise(function (yes) { 267 | let toFinish = jobs.length 268 | jobs.forEach(function (job) { 269 | createDelete(self, job).then(function () { 270 | toFinish--; 271 | console.log('canceled', job); 272 | self.jobs.delete(job); 273 | if (!toFinish) { 274 | yes(); 275 | } 276 | }, function () { 277 | toFinish--; 278 | console.log('error canceling', job) 279 | if (!toFinish) { 280 | yes(); 281 | } 282 | }) 283 | }) 284 | }); 285 | } 286 | 287 | function createJobCB(self) { 288 | return jobCB; 289 | function jobCB() { 290 | if (self.exiting) { 291 | console.log('good bye'); 292 | process.exit(); 293 | } 294 | self.exiting = true; 295 | if (!self.jobs.size) { 296 | return; 297 | } 298 | let jobs = Array.from(self.jobs); 299 | console.log(`there are ${jobs.length} batch jobs still in progress`); 300 | for (let job in jobs) { 301 | console.log(job) 302 | } 303 | console.log('deleting'); 304 | makeDelete(self, jobs).then(function () { 305 | console.log('all set'); 306 | process.exit(); 307 | }) 308 | } 309 | } 310 | CartoDB.prototype.startBatch = function(id) { 311 | if (this.jobs.has(id)) { 312 | return; 313 | } 314 | debugBatch('starting batch', id); 315 | this.jobs.add(id); 316 | if (this.jobs.size === 1) { 317 | process.on('SIGINT', this.jobCB); 318 | } 319 | } 320 | CartoDB.prototype.cleanupBatch = function (id) { 321 | if (!this.jobs.has(id)) { 322 | return; 323 | } 324 | debugBatch('finished batch', id) 325 | this.jobs.delete(id); 326 | if (!this.jobs.size) { 327 | process.removeListener('SIGINT', this.jobCB); 328 | } 329 | } 330 | CartoDB.prototype.batchQuery = function (sql, callback) { 331 | debugBatch(sql) 332 | var innerQuery = { 333 | query: sql 334 | }; 335 | if (this._onSuccess) { 336 | innerQuery.onsuccess = this._onSuccess; 337 | } 338 | if (this._onError) { 339 | innerQuery.onerror = this._onError; 340 | } 341 | 342 | var query = JSON.stringify({ 343 | query: { 344 | query: [innerQuery] 345 | } 346 | }); 347 | var thisUrl = this.url + '/job?' + qs.stringify({ 348 | api_key: this.key 349 | }); 350 | var opts = url.parse(thisUrl); 351 | opts.method = 'POST'; 352 | opts.headers = { 353 | 'Content-Type': 'application/json', 354 | 'Content-Length': query.length 355 | }; 356 | var self = this; 357 | let id; 358 | return quickReq(opts, query).then(function (data) { 359 | id = data.job_id 360 | self.startBatch(data.job_id); 361 | return poll(self.url + '/job/' + data.job_id + '?' + qs.stringify({ 362 | api_key: self.key 363 | })); 364 | }).then(function (resp) { 365 | self.cleanupBatch(id); 366 | process.nextTick(function () { 367 | callback(null, resp); 368 | }) 369 | }).catch(function (e) { 370 | if (id) { 371 | self.cleanupBatch(id); 372 | } 373 | process.nextTick(function () { 374 | callback(e); 375 | }) 376 | }) 377 | } 378 | CartoDB.prototype.query = function (sql, callback) { 379 | var out = []; 380 | var called = false; 381 | this.createReadStream(sql).on('data', function (d) { 382 | out.push(d); 383 | }).on('error', function (e) { 384 | if (called) { 385 | return; 386 | } 387 | called = true; 388 | callback(e); 389 | }).on('finish', function () { 390 | process.nextTick(function () { 391 | if (called) { 392 | return; 393 | } 394 | called = true; 395 | callback(null, out); 396 | }); 397 | }); 398 | }; 399 | CartoDB.prototype.exec = function (sql, cb) { 400 | debug(sql); 401 | if (typeof cb === 'function') { 402 | if (this.isBatch) { 403 | this.isBatch = false; 404 | return this.batchQuery(sql, cb); 405 | } 406 | return this.query(sql, cb); 407 | } else { 408 | return this.createReadStream(sql); 409 | } 410 | }; 411 | CartoDB.prototype.QueryCompiler = require('./compiler'); 412 | CartoDB.prototype.queryCompiler = function queryCompiler(builder) { 413 | return new this.QueryCompiler(this, builder); 414 | }; 415 | CartoDB.prototype.QueryBuilder = require('./builder'); 416 | CartoDB.prototype.queryBuilder = function queryBuilder() { 417 | return new this.QueryBuilder(this); 418 | }; 419 | CartoDB.prototype.Raw = require('./raw'); 420 | CartoDB.prototype.raw = function _raw() { 421 | var raw = new this.Raw(this); 422 | return raw.set.apply(raw, arguments); 423 | }; 424 | 425 | CartoDB.prototype.SchemaBuilder = require('./schema/builder'); 426 | CartoDB.prototype.schemaBuilder = function schemaBuilder() { 427 | return new this.SchemaBuilder(this); 428 | }; 429 | 430 | CartoDB.prototype.SchemaCompiler = require('./schema/compiler'); 431 | CartoDB.prototype.schemaCompiler = function schemaCompiler(builder) { 432 | return new this.SchemaCompiler(this, builder); 433 | }; 434 | 435 | CartoDB.prototype.TableBuilder = require('./schema/tablebuilder'); 436 | CartoDB.prototype.tableBuilder = function tableBuilder(type, tableName, fn) { 437 | return new this.TableBuilder(this, type, tableName, fn); 438 | }; 439 | 440 | CartoDB.prototype.TableCompiler = require('./schema/tablecompiler'); 441 | CartoDB.prototype.tableCompiler = function tableCompiler(tableBuilder) { 442 | return new this.TableCompiler(this, tableBuilder); 443 | }; 444 | 445 | CartoDB.prototype.ColumnBuilder = require('./schema/columnbuilder'); 446 | CartoDB.prototype.columnBuilder = function columnBuilder(tableBuilder, type, args) { 447 | return new this.ColumnBuilder(this, tableBuilder, type, args); 448 | }; 449 | 450 | CartoDB.prototype.ColumnCompiler = require('./schema/columncompiler'); 451 | CartoDB.prototype.columnCompiler = function columnCompiler(tableBuilder, columnBuilder) { 452 | return new this.ColumnCompiler(this, tableBuilder, columnBuilder); 453 | }; 454 | 455 | CartoDB.prototype.Formatter = require('./formatter'); 456 | CartoDB.prototype.formatter = function formatter() { 457 | return new this.Formatter(this); 458 | }; 459 | 460 | CartoDB.prototype.wrapIdentifier = function wrapIdentifier(value) { 461 | if (value === '*') { 462 | return value; 463 | } 464 | var matched = value.match(/(.*?)(\[[0-9]\])/); 465 | if (matched) { 466 | return this.wrapIdentifier(matched[1]) + matched[2]; 467 | } 468 | return '"' + value.replace(/"/g, '""') + '"'; 469 | }; 470 | 471 | methods.forEach(function (method) { 472 | CartoDB.prototype[method] = function () { 473 | var builder = new Builder(this); 474 | return builder[method].apply(builder, arguments); 475 | }; 476 | }); 477 | -------------------------------------------------------------------------------- /lib/interface.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var SqlString = require('./string'); 3 | var Promise = require('bluebird'); 4 | var debug = require('debug')('cartodb:interface'); 5 | module.exports = Interface; 6 | function Interface () {} 7 | 8 | Interface.prototype.toQuery = function (tz) { 9 | var data = this.toSQL(this._method); 10 | if (!Array.isArray(data)) { 11 | data = [data]; 12 | } 13 | debug(data); 14 | var out = '\n' + data.map(function (statement) { 15 | return SqlString.format(statement.sql, statement.bindings, tz, statement.method); 16 | }, this).join(';\n') + ';\n'; 17 | if (this._noTransaction) { 18 | return out; 19 | } 20 | return 'BEGIN;' + out + 'COMMIT;'; 21 | }; 22 | 23 | Interface.prototype.exec = function (cb) { 24 | var query = this.toQuery(); 25 | var callback = cb; 26 | var self = this; 27 | if (this._tableName) { 28 | callback = function (err, resp) { 29 | if (err) { 30 | return cb(err); 31 | } 32 | return self.client.exec('select cdb_cartodbfytable(\'' + self._tableName + '\');', function (err) { 33 | if (err) { 34 | return cb(err); 35 | } 36 | cb(null, resp); 37 | }); 38 | }; 39 | } 40 | return this.client.exec(query, callback); 41 | }; 42 | Interface.prototype.then = function (resolve, reject) { 43 | var self = this; 44 | return new Promise(function (resolve, reject) { 45 | self.exec(function (err, resp) { 46 | if (err) { 47 | return reject(err); 48 | } else { 49 | resolve(resp); 50 | } 51 | }); 52 | }).then(resolve, reject); 53 | }; 54 | Interface.prototype.catch = function (reject) { 55 | return this.then(null, reject); 56 | }; 57 | Interface.prototype.stream = function () { 58 | return this.exec(); 59 | }; 60 | -------------------------------------------------------------------------------- /lib/isEmpty.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function isEmpty(item) { 4 | if (item === null || item === void 0) { 5 | return true; 6 | } 7 | if (typeof item.length === 'number' && item.length > -1) { 8 | return !item.length; 9 | } 10 | return !Object.keys(item).length; 11 | }; 12 | -------------------------------------------------------------------------------- /lib/joinclause.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | 'use strict'; 4 | 5 | var assign = require('./assign'); 6 | 7 | // JoinClause 8 | // ------- 9 | 10 | // The "JoinClause" is an object holding any necessary info about a join, 11 | // including the type, and any associated tables & columns being joined. 12 | function JoinClause(table, type) { 13 | this.table = table; 14 | this.joinType = type; 15 | this.and = this; 16 | this.clauses = []; 17 | } 18 | 19 | assign(JoinClause.prototype, { 20 | 21 | grouping: 'join', 22 | 23 | // Adds an "on" clause to the current join object. 24 | on: function on(first, operator, second) { 25 | var data, 26 | bool = this._bool(); 27 | switch (arguments.length) { 28 | case 1: 29 | { 30 | if (typeof first === 'object' && typeof first.toSQL !== 'function') { 31 | var i = -1, 32 | keys = Object.keys(first); 33 | var method = bool === 'or' ? 'orOn' : 'on'; 34 | while (++i < keys.length) { 35 | this[method](keys[i], first[keys[i]]); 36 | } 37 | return this; 38 | } else { 39 | data = [bool, 'on', first]; 40 | } 41 | break; 42 | } 43 | case 2: 44 | data = [bool, 'on', first, '=', operator]; 45 | break; 46 | default: 47 | data = [bool, 'on', first, operator, second]; 48 | } 49 | this.clauses.push(data); 50 | return this; 51 | }, 52 | 53 | // Adds a "using" clause to the current join. 54 | using: function using(table) { 55 | return this.clauses.push([this._bool(), 'using', table]); 56 | }, 57 | 58 | // Adds an "and on" clause to the current join object. 59 | andOn: function andOn() { 60 | return this.on.apply(this, arguments); 61 | }, 62 | 63 | // Adds an "or on" clause to the current join object. 64 | orOn: function orOn() { 65 | /*jshint unused: false*/ 66 | return this._bool('or').on.apply(this, arguments); 67 | }, 68 | 69 | // Explicitly set the type of join, useful within a function when creating a grouped join. 70 | type: function type(_type) { 71 | this.joinType = _type; 72 | return this; 73 | }, 74 | 75 | _bool: function _bool(bool) { 76 | if (arguments.length === 1) { 77 | this._boolFlag = bool; 78 | return this; 79 | } 80 | var ret = this._boolFlag || 'and'; 81 | this._boolFlag = 'and'; 82 | return ret; 83 | } 84 | 85 | }); 86 | 87 | Object.defineProperty(JoinClause.prototype, 'or', { 88 | get: function get() { 89 | return this._bool('or'); 90 | } 91 | }); 92 | 93 | module.exports = JoinClause; 94 | -------------------------------------------------------------------------------- /lib/methods.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | // All properties we can use to start a query chain 4 | // from the `knex` object, e.g. `knex.select('*').from(...` 5 | 'use strict'; 6 | 7 | module.exports = ['select', 'as', 'columns', 'column', 'from', 'fromJS', 'into', 'table', 'distinct', 'join', 'joinRaw', 'innerJoin', 'leftJoin', 'leftOuterJoin', 'rightJoin', 'rightOuterJoin', 'outerJoin', 'fullOuterJoin', 'crossJoin', 'where', 'andWhere', 'orWhere', 'whereNot', 'orWhereNot', 'whereRaw', 'whereWrapped', 'havingWrapped', 'orWhereRaw', 'whereExists', 'orWhereExists', 'whereNotExists', 'orWhereNotExists', 'whereIn', 'orWhereIn', 'whereNotIn', 'orWhereNotIn', 'whereNull', 'orWhereNull', 'whereNotNull', 'orWhereNotNull', 'whereBetween', 'whereNotBetween', 'orWhereBetween', 'orWhereNotBetween', 'groupBy', 'groupByRaw', 'orderBy', 'orderByRaw', 'union', 'unionAll', 'having', 'havingRaw', 'orHaving', 'orHavingRaw', 'offset', 'limit', 'count', 'min', 'max', 'sum', 'avg', 'increment', 'decrement', 'first', 'debug', 'pluck', 'insert', 'update', 'returning', 'del', 'delete', 'truncate', 'transacting', 'connection']; 8 | -------------------------------------------------------------------------------- /lib/normalizeArr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function normalizeArr() { 3 | var args = new Array(arguments.length); 4 | for (var i = 0; i < args.length; i++) { 5 | args[i] = arguments[i]; 6 | } 7 | if (Array.isArray(args[0])) { 8 | return args[0]; 9 | } 10 | return args; 11 | } 12 | 13 | module.exports = normalizeArr; 14 | -------------------------------------------------------------------------------- /lib/raw.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | // Raw 4 | // ------- 5 | 'use strict'; 6 | 7 | var assign = require('./assign'); 8 | var Interface = require('./interface'); 9 | var inherits = require('inherits'); 10 | 11 | inherits(Raw, Interface); 12 | 13 | function Raw(client) { 14 | this.client = client; 15 | 16 | this.sql = ''; 17 | this.bindings = []; 18 | this._cached = undefined; 19 | this._noTransaction = false; 20 | // Todo: Deprecate 21 | this._wrappedBefore = undefined; 22 | this._wrappedAfter = undefined; 23 | this._debug = client && client.options && client.options.debug; 24 | } 25 | 26 | assign(Raw.prototype, { 27 | 28 | set: function set(sql, bindings) { 29 | this._cached = undefined; 30 | this.sql = sql; 31 | this.bindings = bindings; 32 | return this; 33 | }, 34 | batch: function () { 35 | this.client.batch(); 36 | return this; 37 | }, 38 | onSuccess: function (query) { 39 | this.client.onSuccess(query); 40 | return this; 41 | }, 42 | onError: function (query) { 43 | this.client.onError(query); 44 | return this; 45 | }, 46 | // Wraps the current sql with `before` and `after`. 47 | wrap: function wrap(before, after) { 48 | this._cached = undefined; 49 | this._wrappedBefore = before; 50 | this._wrappedAfter = after; 51 | return this; 52 | }, 53 | 54 | // Calls `toString` on the Knex object. 55 | toString: function toString() { 56 | return this.toQuery(); 57 | }, 58 | noTransaction: function () { 59 | this._noTransaction = true; 60 | return this; 61 | }, 62 | // Returns the raw sql for the query. 63 | toSQL: function toSQL() { 64 | if (this._cached) { 65 | return this._cached; 66 | } 67 | if (Array.isArray(this.bindings)) { 68 | this._cached = replaceRawArrBindings(this); 69 | } else if (this.bindings && typeof this.bindings === 'object') { 70 | this._cached = replaceKeyBindings(this); 71 | } else { 72 | this._cached = { 73 | method: 'raw', 74 | sql: this.sql, 75 | bindings: this.bindings 76 | }; 77 | } 78 | if (this._wrappedBefore) { 79 | this._cached.sql = this._wrappedBefore + this._cached.sql; 80 | } 81 | if (this._wrappedAfter) { 82 | this._cached.sql = this._cached.sql + this._wrappedAfter; 83 | } 84 | this._cached.options = assign({}, this._options); 85 | return this._cached; 86 | } 87 | 88 | }); 89 | 90 | function replaceRawArrBindings(raw) { 91 | var expectedBindings = raw.bindings.length; 92 | var values = raw.bindings; 93 | var client = raw.client; 94 | var index = 0; 95 | var bindings = []; 96 | 97 | var sql = raw.sql.replace(/\?\??/g, function (match) { 98 | var value = values[index++]; 99 | 100 | if (value && typeof value.toSQL === 'function') { 101 | var bindingSQL = value.toSQL(); 102 | bindings = bindings.concat(bindingSQL.bindings); 103 | return bindingSQL.sql; 104 | } 105 | 106 | if (match === '??') { 107 | return client.wrapIdentifier(value); 108 | } 109 | bindings.push(value); 110 | return '?'; 111 | }); 112 | 113 | if (expectedBindings !== index) { 114 | throw new Error('Expected ' + expectedBindings + ' bindings, saw ' + index); 115 | } 116 | 117 | return { 118 | method: 'raw', 119 | sql: sql, 120 | bindings: bindings 121 | }; 122 | } 123 | function replaceKeyBindings(raw) { 124 | const values = raw.bindings; 125 | const client = raw.client; 126 | var bindings = []; 127 | const regex = /\\?(:(\w+):(?=::)|:(\w+):(?!:)|:(\w+))/g; 128 | 129 | const sql = raw.sql.replace(regex, function (match, p1, p2, p3, p4) { 130 | if (match !== p1) { 131 | return p1; 132 | } 133 | 134 | const part = p2 || p3 || p4; 135 | const key = match.trim(); 136 | const isIdentifier = key[key.length - 1] === ':'; 137 | const value = values[part]; 138 | 139 | if (value === undefined) { 140 | if (Object.prototype.hasOwnProperty.call(values, part)) { 141 | formatter.bindings.push(value); 142 | } 143 | 144 | return match; 145 | } 146 | 147 | if (isIdentifier) { 148 | return match.replace(p1, client.wrapIdentifier(value)); 149 | } 150 | 151 | bindings.push(value); 152 | return match.replace(p1, '?'); 153 | }); 154 | 155 | return { 156 | method: 'raw', 157 | sql, 158 | bindings: bindings, 159 | }; 160 | } 161 | 162 | 163 | module.exports = Raw; 164 | -------------------------------------------------------------------------------- /lib/schema/builder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Interface = require('../interface'); 4 | var inherits = require('inherits'); 5 | var debug = require('debug')('cartodb:schemaBuilder'); 6 | // Constructor for the builder instance, typically called from 7 | // `knex.builder`, accepting the current `knex` instance, 8 | // and pulling out the `client` and `grammar` from the current 9 | // knex instance. 10 | function SchemaBuilder(client) { 11 | this.client = client; 12 | this._sequence = []; 13 | this._debug = client.config && client.config.debug; 14 | } 15 | inherits(SchemaBuilder, Interface); 16 | var methods = ['createTable', 'createTableIfNotExists', 'createSchema', 'createSchemaIfNotExists', 'dropSchema', 'dropSchemaIfExists', 'createExtension', 'createExtensionIfNotExists', 'dropExtension', 'dropExtensionIfExists', 'table', 'alterTable', 'hasTable', 'hasColumn', 'dropTable', 'renameTable', 'dropTableIfExists', 'raw']; 17 | // Each of the schema builder methods just add to the 18 | // "_sequence" array for consistency. 19 | methods.forEach(function (method) { 20 | SchemaBuilder.prototype[method] = function () { 21 | if (method === 'table') { 22 | method = 'alterTable'; 23 | } 24 | var args = new Array(arguments.length); 25 | var i = -1; 26 | while (++i < arguments.length) { 27 | args[i] = arguments[i]; 28 | } 29 | this._sequence.push({ 30 | method: method, 31 | args: args 32 | }); 33 | return this; 34 | }; 35 | }); 36 | 37 | 38 | SchemaBuilder.prototype.toString = function () { 39 | return this.toQuery(); 40 | }; 41 | 42 | SchemaBuilder.prototype.toSQL = function () { 43 | var compiler = this.client.schemaCompiler(this); 44 | var out = compiler.toSQL(); 45 | this._tableName = compiler._tableName; 46 | return out; 47 | }; 48 | 49 | module.exports = SchemaBuilder; 50 | -------------------------------------------------------------------------------- /lib/schema/columnbuilder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assign = require('../assign'); 4 | var AlterMethods = {}; 5 | 6 | // Specify that the column is to be dropped. This takes precedence 7 | // over all other rules for the column. 8 | AlterMethods.drop = function () { 9 | this._single.drop = true; 10 | return this; 11 | }; 12 | 13 | // Specify the "type" that we're looking to set the 14 | // Knex takes no responsibility for any data-loss that may 15 | // occur when changing data types. 16 | AlterMethods.alterType = function (type) { 17 | this._statements.push({ 18 | grouping: 'alterType', 19 | value: type 20 | }); 21 | return this; 22 | }; 23 | 24 | // Aliases for convenience. 25 | var aliasMethod = { 26 | 'default': 'defaultTo', 27 | defaultsTo: 'defaultTo', 28 | notNull: 'notNullable' 29 | }; 30 | 31 | // Alias a few methods for clarity when processing. 32 | var columnAlias = { 33 | 'float': 'floating', 34 | 'enum': 'enu', 35 | 'boolean': 'bool', 36 | 'string': 'varchar', 37 | 'bigint': 'bigInteger' 38 | }; 39 | // The chainable interface off the original "column" method. 40 | function ColumnBuilder(client, tableBuilder, type, args) { 41 | this.client = client; 42 | this._single = {}; 43 | this._modifiers = {}; 44 | this._statements = []; 45 | this._type = columnAlias[type] || type; 46 | this._args = args; 47 | this._tableBuilder = tableBuilder; 48 | 49 | // If we're altering the table, extend the object 50 | // with the available "alter" methods. 51 | if (tableBuilder._method === 'alter') { 52 | assign(this, AlterMethods); 53 | } 54 | } 55 | 56 | // All of the modifier methods that can be used to modify the current query. 57 | var modifiers = ['default', 'defaultsTo', 'defaultTo', 'unsigned', 'nullable', 'notNull', 'notNullable', 'first', 'after', 'comment']; 58 | 59 | // If we call any of the modifiers (index or otherwise) on the chainable, we pretend 60 | // as though we're calling `table.method(column)` directly. 61 | modifiers.forEach(function (method) { 62 | ColumnBuilder.prototype[method] = function () { 63 | if (aliasMethod[method]) { 64 | method = aliasMethod[method]; 65 | } 66 | if (method === 'notNullable') { 67 | return this.nullable(false); 68 | } 69 | var args = new Array(arguments.length); 70 | var i = -1; 71 | while (++i < arguments.length) { 72 | args[i] = arguments[i]; 73 | } 74 | this._modifiers[method] = args; 75 | return this; 76 | }; 77 | }); 78 | 79 | ['index', 'primary', 'unique'].forEach(function (method) { 80 | ColumnBuilder.prototype[method] = function () { 81 | if (this._type.toLowerCase().indexOf('increments') === -1) { 82 | this._tableBuilder[method].apply(this._tableBuilder, [].concat.apply(this._args[0], arguments)); 83 | } 84 | return this; 85 | }; 86 | }); 87 | 88 | // Specify that the current column "references" a column, 89 | // which may be tableName.column or just "column" 90 | ColumnBuilder.prototype.references = function (value) { 91 | return this._tableBuilder.foreign.call(this._tableBuilder, this._args[0], this)._columnBuilder(this).references(value); 92 | }; 93 | 94 | 95 | 96 | module.exports = ColumnBuilder; 97 | -------------------------------------------------------------------------------- /lib/schema/columncompiler.js: -------------------------------------------------------------------------------- 1 | 2 | // Column Compiler 3 | // Used for designating column definitions 4 | // during the table "create" / "alter" statements. 5 | // ------- 6 | 'use strict'; 7 | 8 | var Raw = require('../raw'); 9 | var helpers = require('./helpers'); 10 | 11 | function ColumnCompiler(client, tableCompiler, columnBuilder) { 12 | this.client = client; 13 | this.tableCompiler = tableCompiler; 14 | this.columnBuilder = columnBuilder; 15 | this.args = columnBuilder._args; 16 | this.type = columnBuilder._type.toLowerCase(); 17 | var grouped = this.grouped = {}; 18 | columnBuilder._statements.forEach(function (item) { 19 | if (!item.grouping) { 20 | return; 21 | } 22 | var val = item.grouping; 23 | if (!(val in grouped)) { 24 | grouped[val] = []; 25 | } 26 | grouped[val].push(item); 27 | }); 28 | this.modified = columnBuilder._modifiers; 29 | this.isIncrements = this.type.indexOf('increments') !== -1; 30 | this.formatter = client.formatter(); 31 | this.sequence = []; 32 | this.modifiers = ['nullable', 'defaultTo', 'comment']; 33 | } 34 | 35 | ColumnCompiler.prototype.pushQuery = helpers.pushQuery; 36 | 37 | ColumnCompiler.prototype.pushAdditional = helpers.pushAdditional; 38 | 39 | // To convert to sql, we first go through and build the 40 | // column as it would be in the insert statement 41 | ColumnCompiler.prototype.toSQL = function () { 42 | this.pushQuery(this.compileColumn()); 43 | if (this.sequence.additional) { 44 | this.sequence = this.sequence.concat(this.sequence.additional); 45 | } 46 | return this.sequence; 47 | }; 48 | 49 | // Compiles a column. 50 | ColumnCompiler.prototype.compileColumn = function () { 51 | return this.formatter.wrap(this.getColumnName()) + ' ' + this.getColumnType() + this.getModifiers(); 52 | }; 53 | 54 | // Assumes the autoincrementing key is named `id` if not otherwise specified. 55 | ColumnCompiler.prototype.getColumnName = function () { 56 | var value = this.args[0]; 57 | if (value) { 58 | return value; 59 | } 60 | if (this.isIncrements) { 61 | return 'id'; 62 | } else { 63 | throw new Error('You did not specify a column name for the ' + this.type + 'column.'); 64 | } 65 | }; 66 | 67 | ColumnCompiler.prototype.getColumnType = function () { 68 | var type = this[this.type]; 69 | return typeof type === 'function' ? type.apply(this, this.args.slice(1)) : type; 70 | }; 71 | 72 | ColumnCompiler.prototype.getModifiers = function () { 73 | var modifiers = []; 74 | if (this.type.indexOf('increments') === -1) { 75 | for (var i = 0, l = this.modifiers.length; i < l; i++) { 76 | var modifier = this.modifiers[i]; 77 | if (this.modified[modifier]) { 78 | var val = this[modifier].apply(this, this.modified[modifier]); 79 | if (val) { 80 | modifiers.push(val); 81 | } 82 | } 83 | } 84 | } 85 | return modifiers.length > 0 ? ' ' + modifiers.join(' ') : ''; 86 | }; 87 | 88 | // Types 89 | // ------ 90 | 91 | ColumnCompiler.prototype.increments = 'serial primary key'; 92 | ColumnCompiler.prototype.bigincrements = 'bigserial primary key'; 93 | ColumnCompiler.prototype.integer = 'integer'; 94 | ColumnCompiler.prototype.smallint = 'smallint'; 95 | ColumnCompiler.prototype.tinyint = 'smallint'; 96 | ColumnCompiler.prototype.mediumint = 'integer'; 97 | ColumnCompiler.prototype.biginteger = 'bigint'; 98 | ColumnCompiler.prototype.varchar = function (length) { 99 | return 'varchar(' + this._num(length, 255) + ')'; 100 | }; 101 | ColumnCompiler.prototype.text = 'text'; 102 | ColumnCompiler.prototype.floating = 'real'; 103 | ColumnCompiler.prototype.double = 'double precision'; 104 | ColumnCompiler.prototype.decimal = function (precision, scale) { 105 | return 'decimal(' + this._num(precision, 8) + ', ' + this._num(scale, 2) + ')'; 106 | }; 107 | ColumnCompiler.prototype.binary = 'bytea'; 108 | ColumnCompiler.prototype.bool = 'boolean'; 109 | ColumnCompiler.prototype.date = 'date'; 110 | ColumnCompiler.prototype.datetime = function datetime(without) { 111 | return without ? 'timestamp' : 'timestamptz'; 112 | }; 113 | ColumnCompiler.prototype.time = 'time'; 114 | ColumnCompiler.prototype.timestamp = function timestamp(without) { 115 | return without ? 'timestamp' : 'timestamptz'; 116 | }; 117 | ColumnCompiler.prototype.enu = function enu(allowed) { 118 | return 'text check (' + this.formatter.wrap(this.args[0]) + ' in (\'' + allowed.join('\', \'') + '\'))'; 119 | }; 120 | 121 | ColumnCompiler.prototype.bit = function bit(column) { 122 | return column.length !== false ? 'bit(' + column.length + ')' : 'bit'; 123 | }; 124 | ColumnCompiler.prototype.json = function json(jsonb) { 125 | return jsonb ? 'jsonb' : 'json'; 126 | }; 127 | 128 | ColumnCompiler.prototype.uuid = 'uuid'; 129 | ColumnCompiler.prototype.comment = function comment(_comment) { 130 | this.pushAdditional(function () { 131 | this.pushQuery('comment on column ' + this.tableCompiler.tableName() + '.' + this.formatter.wrap(this.args[0]) + ' is ' + (_comment ? '\'' + _comment + '\'' : 'NULL')); 132 | }, _comment); 133 | }; 134 | ColumnCompiler.prototype.specifictype = function (type) { 135 | return type; 136 | }; 137 | 138 | // Modifiers 139 | // ------- 140 | 141 | ColumnCompiler.prototype.nullable = function (nullable) { 142 | return nullable === false ? 'not null' : 'null'; 143 | }; 144 | ColumnCompiler.prototype.notNullable = function () { 145 | return this.nullable(false); 146 | }; 147 | ColumnCompiler.prototype.defaultTo = function (value) { 148 | if (value === void 0) { 149 | return ''; 150 | } else if (value === null) { 151 | value = 'null'; 152 | } else if (value instanceof Raw) { 153 | value = value.toQuery(); 154 | } else if (this.type === 'bool') { 155 | if (value === 'false') { 156 | value = 0; 157 | } 158 | value = '\'' + (value ? 1 : 0) + '\''; 159 | } else if (this.type === 'json' && typeof value === 'object') { 160 | return JSON.stringify(value); 161 | } else { 162 | value = '\'' + value + '\''; 163 | } 164 | return 'default ' + value; 165 | }; 166 | ColumnCompiler.prototype._num = function (val, fallback) { 167 | if (val === undefined || val === null) { 168 | return fallback; 169 | } 170 | var number = parseInt(val, 10); 171 | return isNaN(number) ? fallback : number; 172 | }; 173 | 174 | module.exports = ColumnCompiler; 175 | -------------------------------------------------------------------------------- /lib/schema/compiler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var helpers = require('./helpers'); 4 | var assign = require('../assign'); 5 | var debug = require('debug')('cartodb:schemaCompiler'); 6 | 7 | // The "SchemaCompiler" takes all of the query statements which have been 8 | // gathered in the "SchemaBuilder" and turns them into an array of 9 | // properly formatted / bound query strings. 10 | function SchemaCompiler(client, builder) { 11 | this.builder = builder; 12 | this.client = client; 13 | this.formatter = client.formatter(); 14 | this.sequence = []; 15 | } 16 | 17 | assign(SchemaCompiler.prototype, { 18 | 19 | pushQuery: helpers.pushQuery, 20 | 21 | pushAdditional: helpers.pushAdditional, 22 | 23 | createTable: buildTable('create'), 24 | 25 | createTableIfNotExists: buildTable('createIfNot'), 26 | 27 | alterTable: buildTable('alter'), 28 | 29 | dropTable: function dropTable(tableName) { 30 | this.pushQuery('drop table ' + this.formatter.wrap(tableName)); 31 | }, 32 | 33 | dropTableIfExists: function dropTableIfExists(tableName) { 34 | this.pushQuery('drop table if exists ' + this.formatter.wrap(tableName)); 35 | }, 36 | 37 | raw: function raw(sql, bindings) { 38 | this.sequence.push(this.client.raw(sql, bindings).toSQL()); 39 | }, 40 | 41 | toSQL: function toSQL() { 42 | var sequence = this.builder._sequence; 43 | for (var i = 0, l = sequence.length; i < l; i++) { 44 | var query = sequence[i]; 45 | this[query.method].apply(this, query.args); 46 | } 47 | debug(this.sequence); 48 | return this.sequence; 49 | } 50 | 51 | }); 52 | 53 | function buildTable(type) { 54 | return function (tableName, fn) { 55 | if (type === 'create') { 56 | this._tableName = tableName; 57 | } 58 | var sql = this.client.tableBuilder(type, tableName, fn).toSQL(); 59 | for (var i = 0, l = sql.length; i < l; i++) { 60 | this.sequence.push(sql[i]); 61 | } 62 | }; 63 | } 64 | 65 | 66 | // Check whether the current table 67 | SchemaCompiler.prototype.hasTable = function (tableName) { 68 | this.pushQuery({ 69 | sql: 'select * from information_schema.tables where table_name = ?', 70 | bindings: [tableName], 71 | output: function output(resp) { 72 | return resp.rows.length > 0; 73 | } 74 | }); 75 | }; 76 | 77 | // Compile the query to determine if a column exists in a table. 78 | SchemaCompiler.prototype.hasColumn = function (tableName, columnName) { 79 | this.pushQuery({ 80 | sql: 'select * from information_schema.columns where table_name = ? and column_name = ?', 81 | bindings: [tableName, columnName], 82 | output: function output(resp) { 83 | return resp.rows.length > 0; 84 | } 85 | }); 86 | }; 87 | 88 | // Compile a rename table command. 89 | SchemaCompiler.prototype.renameTable = function (from, to) { 90 | this.pushQuery('alter table ' + this.formatter.wrap(from) + ' rename to ' + this.formatter.wrap(to)); 91 | }; 92 | 93 | SchemaCompiler.prototype.createSchema = function (schemaName) { 94 | this.pushQuery('create schema ' + this.formatter.wrap(schemaName)); 95 | }; 96 | 97 | SchemaCompiler.prototype.createSchemaIfNotExists = function (schemaName) { 98 | this.pushQuery('create schema if not exists ' + this.formatter.wrap(schemaName)); 99 | }; 100 | 101 | SchemaCompiler.prototype.dropSchema = function (schemaName) { 102 | this.pushQuery('drop schema ' + this.formatter.wrap(schemaName)); 103 | }; 104 | 105 | SchemaCompiler.prototype.dropSchemaIfExists = function (schemaName) { 106 | this.pushQuery('drop schema if exists ' + this.formatter.wrap(schemaName)); 107 | }; 108 | 109 | SchemaCompiler.prototype.dropExtension = function (extensionName) { 110 | this.pushQuery('drop extension ' + this.formatter.wrap(extensionName)); 111 | }; 112 | 113 | SchemaCompiler.prototype.dropExtensionIfExists = function (extensionName) { 114 | this.pushQuery('drop extension if exists ' + this.formatter.wrap(extensionName)); 115 | }; 116 | 117 | SchemaCompiler.prototype.createExtension = function (extensionName) { 118 | this.pushQuery('create extension ' + this.formatter.wrap(extensionName)); 119 | }; 120 | 121 | SchemaCompiler.prototype.createExtensionIfNotExists = function (extensionName) { 122 | this.pushQuery('create extension if not exists ' + this.formatter.wrap(extensionName)); 123 | }; 124 | 125 | module.exports = SchemaCompiler; 126 | -------------------------------------------------------------------------------- /lib/schema/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Push a new query onto the compiled "sequence" stack, 4 | // creating a new formatter, returning the compiler. 5 | exports.pushQuery = function (query) { 6 | if (!query) { 7 | return; 8 | } 9 | if (typeof query === 'string') { 10 | query = { sql: query }; 11 | } else { 12 | query = query; 13 | } 14 | if (!query.bindings) { 15 | query.bindings = this.formatter.bindings; 16 | } 17 | this.sequence.push(query); 18 | this.formatter = this.client.formatter(); 19 | }; 20 | 21 | // Used in cases where we need to push some additional column specific statements. 22 | exports.pushAdditional = function (fn) { 23 | var child = new this.constructor(this.client, this.tableCompiler, this.columnBuilder); 24 | var args = new Array(arguments.length - 1); 25 | var i = 0; 26 | while (i < arguments.length) { 27 | args[i++] = arguments[i]; 28 | } 29 | fn.call(child, args); 30 | this.sequence.additional = (this.sequence.additional || []).concat(child.sequence); 31 | }; 32 | -------------------------------------------------------------------------------- /lib/schema/tablebuilder.js: -------------------------------------------------------------------------------- 1 | 2 | // TableBuilder 3 | 4 | // Takes the function passed to the "createTable" or "table/editTable" 5 | // functions and calls it with the "TableBuilder" as both the context and 6 | // the first argument. Inside this function we can specify what happens to the 7 | // method, pushing everything we want to do onto the "allStatements" array, 8 | // which is then compiled into sql. 9 | // ------ 10 | 'use strict'; 11 | 12 | var debug = require('debug')('cartodb:tablebuilder'); 13 | var assign = require('../assign'); 14 | function TableBuilder(client, method, tableName, fn) { 15 | this.client = client; 16 | this._fn = fn; 17 | this._method = method; 18 | this._tableName = tableName; 19 | this._statements = []; 20 | this._single = {}; 21 | } 22 | 23 | var AlterMethods = { 24 | 25 | // Renames the current column `from` the current 26 | // TODO: this.column(from).rename(to) 27 | renameColumn: function renameColumn(from, to) { 28 | this._statements.push({ 29 | grouping: 'alterTable', 30 | method: 'renameColumn', 31 | args: [from, to] 32 | }); 33 | return this; 34 | }, 35 | 36 | dropTimestamps: function dropTimestamps() { 37 | return this.dropColumns(['created_at', 'updated_at']); 38 | } 39 | 40 | // TODO: changeType 41 | }; 42 | 43 | // Drop a column from the current table. 44 | // TODO: Enable this.column(columnName).drop(); 45 | AlterMethods.dropColumn = AlterMethods.dropColumns = function () { 46 | var args = new Array(arguments.length); 47 | var i = -1; 48 | while (++i < arguments.length) { 49 | args[i] = arguments[i]; 50 | } 51 | this._statements.push({ 52 | grouping: 'alterTable', 53 | method: 'dropColumn', 54 | args: arguments 55 | }); 56 | return this; 57 | }; 58 | // Convert the current tableBuilder object "toSQL" 59 | // giving us additional methods if we're altering 60 | // rather than creating the table. 61 | TableBuilder.prototype.toSQL = function () { 62 | if (this._method === 'alter') { 63 | assign(this, AlterMethods); 64 | } 65 | this._fn.call(this, this); 66 | return this.client.tableCompiler(this).toSQL(); 67 | }; 68 | 69 | [ 70 | 71 | // Each of the index methods can be called individually, with the 72 | // column name to be used, e.g. table.unique('column'). 73 | 'index', 'primary', 'unique', 74 | 75 | // Key specific 76 | 'dropPrimary', 'dropUnique', 'dropIndex', 'dropForeign'].forEach(function (method) { 77 | TableBuilder.prototype[method] = function () { 78 | var args = new Array(arguments.length); 79 | var i = -1; 80 | while (++i < arguments.length) { 81 | args[i] = arguments[i]; 82 | } 83 | this._statements.push({ 84 | grouping: 'alterTable', 85 | method: method, 86 | args: args 87 | }); 88 | return this; 89 | }; 90 | }); 91 | 92 | // Warn if we're not in MySQL, since that's the only time these 93 | // three are supported. 94 | var specialMethods = ['engine', 'charset', 'collate']; 95 | specialMethods.forEach(function (method) { 96 | TableBuilder.prototype[method] = function (value) { 97 | if (false) { 98 | debug('Knex only supports ' + method + ' statement with mysql.'); 99 | }if (this._method === 'alter') { 100 | debug('Knex does not support altering the ' + method + ' outside of the create table, please use knex.raw statement.'); 101 | } 102 | this._single[method] = value; 103 | }; 104 | }); 105 | 106 | // Each of the column types that we can add, we create a new ColumnBuilder 107 | // instance and push it onto the statements array. 108 | var columnTypes = [ 109 | 110 | // Numeric 111 | 'tinyint', 'smallint', 'mediumint', 'int', 'bigint', 'decimal', 'float', 'double', 'real', 'bit', 'boolean', 'serial', 112 | 113 | // Date / Time 114 | 'date', 'datetime', 'timestamp', 'time', 'year', 115 | 116 | // String 117 | 'char', 'varchar', 'tinytext', 'tinyText', 'text', 'mediumtext', 'mediumText', 'longtext', 'longText', 'binary', 'varbinary', 'tinyblob', 'tinyBlob', 'mediumblob', 'mediumBlob', 'blob', 'longblob', 'longBlob', 'enum', 'set', 118 | 119 | // Increments, Aliases, and Additional 120 | 'bool', 'dateTime', 'increments', 'bigincrements', 'bigIncrements', 'integer', 'biginteger', 'bigInteger', 'string', 'timestamps', 'json', 'uuid', 'enu', 'specificType']; 121 | 122 | // For each of the column methods, create a new "ColumnBuilder" interface, 123 | // push it onto the "allStatements" stack, and then return the interface, 124 | // with which we can add indexes, etc. 125 | columnTypes.forEach(function (type) { 126 | TableBuilder.prototype[type] = function () { 127 | var args = new Array(arguments.length); 128 | var i = -1; 129 | while (++i < arguments.length) { 130 | args[i] = arguments[i]; 131 | } 132 | 133 | // The "timestamps" call is really a compound call to set the 134 | // `created_at` and `updated_at` columns. 135 | if (type === 'timestamps') { 136 | if (args[0] === true) { 137 | this.timestamp('created_at'); 138 | this.timestamp('updated_at'); 139 | } else { 140 | this.datetime('created_at'); 141 | this.datetime('updated_at'); 142 | } 143 | return undefined; 144 | } 145 | var builder = this.client.columnBuilder(this, type, args); 146 | 147 | this._statements.push({ 148 | grouping: 'columns', 149 | builder: builder 150 | }); 151 | return builder; 152 | }; 153 | }); 154 | 155 | // Set the comment value for a table, they're only allowed to be called 156 | // once per table. 157 | TableBuilder.prototype.comment = function (value) { 158 | this._single.comment = value; 159 | }; 160 | 161 | // Set a foreign key on the table, calling 162 | // `table.foreign('column_name').references('column').on('table').onDelete()... 163 | // Also called from the ColumnBuilder context when chaining. 164 | TableBuilder.prototype.foreign = function (column) { 165 | var foreignData = { column: column }; 166 | this._statements.push({ 167 | grouping: 'alterTable', 168 | method: 'foreign', 169 | args: [foreignData] 170 | }); 171 | var returnObj = { 172 | references: function references(tableColumn) { 173 | var pieces; 174 | if (typeof tableColumn === 'string') { 175 | pieces = tableColumn.split('.'); 176 | } 177 | if (!pieces || pieces.length === 1) { 178 | foreignData.references = pieces ? pieces[0] : tableColumn; 179 | return { 180 | on: function on(tableName) { 181 | foreignData.inTable = tableName; 182 | return returnObj; 183 | }, 184 | inTable: function inTable() { 185 | return this.on.apply(this, arguments); 186 | } 187 | }; 188 | } 189 | foreignData.inTable = pieces[0]; 190 | foreignData.references = pieces[1]; 191 | return returnObj; 192 | }, 193 | onUpdate: function onUpdate(statement) { 194 | foreignData.onUpdate = statement; 195 | return returnObj; 196 | }, 197 | onDelete: function onDelete(statement) { 198 | foreignData.onDelete = statement; 199 | return returnObj; 200 | }, 201 | _columnBuilder: function _columnBuilder(builder) { 202 | assign(builder, returnObj); 203 | returnObj = builder; 204 | return builder; 205 | } 206 | }; 207 | return returnObj; 208 | }; 209 | 210 | 211 | module.exports = TableBuilder; 212 | -------------------------------------------------------------------------------- /lib/schema/tablecompiler.js: -------------------------------------------------------------------------------- 1 | 2 | // Table Compiler 3 | // ------- 4 | 'use strict'; 5 | 6 | var helpers = require('./helpers'); 7 | var normalizeArr = require('../normalizeArr'); 8 | var debug = require('debug')('cartodb:tablecompiler'); 9 | var isEmpty = require('../isEmpty'); 10 | 11 | function TableCompiler(client, tableBuilder) { 12 | this.client = client; 13 | this.method = tableBuilder._method; 14 | this.tableNameRaw = tableBuilder._tableName; 15 | this.single = tableBuilder._single; 16 | var grouped = this.grouped = {}; 17 | tableBuilder._statements.forEach(function (item) { 18 | if (!item.grouping) { 19 | return; 20 | } 21 | var val = item.grouping; 22 | if (!(val in grouped)) { 23 | grouped[val] = []; 24 | } 25 | grouped[val].push(item); 26 | }); 27 | this.formatter = client.formatter(); 28 | this.sequence = []; 29 | } 30 | 31 | TableCompiler.prototype.pushQuery = helpers.pushQuery; 32 | 33 | TableCompiler.prototype.pushAdditional = helpers.pushAdditional; 34 | 35 | // Convert the tableCompiler toSQL 36 | TableCompiler.prototype.toSQL = function () { 37 | this[this.method](); 38 | return this.sequence; 39 | }; 40 | 41 | // Column Compilation 42 | // ------- 43 | 44 | // If this is a table "creation", we need to first run through all 45 | // of the columns to build them into a single string, 46 | // and then run through anything else and push it to the query sequence. 47 | TableCompiler.prototype.create = function (ifNot) { 48 | var columns = this.getColumns(); 49 | var columnTypes = this.getColumnTypes(columns); 50 | this.createQuery(columnTypes, ifNot); 51 | this.columnQueries(columns); 52 | delete this.single.comment; 53 | this.alterTable(); 54 | }; 55 | 56 | // Only create the table if it doesn't exist. 57 | TableCompiler.prototype.createIfNot = function () { 58 | this.create(true); 59 | }; 60 | 61 | // If we're altering the table, we need to one-by-one 62 | // go through and handle each of the queries associated 63 | // with altering the table's schema. 64 | TableCompiler.prototype.alter = function () { 65 | var columns = this.getColumns(); 66 | var columnTypes = this.getColumnTypes(columns); 67 | this.addColumns(columnTypes); 68 | this.columnQueries(columns); 69 | this.alterTable(); 70 | }; 71 | 72 | TableCompiler.prototype.foreign = function (foreignData) { 73 | if (foreignData.inTable && foreignData.references) { 74 | var keyName = this._indexCommand('foreign', this.tableNameRaw, foreignData.column); 75 | var column = this.formatter.columnize(foreignData.column); 76 | var references = this.formatter.columnize(foreignData.references); 77 | var inTable = this.formatter.wrap(foreignData.inTable); 78 | var onUpdate = foreignData.onUpdate ? ' on update ' + foreignData.onUpdate : ''; 79 | var onDelete = foreignData.onDelete ? ' on delete ' + foreignData.onDelete : ''; 80 | this.pushQuery('alter table ' + this.tableName() + ' add constraint ' + keyName + ' ' + 'foreign key (' + column + ') references ' + inTable + ' (' + references + ')' + onUpdate + onDelete); 81 | } 82 | }; 83 | 84 | // Get all of the column sql & bindings individually for building the table queries. 85 | TableCompiler.prototype.getColumnTypes = function (columns) { 86 | return columns.map(function (item) { 87 | return item[0]; 88 | }).reduce(function (memo, column) { 89 | memo.sql.push(column.sql); 90 | memo.bindings.concat(column.bindings); 91 | return memo; 92 | }, { sql: [], bindings: [] }); 93 | }; 94 | 95 | // Adds all of the additional queries from the "column" 96 | TableCompiler.prototype.columnQueries = function (columns) { 97 | var queries = columns.map(function (item) { 98 | return item.slice(1); 99 | }).reduce(function (memo, column) { 100 | if (!isEmpty(column)) { 101 | return memo.concat(column); 102 | } 103 | return memo; 104 | }, []); 105 | for (var i = 0, l = queries.length; i < l; i++) { 106 | this.pushQuery(queries[i]); 107 | } 108 | }; 109 | 110 | // Add a new column. 111 | TableCompiler.prototype.addColumnsPrefix = 'add column '; 112 | 113 | // All of the columns to "add" for the query 114 | TableCompiler.prototype.addColumns = function (columns) { 115 | if (columns.sql.length > 0) { 116 | var columnSql = columns.sql.map(function (column) { 117 | return this.addColumnsPrefix + column; 118 | }, this); 119 | this.pushQuery({ 120 | sql: 'alter table ' + this.tableName() + ' ' + columnSql.join(', '), 121 | bindings: columns.bindings 122 | }); 123 | } 124 | }; 125 | 126 | // Compile the columns as needed for the current create or alter table 127 | TableCompiler.prototype.getColumns = function () { 128 | var i = -1, 129 | compiledColumns = [], 130 | columns = this.grouped.columns || []; 131 | while (++i < columns.length) { 132 | compiledColumns.push(this.client.columnCompiler(this, columns[i].builder).toSQL()); 133 | } 134 | return compiledColumns; 135 | }; 136 | 137 | TableCompiler.prototype.tableName = function () { 138 | return this.formatter.wrap(this.tableNameRaw); 139 | }; 140 | 141 | // Generate all of the alter column statements necessary for the query. 142 | TableCompiler.prototype.alterTable = function () { 143 | var alterTable = this.grouped.alterTable || []; 144 | for (var i = 0, l = alterTable.length; i < l; i++) { 145 | var statement = alterTable[i]; 146 | if (this[statement.method]) { 147 | this[statement.method].apply(this, statement.args); 148 | } else { 149 | debug(statement.method + ' does not exist'); 150 | } 151 | } 152 | for (var item in this.single) { 153 | if (typeof this[item] === 'function') { 154 | this[item](this.single[item]); 155 | } 156 | } 157 | }; 158 | 159 | // Drop the index on the current table. 160 | TableCompiler.prototype.dropIndex = function (value) { 161 | this.pushQuery('drop index' + value); 162 | }; 163 | 164 | // Drop the unique 165 | TableCompiler.prototype.dropUnique = TableCompiler.prototype.dropForeign = function () { 166 | throw new Error('Method implemented in the dialect driver'); 167 | }; 168 | 169 | TableCompiler.prototype.dropColumnPrefix = 'drop column '; 170 | TableCompiler.prototype.dropColumn = function () { 171 | var columns = normalizeArr.apply(null, arguments); 172 | var drops = (Array.isArray(columns) ? columns : [columns]).map(function (column) { 173 | return this.dropColumnPrefix + this.formatter.wrap(column); 174 | }, this); 175 | this.pushQuery('alter table ' + this.tableName() + ' ' + drops.join(', ')); 176 | }; 177 | 178 | // If no name was specified for this index, we will create one using a basic 179 | // convention of the table name, followed by the columns, followed by an 180 | // index type, such as primary or index, which makes the index unique. 181 | TableCompiler.prototype._indexCommand = function (type, tableName, columns) { 182 | if (!Array.isArray(columns)) { 183 | columns = columns ? [columns] : []; 184 | } 185 | var table = tableName.replace(/\.|-/g, '_'); 186 | return (table + '_' + columns.join('_') + '_' + type).toLowerCase(); 187 | }; 188 | 189 | //postgres ones 190 | // Compile a rename column command. 191 | TableCompiler.prototype.renameColumn = function (from, to) { 192 | return this.pushQuery({ 193 | sql: 'alter table ' + this.tableName() + ' rename ' + this.formatter.wrap(from) + ' to ' + this.formatter.wrap(to) 194 | }); 195 | }; 196 | 197 | TableCompiler.prototype.compileAdd = function (builder) { 198 | var table = this.formatter.wrap(builder); 199 | var columns = this.prefixArray('add column', this.getColumns(builder)); 200 | return this.pushQuery({ 201 | sql: 'alter table ' + table + ' ' + columns.join(', ') 202 | }); 203 | }; 204 | 205 | // Adds the "create" query to the query sequence. 206 | TableCompiler.prototype.createQuery = function (columns, ifNot) { 207 | var createStatement = ifNot ? 'create table if not exists ' : 'create table '; 208 | this.pushQuery({ 209 | sql: createStatement + this.tableName() + ' (' + columns.sql.join(', ') + ')', 210 | bindings: columns.bindings 211 | }); 212 | if ('comment' in this.single) { 213 | this.comment(this.single.comment); 214 | } 215 | }; 216 | 217 | // Compiles the comment on the table. 218 | TableCompiler.prototype.comment = function (comment) { // eslint-disable-line no-unused-vars 219 | this.pushQuery('comment on table ' + this.tableName() + ' is ' + '\'' + (this.single.comment || '') + '\''); 220 | }; 221 | 222 | // Indexes: 223 | // ------- 224 | 225 | TableCompiler.prototype.primary = function (columns) { 226 | this.pushQuery('alter table ' + this.tableName() + ' add primary key (' + this.formatter.columnize(columns) + ')'); 227 | }; 228 | TableCompiler.prototype.unique = function (columns, indexName) { 229 | indexName = indexName || this._indexCommand('unique', this.tableNameRaw, columns); 230 | this.pushQuery('alter table ' + this.tableName() + ' add constraint ' + indexName + ' unique (' + this.formatter.columnize(columns) + ')'); 231 | }; 232 | TableCompiler.prototype.index = function (columns, indexName, indexType) { 233 | indexName = indexName || this._indexCommand('index', this.tableNameRaw, columns); 234 | this.pushQuery('create index ' + indexName + ' on ' + this.tableName() + (indexType && ' using ' + indexType || '') + ' (' + this.formatter.columnize(columns) + ')'); 235 | }; 236 | TableCompiler.prototype.dropPrimary = function () { 237 | this.pushQuery('alter table ' + this.tableName() + ' drop constraint ' + this.tableNameRaw + '_pkey'); 238 | }; 239 | TableCompiler.prototype.dropIndex = function (columns, indexName) { 240 | indexName = indexName || this._indexCommand('index', this.tableNameRaw, columns); 241 | this.pushQuery('drop index ' + indexName); 242 | }; 243 | TableCompiler.prototype.dropUnique = function (columns, indexName) { 244 | indexName = indexName || this._indexCommand('unique', this.tableNameRaw, columns); 245 | this.pushQuery('alter table ' + this.tableName() + ' drop constraint ' + indexName); 246 | }; 247 | TableCompiler.prototype.dropForeign = function (columns, indexName) { 248 | indexName = indexName || this._indexCommand('foreign', this.tableNameRaw, columns); 249 | this.pushQuery('alter table ' + this.tableName() + ' drop constraint ' + indexName); 250 | }; 251 | module.exports = TableCompiler; 252 | -------------------------------------------------------------------------------- /lib/string.js: -------------------------------------------------------------------------------- 1 | // from knex 2 | // Copyright (c) 2013-2014 Tim Griesser 3 | 'use strict'; 4 | 5 | var crypto = require('crypto'); 6 | function makeValues(values) { 7 | var out = ''; 8 | values.forEach(function (value, i) { 9 | if (i) { 10 | out += ','; 11 | } else { 12 | out += '('; 13 | } 14 | if (typeof value === 'boolean') { 15 | out += 'bool'; 16 | return; 17 | } 18 | if (typeof value === 'number') { 19 | out += 'numeric'; 20 | return; 21 | } 22 | if (typeof value === 'string') { 23 | out += 'text'; 24 | return; 25 | } 26 | if (value instanceof Date) { 27 | out += 'timestamptz'; 28 | return; 29 | } 30 | if (isGeojson(value)) { 31 | out += 'geometry'; 32 | return; 33 | } 34 | out += 'unknown'; 35 | }); 36 | return out + ')'; 37 | } 38 | function makeName (sql, values) { 39 | var help = ''; 40 | if (values && values.length) { 41 | help = makeValues(values) 42 | } 43 | return ['_' + crypto.createHash('sha256').update(sql).update(help).digest('hex').slice(0, 16), help]; 44 | } 45 | 46 | var debug = require('debug')('cartodb:string'); 47 | function tagRegex(tag) { 48 | return new RegExp('\\$' + tag + '\\$'); 49 | } 50 | function getBase(input) { 51 | var tagBase = 'cartodb'; 52 | if (!input.match(tagRegex(tagBase))) { 53 | return '$' + tagBase + '$'; 54 | } 55 | var i = 0; 56 | while(input.match(tagRegex(tagBase + i))) { 57 | i++; 58 | } 59 | return '$' + tagBase + i + '$'; 60 | } 61 | exports.formatString = function formatString(item) { 62 | var tag = getBase(item); 63 | return tag + item + tag; 64 | }; 65 | var controlRegex = /[\0\n\r\b\t\\\x1a]/g; // eslint-disable-line no-control-regex 66 | exports.escape = function (val, timeZone) { 67 | if (val == null) { 68 | return 'NULL'; 69 | } 70 | 71 | switch (typeof val) { 72 | case 'boolean': 73 | return val ? 'true' : 'false'; 74 | case 'number': 75 | return 'numeric $$' + val + '$$'; 76 | } 77 | 78 | if (val instanceof Date) { 79 | val = exports.dateToString(val, timeZone || 'local'); 80 | } 81 | 82 | if (Buffer.isBuffer(val)) { 83 | return exports.bufferToString(val); 84 | } 85 | 86 | if (Array.isArray(val)) { 87 | return exports.arrayToList(val, timeZone); 88 | } 89 | var geojson = isGeojson(val); 90 | if (typeof val === 'object') { 91 | try { 92 | val = JSON.stringify(val); 93 | } catch (e) { 94 | debug(e); 95 | val = val + ''; 96 | } 97 | } 98 | 99 | val = val.replace(controlRegex, function (s) { 100 | switch (s) { 101 | case '\u0000': 102 | return '\\0'; 103 | case '\n': 104 | return '\\n'; 105 | case '\r': 106 | return '\\r'; 107 | case '\b': 108 | return '\\b'; 109 | case '\t': 110 | return '\\t'; 111 | case '\u001a': 112 | return '\\Z'; 113 | default: 114 | return '\\' + s; 115 | } 116 | }); 117 | val = exports.formatString(val); 118 | if (geojson) { 119 | return 'ST_SetSRID(ST_GeomFromGeoJSON(' + val + '), 4326)'; 120 | } 121 | return val; 122 | }; 123 | 124 | exports.arrayToList = function (array, timeZone) { 125 | return array.map(function (v) { 126 | if (Array.isArray(v)) { 127 | return '(' + exports.arrayToList(v, timeZone) + ')'; 128 | } 129 | return exports.escape(v, timeZone); 130 | }).join(', '); 131 | }; 132 | function wrapIdentifier(value) { 133 | if (value === '*') return value; 134 | 135 | let arrayAccessor = ''; 136 | const arrayAccessorMatch = value.match(/(.*?)(\[[0-9]+\])/); 137 | 138 | if (arrayAccessorMatch) { 139 | value = arrayAccessorMatch[1]; 140 | arrayAccessor = arrayAccessorMatch[2]; 141 | } 142 | 143 | return `"${value.replace(/"/g, '""')}"${arrayAccessor}`; 144 | } 145 | const escapeArr = (sql, values) => { 146 | let index = 0; 147 | const newValues = []; 148 | sql = sql.replace(/\\?\?\??/g, function (match) { 149 | if (match === '\\?') { 150 | return match; 151 | } 152 | const value = values[index++]; 153 | if (match === '??') { 154 | return wrapIdentifier(value); 155 | } 156 | // if (index === values.length && match !== '?') { 157 | // console.log('match', match) 158 | // return match; 159 | // } 160 | newValues.push(value); 161 | return '$' + newValues.length; 162 | }) + ';'; 163 | return { 164 | sql: sql, 165 | values: newValues 166 | } 167 | } 168 | const regex = /\\?(:(\w+):(?=::)|:(\w+):(?!:)|:(\w+))/g; 169 | const escapeObj = (sql, values) => { 170 | let index = 0; 171 | const newValues = []; 172 | sql = (' ' + sql).replace(regex, function (match, p1, p2, p3, p4) { 173 | const part = p2 || p3 || p4; 174 | const key = match.trim(); 175 | const isIdentifier = key[key.length - 1] === ':'; 176 | const value = values[part]; 177 | if (isIdentifier) { 178 | return wrapIdentifier(value); 179 | } 180 | newValues.push(value); 181 | return '$' + newValues.length; 182 | }) + ';'; 183 | return { 184 | sql: sql, 185 | values: newValues 186 | } 187 | } 188 | const makeEscape = (sql, values) => { 189 | if (Array.isArray(values)) { 190 | if (!values.length) { 191 | return { 192 | sql: sql, 193 | values: [] 194 | } 195 | } 196 | return escapeArr(sql, values); 197 | } 198 | if (!Object.keys(values).length) { 199 | return { 200 | sql: sql, 201 | values: [] 202 | } 203 | return escapeObj(sql, values); 204 | } 205 | } 206 | function escape(timezone) { 207 | return escapeWithTimezone; 208 | function escapeWithTimezone(value) { 209 | return exports.escape(value, timezone) 210 | } 211 | } 212 | function formatInsert(sql, values, timeZone) { 213 | var index = 0; 214 | sql = sql.replace(/\?/g, function (match) { 215 | index++; 216 | if (index === values.length && match !== '?') { 217 | return match; 218 | } 219 | return '$' + index; 220 | }) + ';'; 221 | 222 | let names = makeName(sql); 223 | let name = names[0]; 224 | let params = names[1]; 225 | var out = [ 226 | 'PREPARE ' + name + params + ' AS', 227 | sql 228 | ]; 229 | values.forEach(function (item) { 230 | out.push('EXECUTE ' + name + (item.length ? ('(' + item.map(escape(timeZone)).join(',') + ');') : ';')); 231 | }); 232 | out.push('DEALLOCATE ' + name) 233 | 234 | return out.join('\n'); 235 | } 236 | exports.format = function (sql, values, timeZone, method) { 237 | values = values == null ? [] : values; 238 | 239 | if (!values.length) { 240 | return sql; 241 | } 242 | if (method === 'insert') { 243 | return formatInsert(sql, values, timeZone); 244 | } 245 | const resp = makeEscape(sql, values); 246 | if (!resp.values.length) { 247 | return resp.sql; 248 | } 249 | sql = resp.sql; 250 | values = resp.values; 251 | debug(sql); 252 | debug(values); 253 | 254 | let escapedValues = (values.length ? ('(' + values.map(escape(timeZone)).join(',') + ');') : ';'); 255 | let names = makeName(sql, values); 256 | let name = names[0]; 257 | let params = names[1] 258 | return [ 259 | 'PREPARE ' + name + params + ' AS', 260 | sql, 261 | 'EXECUTE ' + name + escapedValues, 262 | 'DEALLOCATE ' + name 263 | ].join('\n'); 264 | 265 | }; 266 | var types = [ 267 | 'Point', 'MultiPoint', 268 | 'LineString', 'MultiLineString', 269 | 'Polygon', 'MultiPolygon', 270 | 'GeometryCollection' 271 | ]; 272 | function isGeojson(val) { 273 | if (typeof val !== 'object') { 274 | return false; 275 | } 276 | var type = val && val.type; 277 | if (types.indexOf(type) > -1) { 278 | return true; 279 | } 280 | return false; 281 | } 282 | exports.dateToString = function (date, timeZone) { 283 | var dt = new Date(date); 284 | 285 | if (timeZone !== 'local') { 286 | var tz = convertTimezone(timeZone); 287 | 288 | dt.setTime(dt.getTime() + dt.getTimezoneOffset() * 60000); 289 | if (tz !== false) { 290 | dt.setTime(dt.getTime() + tz * 60000); 291 | } 292 | } 293 | 294 | var year = dt.getFullYear(); 295 | var month = zeroPad(dt.getMonth() + 1, 2); 296 | var day = zeroPad(dt.getDate(), 2); 297 | var hour = zeroPad(dt.getHours(), 2); 298 | var minute = zeroPad(dt.getMinutes(), 2); 299 | var second = zeroPad(dt.getSeconds(), 2); 300 | var millisecond = zeroPad(dt.getMilliseconds(), 3); 301 | 302 | return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + millisecond; 303 | }; 304 | 305 | exports.bufferToString = function bufferToString(buffer) { 306 | return '$$\\x' + buffer.toString('hex') + '$$'; 307 | }; 308 | 309 | function zeroPad(number, length) { 310 | number = number.toString(); 311 | while (number.length < length) { 312 | number = '0' + number; 313 | } 314 | 315 | return number; 316 | } 317 | 318 | function convertTimezone(tz) { 319 | if (tz === 'Z') { 320 | return 0; 321 | } 322 | 323 | var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/); 324 | if (m) { 325 | return (m[1] === '-' ? -1 : 1) * (parseInt(m[2], 10) + (m[3] ? parseInt(m[3], 10) : 0) / 60) * 60; 326 | } 327 | return false; 328 | } 329 | // function prepare(opts) { 330 | // var sql = opts.sql; 331 | // var values = opts.values; 332 | // debug(values); 333 | // var name = makeName(); 334 | // if (opts.method === 'insert') { 335 | // var out = [ 336 | // 'PREPARE ' + name + ' AS', 337 | // sql 338 | // ]; 339 | // values.forEach(function (item) { 340 | // out.push('EXECUTE ' + name + (item.length ? ('(' + item.map().join(',') + ');') : ';')); 341 | // }); 342 | // return out.join('\n'); 343 | // } else { 344 | // return [ 345 | // 'PREPARE ' + name + ' AS', 346 | // sql, 347 | // 'EXECUTE ' + name + (values.length ? ('(' + values.join(',') + ');') : ';') 348 | // ].join('\n'); 349 | // } 350 | // } 351 | -------------------------------------------------------------------------------- /lib/write-stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var debugStream = require('debug')('cartodb:stream'); 3 | var stream = require('readable-stream'); 4 | var Transform = stream.Transform; 5 | var Promise = require('bluebird'); 6 | var duplexify = require('duplexify').obj; 7 | module.exports = function (cartodb) { 8 | return createWriteStream; 9 | function createWriteStream(table, opts) { 10 | opts = opts || {}; 11 | var created = !opts.create; 12 | var queue = []; 13 | var max = opts.batchSize || 50; 14 | var maxInProgress = opts.maxInProgress || 10; 15 | 16 | function mabyeCreate(chunk) { 17 | if (created) { 18 | return Promise.resolve(true); 19 | } 20 | return cartodb.schema.createTable(table, function (table) { 21 | Object.keys(chunk.properties).forEach(function (key) { 22 | switch(typeof chunk.properties[key]) { 23 | case 'number': 24 | return table.float(key); 25 | case 'boolean': 26 | return table.bool(key); 27 | default: 28 | if (chunk.properties[key] instanceof Date) { 29 | return table.timestamp(key, true); 30 | } 31 | return table.text(key); 32 | } 33 | }); 34 | }).then(function (a) { 35 | created = true; 36 | return a; 37 | }); 38 | } 39 | var transform = new Transform({ 40 | objectMode: true, 41 | transform: function (chunk, _, next) { 42 | var self = this; 43 | mabyeCreate(chunk).then(function () { 44 | queue.push(fixGeoJSON(chunk)); 45 | if (queue.length >= max) { 46 | var currentQueue = queue; 47 | queue = []; 48 | debugStream('queue'); 49 | self.push(currentQueue); 50 | next(); 51 | } else { 52 | next(); 53 | } 54 | }).catch(next); 55 | }, 56 | flush: function (done) { 57 | debugStream('flush'); 58 | if (queue.length) { 59 | this.push(queue); 60 | } 61 | done(); 62 | } 63 | }); 64 | var dup; 65 | var inProgress = 0; 66 | function maybeNext(next) { 67 | if (inProgress > maxInProgress) { 68 | return dup.once('inserted', function () { 69 | maybeNext(next); 70 | }); 71 | } 72 | next(); 73 | } 74 | var writable = new stream.Writable({ 75 | objectMode: true, 76 | write: function (chunk, _, next) { 77 | debugStream('write'); 78 | inProgress++; 79 | maybeNext(next); 80 | cartodb(table).insert(chunk).exec(function (err) { 81 | if (err) { 82 | dup.emit('error', err); 83 | } 84 | inProgress--; 85 | dup.emit('inserted', chunk.length); 86 | }); 87 | }, 88 | final: function (done) { 89 | if (!inProgress) { 90 | dup.emit('uploaded'); 91 | done(); 92 | } else { 93 | dup.on('inserted', function () { 94 | if (!inProgress) { 95 | dup.emit('uploaded'); 96 | done(); 97 | } 98 | }); 99 | } 100 | } 101 | }); 102 | transform.pipe(writable); 103 | dup = duplexify(transform, writable); 104 | return dup; 105 | } 106 | }; 107 | function fixGeoJSON(chunk) { 108 | var out = {}; 109 | Object.keys(chunk.properties).forEach(function (key) { 110 | out[key] = chunk.properties[key]; 111 | }); 112 | out.the_geom = chunk.geometry; 113 | return out; 114 | } 115 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015 Tim Griesser 2 | Copyright (C) 2015 Applied Geographics, Inc. & Calvin W. Metcalf 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cartodb-tools", 3 | "version": "2.11.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cartodb-tools", 9 | "version": "2.11.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bluebird": "^2.9.25", 13 | "debug": "^2.2.0", 14 | "duplexify": "^4.1.2", 15 | "inherits": "^2.0.1", 16 | "jsonstream3": "^3.0.0", 17 | "querystringparser": "^0.1.1", 18 | "readable-stream": "^4.2.0" 19 | }, 20 | "devDependencies": { 21 | "tape": "^5.6.1" 22 | } 23 | }, 24 | "node_modules/abort-controller": { 25 | "version": "3.0.0", 26 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 27 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 28 | "dependencies": { 29 | "event-target-shim": "^5.0.0" 30 | }, 31 | "engines": { 32 | "node": ">=6.5" 33 | } 34 | }, 35 | "node_modules/array.prototype.every": { 36 | "version": "1.1.3", 37 | "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", 38 | "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==", 39 | "dev": true, 40 | "dependencies": { 41 | "call-bind": "^1.0.2", 42 | "define-properties": "^1.1.3", 43 | "es-abstract": "^1.19.0", 44 | "is-string": "^1.0.7" 45 | }, 46 | "engines": { 47 | "node": ">= 0.4" 48 | }, 49 | "funding": { 50 | "url": "https://github.com/sponsors/ljharb" 51 | } 52 | }, 53 | "node_modules/available-typed-arrays": { 54 | "version": "1.0.5", 55 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 56 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 57 | "dev": true, 58 | "engines": { 59 | "node": ">= 0.4" 60 | }, 61 | "funding": { 62 | "url": "https://github.com/sponsors/ljharb" 63 | } 64 | }, 65 | "node_modules/balanced-match": { 66 | "version": "1.0.2", 67 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 68 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 69 | "dev": true 70 | }, 71 | "node_modules/base64-js": { 72 | "version": "1.5.1", 73 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 74 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 75 | "funding": [ 76 | { 77 | "type": "github", 78 | "url": "https://github.com/sponsors/feross" 79 | }, 80 | { 81 | "type": "patreon", 82 | "url": "https://www.patreon.com/feross" 83 | }, 84 | { 85 | "type": "consulting", 86 | "url": "https://feross.org/support" 87 | } 88 | ] 89 | }, 90 | "node_modules/bluebird": { 91 | "version": "2.11.0", 92 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", 93 | "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" 94 | }, 95 | "node_modules/brace-expansion": { 96 | "version": "1.1.11", 97 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 98 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 99 | "dev": true, 100 | "dependencies": { 101 | "balanced-match": "^1.0.0", 102 | "concat-map": "0.0.1" 103 | } 104 | }, 105 | "node_modules/buffer": { 106 | "version": "6.0.3", 107 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 108 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 109 | "funding": [ 110 | { 111 | "type": "github", 112 | "url": "https://github.com/sponsors/feross" 113 | }, 114 | { 115 | "type": "patreon", 116 | "url": "https://www.patreon.com/feross" 117 | }, 118 | { 119 | "type": "consulting", 120 | "url": "https://feross.org/support" 121 | } 122 | ], 123 | "dependencies": { 124 | "base64-js": "^1.3.1", 125 | "ieee754": "^1.2.1" 126 | } 127 | }, 128 | "node_modules/call-bind": { 129 | "version": "1.0.2", 130 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 131 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 132 | "dev": true, 133 | "dependencies": { 134 | "function-bind": "^1.1.1", 135 | "get-intrinsic": "^1.0.2" 136 | }, 137 | "funding": { 138 | "url": "https://github.com/sponsors/ljharb" 139 | } 140 | }, 141 | "node_modules/concat-map": { 142 | "version": "0.0.1", 143 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 144 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 145 | "dev": true 146 | }, 147 | "node_modules/core-util-is": { 148 | "version": "1.0.3", 149 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 150 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" 151 | }, 152 | "node_modules/debug": { 153 | "version": "2.6.9", 154 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 155 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 156 | "dependencies": { 157 | "ms": "2.0.0" 158 | } 159 | }, 160 | "node_modules/deep-equal": { 161 | "version": "2.0.5", 162 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", 163 | "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", 164 | "dev": true, 165 | "dependencies": { 166 | "call-bind": "^1.0.0", 167 | "es-get-iterator": "^1.1.1", 168 | "get-intrinsic": "^1.0.1", 169 | "is-arguments": "^1.0.4", 170 | "is-date-object": "^1.0.2", 171 | "is-regex": "^1.1.1", 172 | "isarray": "^2.0.5", 173 | "object-is": "^1.1.4", 174 | "object-keys": "^1.1.1", 175 | "object.assign": "^4.1.2", 176 | "regexp.prototype.flags": "^1.3.0", 177 | "side-channel": "^1.0.3", 178 | "which-boxed-primitive": "^1.0.1", 179 | "which-collection": "^1.0.1", 180 | "which-typed-array": "^1.1.2" 181 | }, 182 | "funding": { 183 | "url": "https://github.com/sponsors/ljharb" 184 | } 185 | }, 186 | "node_modules/define-properties": { 187 | "version": "1.1.4", 188 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 189 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 190 | "dev": true, 191 | "dependencies": { 192 | "has-property-descriptors": "^1.0.0", 193 | "object-keys": "^1.1.1" 194 | }, 195 | "engines": { 196 | "node": ">= 0.4" 197 | }, 198 | "funding": { 199 | "url": "https://github.com/sponsors/ljharb" 200 | } 201 | }, 202 | "node_modules/defined": { 203 | "version": "1.0.0", 204 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 205 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 206 | "dev": true 207 | }, 208 | "node_modules/dotignore": { 209 | "version": "0.1.2", 210 | "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", 211 | "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", 212 | "dev": true, 213 | "dependencies": { 214 | "minimatch": "^3.0.4" 215 | }, 216 | "bin": { 217 | "ignored": "bin/ignored" 218 | } 219 | }, 220 | "node_modules/duplexify": { 221 | "version": "4.1.2", 222 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", 223 | "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", 224 | "dependencies": { 225 | "end-of-stream": "^1.4.1", 226 | "inherits": "^2.0.3", 227 | "readable-stream": "^3.1.1", 228 | "stream-shift": "^1.0.0" 229 | } 230 | }, 231 | "node_modules/duplexify/node_modules/readable-stream": { 232 | "version": "3.6.0", 233 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 234 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 235 | "dependencies": { 236 | "inherits": "^2.0.3", 237 | "string_decoder": "^1.1.1", 238 | "util-deprecate": "^1.0.1" 239 | }, 240 | "engines": { 241 | "node": ">= 6" 242 | } 243 | }, 244 | "node_modules/end-of-stream": { 245 | "version": "1.4.1", 246 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", 247 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", 248 | "dependencies": { 249 | "once": "^1.4.0" 250 | } 251 | }, 252 | "node_modules/es-abstract": { 253 | "version": "1.20.3", 254 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", 255 | "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", 256 | "dev": true, 257 | "dependencies": { 258 | "call-bind": "^1.0.2", 259 | "es-to-primitive": "^1.2.1", 260 | "function-bind": "^1.1.1", 261 | "function.prototype.name": "^1.1.5", 262 | "get-intrinsic": "^1.1.3", 263 | "get-symbol-description": "^1.0.0", 264 | "has": "^1.0.3", 265 | "has-property-descriptors": "^1.0.0", 266 | "has-symbols": "^1.0.3", 267 | "internal-slot": "^1.0.3", 268 | "is-callable": "^1.2.6", 269 | "is-negative-zero": "^2.0.2", 270 | "is-regex": "^1.1.4", 271 | "is-shared-array-buffer": "^1.0.2", 272 | "is-string": "^1.0.7", 273 | "is-weakref": "^1.0.2", 274 | "object-inspect": "^1.12.2", 275 | "object-keys": "^1.1.1", 276 | "object.assign": "^4.1.4", 277 | "regexp.prototype.flags": "^1.4.3", 278 | "safe-regex-test": "^1.0.0", 279 | "string.prototype.trimend": "^1.0.5", 280 | "string.prototype.trimstart": "^1.0.5", 281 | "unbox-primitive": "^1.0.2" 282 | }, 283 | "engines": { 284 | "node": ">= 0.4" 285 | }, 286 | "funding": { 287 | "url": "https://github.com/sponsors/ljharb" 288 | } 289 | }, 290 | "node_modules/es-get-iterator": { 291 | "version": "1.1.2", 292 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", 293 | "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", 294 | "dev": true, 295 | "dependencies": { 296 | "call-bind": "^1.0.2", 297 | "get-intrinsic": "^1.1.0", 298 | "has-symbols": "^1.0.1", 299 | "is-arguments": "^1.1.0", 300 | "is-map": "^2.0.2", 301 | "is-set": "^2.0.2", 302 | "is-string": "^1.0.5", 303 | "isarray": "^2.0.5" 304 | }, 305 | "funding": { 306 | "url": "https://github.com/sponsors/ljharb" 307 | } 308 | }, 309 | "node_modules/es-to-primitive": { 310 | "version": "1.2.1", 311 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 312 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 313 | "dev": true, 314 | "dependencies": { 315 | "is-callable": "^1.1.4", 316 | "is-date-object": "^1.0.1", 317 | "is-symbol": "^1.0.2" 318 | }, 319 | "engines": { 320 | "node": ">= 0.4" 321 | }, 322 | "funding": { 323 | "url": "https://github.com/sponsors/ljharb" 324 | } 325 | }, 326 | "node_modules/event-target-shim": { 327 | "version": "5.0.1", 328 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 329 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", 330 | "engines": { 331 | "node": ">=6" 332 | } 333 | }, 334 | "node_modules/events": { 335 | "version": "3.3.0", 336 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 337 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", 338 | "engines": { 339 | "node": ">=0.8.x" 340 | } 341 | }, 342 | "node_modules/for-each": { 343 | "version": "0.3.3", 344 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 345 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 346 | "dev": true, 347 | "dependencies": { 348 | "is-callable": "^1.1.3" 349 | } 350 | }, 351 | "node_modules/fs.realpath": { 352 | "version": "1.0.0", 353 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 354 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 355 | "dev": true 356 | }, 357 | "node_modules/function-bind": { 358 | "version": "1.1.1", 359 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 360 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 361 | "dev": true 362 | }, 363 | "node_modules/function.prototype.name": { 364 | "version": "1.1.5", 365 | "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", 366 | "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", 367 | "dev": true, 368 | "dependencies": { 369 | "call-bind": "^1.0.2", 370 | "define-properties": "^1.1.3", 371 | "es-abstract": "^1.19.0", 372 | "functions-have-names": "^1.2.2" 373 | }, 374 | "engines": { 375 | "node": ">= 0.4" 376 | }, 377 | "funding": { 378 | "url": "https://github.com/sponsors/ljharb" 379 | } 380 | }, 381 | "node_modules/functions-have-names": { 382 | "version": "1.2.3", 383 | "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", 384 | "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", 385 | "dev": true, 386 | "funding": { 387 | "url": "https://github.com/sponsors/ljharb" 388 | } 389 | }, 390 | "node_modules/get-intrinsic": { 391 | "version": "1.1.3", 392 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 393 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 394 | "dev": true, 395 | "dependencies": { 396 | "function-bind": "^1.1.1", 397 | "has": "^1.0.3", 398 | "has-symbols": "^1.0.3" 399 | }, 400 | "funding": { 401 | "url": "https://github.com/sponsors/ljharb" 402 | } 403 | }, 404 | "node_modules/get-package-type": { 405 | "version": "0.1.0", 406 | "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", 407 | "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", 408 | "dev": true, 409 | "engines": { 410 | "node": ">=8.0.0" 411 | } 412 | }, 413 | "node_modules/get-symbol-description": { 414 | "version": "1.0.0", 415 | "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", 416 | "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", 417 | "dev": true, 418 | "dependencies": { 419 | "call-bind": "^1.0.2", 420 | "get-intrinsic": "^1.1.1" 421 | }, 422 | "engines": { 423 | "node": ">= 0.4" 424 | }, 425 | "funding": { 426 | "url": "https://github.com/sponsors/ljharb" 427 | } 428 | }, 429 | "node_modules/glob": { 430 | "version": "7.2.3", 431 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 432 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 433 | "dev": true, 434 | "dependencies": { 435 | "fs.realpath": "^1.0.0", 436 | "inflight": "^1.0.4", 437 | "inherits": "2", 438 | "minimatch": "^3.1.1", 439 | "once": "^1.3.0", 440 | "path-is-absolute": "^1.0.0" 441 | }, 442 | "engines": { 443 | "node": "*" 444 | }, 445 | "funding": { 446 | "url": "https://github.com/sponsors/isaacs" 447 | } 448 | }, 449 | "node_modules/has": { 450 | "version": "1.0.3", 451 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 452 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 453 | "dev": true, 454 | "dependencies": { 455 | "function-bind": "^1.1.1" 456 | }, 457 | "engines": { 458 | "node": ">= 0.4.0" 459 | } 460 | }, 461 | "node_modules/has-bigints": { 462 | "version": "1.0.2", 463 | "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", 464 | "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", 465 | "dev": true, 466 | "funding": { 467 | "url": "https://github.com/sponsors/ljharb" 468 | } 469 | }, 470 | "node_modules/has-dynamic-import": { 471 | "version": "2.0.1", 472 | "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz", 473 | "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==", 474 | "dev": true, 475 | "dependencies": { 476 | "call-bind": "^1.0.2", 477 | "get-intrinsic": "^1.1.1" 478 | }, 479 | "funding": { 480 | "url": "https://github.com/sponsors/ljharb" 481 | } 482 | }, 483 | "node_modules/has-property-descriptors": { 484 | "version": "1.0.0", 485 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 486 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 487 | "dev": true, 488 | "dependencies": { 489 | "get-intrinsic": "^1.1.1" 490 | }, 491 | "funding": { 492 | "url": "https://github.com/sponsors/ljharb" 493 | } 494 | }, 495 | "node_modules/has-symbols": { 496 | "version": "1.0.3", 497 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 498 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 499 | "dev": true, 500 | "engines": { 501 | "node": ">= 0.4" 502 | }, 503 | "funding": { 504 | "url": "https://github.com/sponsors/ljharb" 505 | } 506 | }, 507 | "node_modules/has-tostringtag": { 508 | "version": "1.0.0", 509 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 510 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 511 | "dev": true, 512 | "dependencies": { 513 | "has-symbols": "^1.0.2" 514 | }, 515 | "engines": { 516 | "node": ">= 0.4" 517 | }, 518 | "funding": { 519 | "url": "https://github.com/sponsors/ljharb" 520 | } 521 | }, 522 | "node_modules/ieee754": { 523 | "version": "1.2.1", 524 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 525 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 526 | "funding": [ 527 | { 528 | "type": "github", 529 | "url": "https://github.com/sponsors/feross" 530 | }, 531 | { 532 | "type": "patreon", 533 | "url": "https://www.patreon.com/feross" 534 | }, 535 | { 536 | "type": "consulting", 537 | "url": "https://feross.org/support" 538 | } 539 | ] 540 | }, 541 | "node_modules/inflight": { 542 | "version": "1.0.6", 543 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 544 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 545 | "dev": true, 546 | "dependencies": { 547 | "once": "^1.3.0", 548 | "wrappy": "1" 549 | } 550 | }, 551 | "node_modules/inherits": { 552 | "version": "2.0.4", 553 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 554 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 555 | }, 556 | "node_modules/internal-slot": { 557 | "version": "1.0.3", 558 | "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", 559 | "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", 560 | "dev": true, 561 | "dependencies": { 562 | "get-intrinsic": "^1.1.0", 563 | "has": "^1.0.3", 564 | "side-channel": "^1.0.4" 565 | }, 566 | "engines": { 567 | "node": ">= 0.4" 568 | } 569 | }, 570 | "node_modules/is-arguments": { 571 | "version": "1.1.1", 572 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 573 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 574 | "dev": true, 575 | "dependencies": { 576 | "call-bind": "^1.0.2", 577 | "has-tostringtag": "^1.0.0" 578 | }, 579 | "engines": { 580 | "node": ">= 0.4" 581 | }, 582 | "funding": { 583 | "url": "https://github.com/sponsors/ljharb" 584 | } 585 | }, 586 | "node_modules/is-bigint": { 587 | "version": "1.0.4", 588 | "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", 589 | "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", 590 | "dev": true, 591 | "dependencies": { 592 | "has-bigints": "^1.0.1" 593 | }, 594 | "funding": { 595 | "url": "https://github.com/sponsors/ljharb" 596 | } 597 | }, 598 | "node_modules/is-boolean-object": { 599 | "version": "1.1.2", 600 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", 601 | "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", 602 | "dev": true, 603 | "dependencies": { 604 | "call-bind": "^1.0.2", 605 | "has-tostringtag": "^1.0.0" 606 | }, 607 | "engines": { 608 | "node": ">= 0.4" 609 | }, 610 | "funding": { 611 | "url": "https://github.com/sponsors/ljharb" 612 | } 613 | }, 614 | "node_modules/is-callable": { 615 | "version": "1.2.7", 616 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 617 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 618 | "dev": true, 619 | "engines": { 620 | "node": ">= 0.4" 621 | }, 622 | "funding": { 623 | "url": "https://github.com/sponsors/ljharb" 624 | } 625 | }, 626 | "node_modules/is-core-module": { 627 | "version": "2.10.0", 628 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", 629 | "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", 630 | "dev": true, 631 | "dependencies": { 632 | "has": "^1.0.3" 633 | }, 634 | "funding": { 635 | "url": "https://github.com/sponsors/ljharb" 636 | } 637 | }, 638 | "node_modules/is-date-object": { 639 | "version": "1.0.5", 640 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", 641 | "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", 642 | "dev": true, 643 | "dependencies": { 644 | "has-tostringtag": "^1.0.0" 645 | }, 646 | "engines": { 647 | "node": ">= 0.4" 648 | }, 649 | "funding": { 650 | "url": "https://github.com/sponsors/ljharb" 651 | } 652 | }, 653 | "node_modules/is-map": { 654 | "version": "2.0.2", 655 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", 656 | "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", 657 | "dev": true, 658 | "funding": { 659 | "url": "https://github.com/sponsors/ljharb" 660 | } 661 | }, 662 | "node_modules/is-negative-zero": { 663 | "version": "2.0.2", 664 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", 665 | "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", 666 | "dev": true, 667 | "engines": { 668 | "node": ">= 0.4" 669 | }, 670 | "funding": { 671 | "url": "https://github.com/sponsors/ljharb" 672 | } 673 | }, 674 | "node_modules/is-number-object": { 675 | "version": "1.0.7", 676 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", 677 | "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", 678 | "dev": true, 679 | "dependencies": { 680 | "has-tostringtag": "^1.0.0" 681 | }, 682 | "engines": { 683 | "node": ">= 0.4" 684 | }, 685 | "funding": { 686 | "url": "https://github.com/sponsors/ljharb" 687 | } 688 | }, 689 | "node_modules/is-regex": { 690 | "version": "1.1.4", 691 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 692 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 693 | "dev": true, 694 | "dependencies": { 695 | "call-bind": "^1.0.2", 696 | "has-tostringtag": "^1.0.0" 697 | }, 698 | "engines": { 699 | "node": ">= 0.4" 700 | }, 701 | "funding": { 702 | "url": "https://github.com/sponsors/ljharb" 703 | } 704 | }, 705 | "node_modules/is-set": { 706 | "version": "2.0.2", 707 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", 708 | "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", 709 | "dev": true, 710 | "funding": { 711 | "url": "https://github.com/sponsors/ljharb" 712 | } 713 | }, 714 | "node_modules/is-shared-array-buffer": { 715 | "version": "1.0.2", 716 | "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", 717 | "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", 718 | "dev": true, 719 | "dependencies": { 720 | "call-bind": "^1.0.2" 721 | }, 722 | "funding": { 723 | "url": "https://github.com/sponsors/ljharb" 724 | } 725 | }, 726 | "node_modules/is-string": { 727 | "version": "1.0.7", 728 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", 729 | "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", 730 | "dev": true, 731 | "dependencies": { 732 | "has-tostringtag": "^1.0.0" 733 | }, 734 | "engines": { 735 | "node": ">= 0.4" 736 | }, 737 | "funding": { 738 | "url": "https://github.com/sponsors/ljharb" 739 | } 740 | }, 741 | "node_modules/is-symbol": { 742 | "version": "1.0.4", 743 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", 744 | "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", 745 | "dev": true, 746 | "dependencies": { 747 | "has-symbols": "^1.0.2" 748 | }, 749 | "engines": { 750 | "node": ">= 0.4" 751 | }, 752 | "funding": { 753 | "url": "https://github.com/sponsors/ljharb" 754 | } 755 | }, 756 | "node_modules/is-typed-array": { 757 | "version": "1.1.9", 758 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", 759 | "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", 760 | "dev": true, 761 | "dependencies": { 762 | "available-typed-arrays": "^1.0.5", 763 | "call-bind": "^1.0.2", 764 | "es-abstract": "^1.20.0", 765 | "for-each": "^0.3.3", 766 | "has-tostringtag": "^1.0.0" 767 | }, 768 | "engines": { 769 | "node": ">= 0.4" 770 | }, 771 | "funding": { 772 | "url": "https://github.com/sponsors/ljharb" 773 | } 774 | }, 775 | "node_modules/is-weakmap": { 776 | "version": "2.0.1", 777 | "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", 778 | "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", 779 | "dev": true, 780 | "funding": { 781 | "url": "https://github.com/sponsors/ljharb" 782 | } 783 | }, 784 | "node_modules/is-weakref": { 785 | "version": "1.0.2", 786 | "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", 787 | "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", 788 | "dev": true, 789 | "dependencies": { 790 | "call-bind": "^1.0.2" 791 | }, 792 | "funding": { 793 | "url": "https://github.com/sponsors/ljharb" 794 | } 795 | }, 796 | "node_modules/is-weakset": { 797 | "version": "2.0.2", 798 | "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", 799 | "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", 800 | "dev": true, 801 | "dependencies": { 802 | "call-bind": "^1.0.2", 803 | "get-intrinsic": "^1.1.1" 804 | }, 805 | "funding": { 806 | "url": "https://github.com/sponsors/ljharb" 807 | } 808 | }, 809 | "node_modules/isarray": { 810 | "version": "2.0.5", 811 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", 812 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", 813 | "dev": true 814 | }, 815 | "node_modules/jsonparse": { 816 | "version": "1.0.0", 817 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz", 818 | "integrity": "sha1-JiL05mwI4arH7b63YFPJt+EhH3Y=", 819 | "engines": [ 820 | "node >= 0.2.0" 821 | ] 822 | }, 823 | "node_modules/jsonstream3": { 824 | "version": "3.0.0", 825 | "resolved": "https://registry.npmjs.org/jsonstream3/-/jsonstream3-3.0.0.tgz", 826 | "integrity": "sha1-hW6jECnE1Azx3m3Zkob1nIYYWDM=", 827 | "dependencies": { 828 | "inherits": "^2.0.1", 829 | "jsonparse": "~1.0.0", 830 | "readable-stream": "^2.0.2" 831 | }, 832 | "bin": { 833 | "jsonstream3": "index.js" 834 | }, 835 | "engines": { 836 | "node": "*" 837 | } 838 | }, 839 | "node_modules/jsonstream3/node_modules/isarray": { 840 | "version": "1.0.0", 841 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 842 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" 843 | }, 844 | "node_modules/jsonstream3/node_modules/readable-stream": { 845 | "version": "2.3.7", 846 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 847 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 848 | "dependencies": { 849 | "core-util-is": "~1.0.0", 850 | "inherits": "~2.0.3", 851 | "isarray": "~1.0.0", 852 | "process-nextick-args": "~2.0.0", 853 | "safe-buffer": "~5.1.1", 854 | "string_decoder": "~1.1.1", 855 | "util-deprecate": "~1.0.1" 856 | } 857 | }, 858 | "node_modules/jsonstream3/node_modules/safe-buffer": { 859 | "version": "5.1.2", 860 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 861 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 862 | }, 863 | "node_modules/jsonstream3/node_modules/string_decoder": { 864 | "version": "1.1.1", 865 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 866 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 867 | "dependencies": { 868 | "safe-buffer": "~5.1.0" 869 | } 870 | }, 871 | "node_modules/minimatch": { 872 | "version": "3.1.2", 873 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 874 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 875 | "dev": true, 876 | "dependencies": { 877 | "brace-expansion": "^1.1.7" 878 | }, 879 | "engines": { 880 | "node": "*" 881 | } 882 | }, 883 | "node_modules/minimist": { 884 | "version": "1.2.6", 885 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 886 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 887 | "dev": true 888 | }, 889 | "node_modules/ms": { 890 | "version": "2.0.0", 891 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 892 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 893 | }, 894 | "node_modules/object-inspect": { 895 | "version": "1.12.2", 896 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 897 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 898 | "dev": true, 899 | "funding": { 900 | "url": "https://github.com/sponsors/ljharb" 901 | } 902 | }, 903 | "node_modules/object-is": { 904 | "version": "1.1.5", 905 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", 906 | "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", 907 | "dev": true, 908 | "dependencies": { 909 | "call-bind": "^1.0.2", 910 | "define-properties": "^1.1.3" 911 | }, 912 | "engines": { 913 | "node": ">= 0.4" 914 | }, 915 | "funding": { 916 | "url": "https://github.com/sponsors/ljharb" 917 | } 918 | }, 919 | "node_modules/object-keys": { 920 | "version": "1.1.1", 921 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 922 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 923 | "dev": true, 924 | "engines": { 925 | "node": ">= 0.4" 926 | } 927 | }, 928 | "node_modules/object.assign": { 929 | "version": "4.1.4", 930 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", 931 | "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", 932 | "dev": true, 933 | "dependencies": { 934 | "call-bind": "^1.0.2", 935 | "define-properties": "^1.1.4", 936 | "has-symbols": "^1.0.3", 937 | "object-keys": "^1.1.1" 938 | }, 939 | "engines": { 940 | "node": ">= 0.4" 941 | }, 942 | "funding": { 943 | "url": "https://github.com/sponsors/ljharb" 944 | } 945 | }, 946 | "node_modules/once": { 947 | "version": "1.4.0", 948 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 949 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 950 | "dependencies": { 951 | "wrappy": "1" 952 | } 953 | }, 954 | "node_modules/path-is-absolute": { 955 | "version": "1.0.1", 956 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 957 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 958 | "dev": true, 959 | "engines": { 960 | "node": ">=0.10.0" 961 | } 962 | }, 963 | "node_modules/path-parse": { 964 | "version": "1.0.7", 965 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 966 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 967 | "dev": true 968 | }, 969 | "node_modules/process": { 970 | "version": "0.11.10", 971 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 972 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 973 | "engines": { 974 | "node": ">= 0.6.0" 975 | } 976 | }, 977 | "node_modules/process-nextick-args": { 978 | "version": "2.0.1", 979 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 980 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 981 | }, 982 | "node_modules/querystringparser": { 983 | "version": "0.1.1", 984 | "resolved": "https://registry.npmjs.org/querystringparser/-/querystringparser-0.1.1.tgz", 985 | "integrity": "sha1-nl9OoURkHbpjjZ23GGnSZ1J9w4A=" 986 | }, 987 | "node_modules/readable-stream": { 988 | "version": "4.2.0", 989 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", 990 | "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", 991 | "dependencies": { 992 | "abort-controller": "^3.0.0", 993 | "buffer": "^6.0.3", 994 | "events": "^3.3.0", 995 | "process": "^0.11.10" 996 | }, 997 | "engines": { 998 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 999 | } 1000 | }, 1001 | "node_modules/regexp.prototype.flags": { 1002 | "version": "1.4.3", 1003 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", 1004 | "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", 1005 | "dev": true, 1006 | "dependencies": { 1007 | "call-bind": "^1.0.2", 1008 | "define-properties": "^1.1.3", 1009 | "functions-have-names": "^1.2.2" 1010 | }, 1011 | "engines": { 1012 | "node": ">= 0.4" 1013 | }, 1014 | "funding": { 1015 | "url": "https://github.com/sponsors/ljharb" 1016 | } 1017 | }, 1018 | "node_modules/resolve": { 1019 | "version": "2.0.0-next.4", 1020 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", 1021 | "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", 1022 | "dev": true, 1023 | "dependencies": { 1024 | "is-core-module": "^2.9.0", 1025 | "path-parse": "^1.0.7", 1026 | "supports-preserve-symlinks-flag": "^1.0.0" 1027 | }, 1028 | "bin": { 1029 | "resolve": "bin/resolve" 1030 | }, 1031 | "funding": { 1032 | "url": "https://github.com/sponsors/ljharb" 1033 | } 1034 | }, 1035 | "node_modules/resumer": { 1036 | "version": "0.0.0", 1037 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 1038 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 1039 | "dev": true, 1040 | "dependencies": { 1041 | "through": "~2.3.4" 1042 | } 1043 | }, 1044 | "node_modules/safe-buffer": { 1045 | "version": "5.2.1", 1046 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1047 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1048 | "funding": [ 1049 | { 1050 | "type": "github", 1051 | "url": "https://github.com/sponsors/feross" 1052 | }, 1053 | { 1054 | "type": "patreon", 1055 | "url": "https://www.patreon.com/feross" 1056 | }, 1057 | { 1058 | "type": "consulting", 1059 | "url": "https://feross.org/support" 1060 | } 1061 | ] 1062 | }, 1063 | "node_modules/safe-regex-test": { 1064 | "version": "1.0.0", 1065 | "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", 1066 | "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", 1067 | "dev": true, 1068 | "dependencies": { 1069 | "call-bind": "^1.0.2", 1070 | "get-intrinsic": "^1.1.3", 1071 | "is-regex": "^1.1.4" 1072 | }, 1073 | "funding": { 1074 | "url": "https://github.com/sponsors/ljharb" 1075 | } 1076 | }, 1077 | "node_modules/side-channel": { 1078 | "version": "1.0.4", 1079 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1080 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1081 | "dev": true, 1082 | "dependencies": { 1083 | "call-bind": "^1.0.0", 1084 | "get-intrinsic": "^1.0.2", 1085 | "object-inspect": "^1.9.0" 1086 | }, 1087 | "funding": { 1088 | "url": "https://github.com/sponsors/ljharb" 1089 | } 1090 | }, 1091 | "node_modules/stream-shift": { 1092 | "version": "1.0.0", 1093 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", 1094 | "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" 1095 | }, 1096 | "node_modules/string_decoder": { 1097 | "version": "1.3.0", 1098 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1099 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1100 | "dependencies": { 1101 | "safe-buffer": "~5.2.0" 1102 | } 1103 | }, 1104 | "node_modules/string.prototype.trim": { 1105 | "version": "1.2.6", 1106 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz", 1107 | "integrity": "sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ==", 1108 | "dev": true, 1109 | "dependencies": { 1110 | "call-bind": "^1.0.2", 1111 | "define-properties": "^1.1.4", 1112 | "es-abstract": "^1.19.5" 1113 | }, 1114 | "engines": { 1115 | "node": ">= 0.4" 1116 | }, 1117 | "funding": { 1118 | "url": "https://github.com/sponsors/ljharb" 1119 | } 1120 | }, 1121 | "node_modules/string.prototype.trimend": { 1122 | "version": "1.0.5", 1123 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", 1124 | "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", 1125 | "dev": true, 1126 | "dependencies": { 1127 | "call-bind": "^1.0.2", 1128 | "define-properties": "^1.1.4", 1129 | "es-abstract": "^1.19.5" 1130 | }, 1131 | "funding": { 1132 | "url": "https://github.com/sponsors/ljharb" 1133 | } 1134 | }, 1135 | "node_modules/string.prototype.trimstart": { 1136 | "version": "1.0.5", 1137 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", 1138 | "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", 1139 | "dev": true, 1140 | "dependencies": { 1141 | "call-bind": "^1.0.2", 1142 | "define-properties": "^1.1.4", 1143 | "es-abstract": "^1.19.5" 1144 | }, 1145 | "funding": { 1146 | "url": "https://github.com/sponsors/ljharb" 1147 | } 1148 | }, 1149 | "node_modules/supports-preserve-symlinks-flag": { 1150 | "version": "1.0.0", 1151 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1152 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1153 | "dev": true, 1154 | "engines": { 1155 | "node": ">= 0.4" 1156 | }, 1157 | "funding": { 1158 | "url": "https://github.com/sponsors/ljharb" 1159 | } 1160 | }, 1161 | "node_modules/tape": { 1162 | "version": "5.6.1", 1163 | "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.1.tgz", 1164 | "integrity": "sha512-reNzS3rzsJtKk0f+zJx2XlzIsjJXlIcOIrIxk5shHAG/DzW3BKyMg8UfN79oluYlcWo4lIt56ahLqwgpRT4idg==", 1165 | "dev": true, 1166 | "dependencies": { 1167 | "array.prototype.every": "^1.1.3", 1168 | "call-bind": "^1.0.2", 1169 | "deep-equal": "^2.0.5", 1170 | "defined": "^1.0.0", 1171 | "dotignore": "^0.1.2", 1172 | "for-each": "^0.3.3", 1173 | "get-package-type": "^0.1.0", 1174 | "glob": "^7.2.3", 1175 | "has": "^1.0.3", 1176 | "has-dynamic-import": "^2.0.1", 1177 | "inherits": "^2.0.4", 1178 | "is-regex": "^1.1.4", 1179 | "minimist": "^1.2.6", 1180 | "object-inspect": "^1.12.2", 1181 | "object-is": "^1.1.5", 1182 | "object-keys": "^1.1.1", 1183 | "object.assign": "^4.1.4", 1184 | "resolve": "^2.0.0-next.3", 1185 | "resumer": "^0.0.0", 1186 | "string.prototype.trim": "^1.2.6", 1187 | "through": "^2.3.8" 1188 | }, 1189 | "bin": { 1190 | "tape": "bin/tape" 1191 | }, 1192 | "funding": { 1193 | "url": "https://github.com/sponsors/ljharb" 1194 | } 1195 | }, 1196 | "node_modules/through": { 1197 | "version": "2.3.8", 1198 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1199 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1200 | "dev": true 1201 | }, 1202 | "node_modules/unbox-primitive": { 1203 | "version": "1.0.2", 1204 | "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", 1205 | "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", 1206 | "dev": true, 1207 | "dependencies": { 1208 | "call-bind": "^1.0.2", 1209 | "has-bigints": "^1.0.2", 1210 | "has-symbols": "^1.0.3", 1211 | "which-boxed-primitive": "^1.0.2" 1212 | }, 1213 | "funding": { 1214 | "url": "https://github.com/sponsors/ljharb" 1215 | } 1216 | }, 1217 | "node_modules/util-deprecate": { 1218 | "version": "1.0.2", 1219 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1220 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 1221 | }, 1222 | "node_modules/which-boxed-primitive": { 1223 | "version": "1.0.2", 1224 | "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", 1225 | "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", 1226 | "dev": true, 1227 | "dependencies": { 1228 | "is-bigint": "^1.0.1", 1229 | "is-boolean-object": "^1.1.0", 1230 | "is-number-object": "^1.0.4", 1231 | "is-string": "^1.0.5", 1232 | "is-symbol": "^1.0.3" 1233 | }, 1234 | "funding": { 1235 | "url": "https://github.com/sponsors/ljharb" 1236 | } 1237 | }, 1238 | "node_modules/which-collection": { 1239 | "version": "1.0.1", 1240 | "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", 1241 | "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", 1242 | "dev": true, 1243 | "dependencies": { 1244 | "is-map": "^2.0.1", 1245 | "is-set": "^2.0.1", 1246 | "is-weakmap": "^2.0.1", 1247 | "is-weakset": "^2.0.1" 1248 | }, 1249 | "funding": { 1250 | "url": "https://github.com/sponsors/ljharb" 1251 | } 1252 | }, 1253 | "node_modules/which-typed-array": { 1254 | "version": "1.1.8", 1255 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", 1256 | "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", 1257 | "dev": true, 1258 | "dependencies": { 1259 | "available-typed-arrays": "^1.0.5", 1260 | "call-bind": "^1.0.2", 1261 | "es-abstract": "^1.20.0", 1262 | "for-each": "^0.3.3", 1263 | "has-tostringtag": "^1.0.0", 1264 | "is-typed-array": "^1.1.9" 1265 | }, 1266 | "engines": { 1267 | "node": ">= 0.4" 1268 | }, 1269 | "funding": { 1270 | "url": "https://github.com/sponsors/ljharb" 1271 | } 1272 | }, 1273 | "node_modules/wrappy": { 1274 | "version": "1.0.2", 1275 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1276 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1277 | } 1278 | }, 1279 | "dependencies": { 1280 | "abort-controller": { 1281 | "version": "3.0.0", 1282 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 1283 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 1284 | "requires": { 1285 | "event-target-shim": "^5.0.0" 1286 | } 1287 | }, 1288 | "array.prototype.every": { 1289 | "version": "1.1.3", 1290 | "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", 1291 | "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==", 1292 | "dev": true, 1293 | "requires": { 1294 | "call-bind": "^1.0.2", 1295 | "define-properties": "^1.1.3", 1296 | "es-abstract": "^1.19.0", 1297 | "is-string": "^1.0.7" 1298 | } 1299 | }, 1300 | "available-typed-arrays": { 1301 | "version": "1.0.5", 1302 | "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", 1303 | "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", 1304 | "dev": true 1305 | }, 1306 | "balanced-match": { 1307 | "version": "1.0.2", 1308 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1309 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1310 | "dev": true 1311 | }, 1312 | "base64-js": { 1313 | "version": "1.5.1", 1314 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1315 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 1316 | }, 1317 | "bluebird": { 1318 | "version": "2.11.0", 1319 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", 1320 | "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" 1321 | }, 1322 | "brace-expansion": { 1323 | "version": "1.1.11", 1324 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1325 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1326 | "dev": true, 1327 | "requires": { 1328 | "balanced-match": "^1.0.0", 1329 | "concat-map": "0.0.1" 1330 | } 1331 | }, 1332 | "buffer": { 1333 | "version": "6.0.3", 1334 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 1335 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 1336 | "requires": { 1337 | "base64-js": "^1.3.1", 1338 | "ieee754": "^1.2.1" 1339 | } 1340 | }, 1341 | "call-bind": { 1342 | "version": "1.0.2", 1343 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 1344 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 1345 | "dev": true, 1346 | "requires": { 1347 | "function-bind": "^1.1.1", 1348 | "get-intrinsic": "^1.0.2" 1349 | } 1350 | }, 1351 | "concat-map": { 1352 | "version": "0.0.1", 1353 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1354 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1355 | "dev": true 1356 | }, 1357 | "core-util-is": { 1358 | "version": "1.0.3", 1359 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 1360 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" 1361 | }, 1362 | "debug": { 1363 | "version": "2.6.9", 1364 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1365 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1366 | "requires": { 1367 | "ms": "2.0.0" 1368 | } 1369 | }, 1370 | "deep-equal": { 1371 | "version": "2.0.5", 1372 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", 1373 | "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", 1374 | "dev": true, 1375 | "requires": { 1376 | "call-bind": "^1.0.0", 1377 | "es-get-iterator": "^1.1.1", 1378 | "get-intrinsic": "^1.0.1", 1379 | "is-arguments": "^1.0.4", 1380 | "is-date-object": "^1.0.2", 1381 | "is-regex": "^1.1.1", 1382 | "isarray": "^2.0.5", 1383 | "object-is": "^1.1.4", 1384 | "object-keys": "^1.1.1", 1385 | "object.assign": "^4.1.2", 1386 | "regexp.prototype.flags": "^1.3.0", 1387 | "side-channel": "^1.0.3", 1388 | "which-boxed-primitive": "^1.0.1", 1389 | "which-collection": "^1.0.1", 1390 | "which-typed-array": "^1.1.2" 1391 | } 1392 | }, 1393 | "define-properties": { 1394 | "version": "1.1.4", 1395 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 1396 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 1397 | "dev": true, 1398 | "requires": { 1399 | "has-property-descriptors": "^1.0.0", 1400 | "object-keys": "^1.1.1" 1401 | } 1402 | }, 1403 | "defined": { 1404 | "version": "1.0.0", 1405 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 1406 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 1407 | "dev": true 1408 | }, 1409 | "dotignore": { 1410 | "version": "0.1.2", 1411 | "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", 1412 | "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", 1413 | "dev": true, 1414 | "requires": { 1415 | "minimatch": "^3.0.4" 1416 | } 1417 | }, 1418 | "duplexify": { 1419 | "version": "4.1.2", 1420 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", 1421 | "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", 1422 | "requires": { 1423 | "end-of-stream": "^1.4.1", 1424 | "inherits": "^2.0.3", 1425 | "readable-stream": "^3.1.1", 1426 | "stream-shift": "^1.0.0" 1427 | }, 1428 | "dependencies": { 1429 | "readable-stream": { 1430 | "version": "3.6.0", 1431 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 1432 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 1433 | "requires": { 1434 | "inherits": "^2.0.3", 1435 | "string_decoder": "^1.1.1", 1436 | "util-deprecate": "^1.0.1" 1437 | } 1438 | } 1439 | } 1440 | }, 1441 | "end-of-stream": { 1442 | "version": "1.4.1", 1443 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", 1444 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", 1445 | "requires": { 1446 | "once": "^1.4.0" 1447 | } 1448 | }, 1449 | "es-abstract": { 1450 | "version": "1.20.3", 1451 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", 1452 | "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", 1453 | "dev": true, 1454 | "requires": { 1455 | "call-bind": "^1.0.2", 1456 | "es-to-primitive": "^1.2.1", 1457 | "function-bind": "^1.1.1", 1458 | "function.prototype.name": "^1.1.5", 1459 | "get-intrinsic": "^1.1.3", 1460 | "get-symbol-description": "^1.0.0", 1461 | "has": "^1.0.3", 1462 | "has-property-descriptors": "^1.0.0", 1463 | "has-symbols": "^1.0.3", 1464 | "internal-slot": "^1.0.3", 1465 | "is-callable": "^1.2.6", 1466 | "is-negative-zero": "^2.0.2", 1467 | "is-regex": "^1.1.4", 1468 | "is-shared-array-buffer": "^1.0.2", 1469 | "is-string": "^1.0.7", 1470 | "is-weakref": "^1.0.2", 1471 | "object-inspect": "^1.12.2", 1472 | "object-keys": "^1.1.1", 1473 | "object.assign": "^4.1.4", 1474 | "regexp.prototype.flags": "^1.4.3", 1475 | "safe-regex-test": "^1.0.0", 1476 | "string.prototype.trimend": "^1.0.5", 1477 | "string.prototype.trimstart": "^1.0.5", 1478 | "unbox-primitive": "^1.0.2" 1479 | } 1480 | }, 1481 | "es-get-iterator": { 1482 | "version": "1.1.2", 1483 | "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", 1484 | "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", 1485 | "dev": true, 1486 | "requires": { 1487 | "call-bind": "^1.0.2", 1488 | "get-intrinsic": "^1.1.0", 1489 | "has-symbols": "^1.0.1", 1490 | "is-arguments": "^1.1.0", 1491 | "is-map": "^2.0.2", 1492 | "is-set": "^2.0.2", 1493 | "is-string": "^1.0.5", 1494 | "isarray": "^2.0.5" 1495 | } 1496 | }, 1497 | "es-to-primitive": { 1498 | "version": "1.2.1", 1499 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 1500 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 1501 | "dev": true, 1502 | "requires": { 1503 | "is-callable": "^1.1.4", 1504 | "is-date-object": "^1.0.1", 1505 | "is-symbol": "^1.0.2" 1506 | } 1507 | }, 1508 | "event-target-shim": { 1509 | "version": "5.0.1", 1510 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 1511 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" 1512 | }, 1513 | "events": { 1514 | "version": "3.3.0", 1515 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 1516 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" 1517 | }, 1518 | "for-each": { 1519 | "version": "0.3.3", 1520 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 1521 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 1522 | "dev": true, 1523 | "requires": { 1524 | "is-callable": "^1.1.3" 1525 | } 1526 | }, 1527 | "fs.realpath": { 1528 | "version": "1.0.0", 1529 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1530 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1531 | "dev": true 1532 | }, 1533 | "function-bind": { 1534 | "version": "1.1.1", 1535 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1536 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1537 | "dev": true 1538 | }, 1539 | "function.prototype.name": { 1540 | "version": "1.1.5", 1541 | "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", 1542 | "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", 1543 | "dev": true, 1544 | "requires": { 1545 | "call-bind": "^1.0.2", 1546 | "define-properties": "^1.1.3", 1547 | "es-abstract": "^1.19.0", 1548 | "functions-have-names": "^1.2.2" 1549 | } 1550 | }, 1551 | "functions-have-names": { 1552 | "version": "1.2.3", 1553 | "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", 1554 | "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", 1555 | "dev": true 1556 | }, 1557 | "get-intrinsic": { 1558 | "version": "1.1.3", 1559 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 1560 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 1561 | "dev": true, 1562 | "requires": { 1563 | "function-bind": "^1.1.1", 1564 | "has": "^1.0.3", 1565 | "has-symbols": "^1.0.3" 1566 | } 1567 | }, 1568 | "get-package-type": { 1569 | "version": "0.1.0", 1570 | "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", 1571 | "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", 1572 | "dev": true 1573 | }, 1574 | "get-symbol-description": { 1575 | "version": "1.0.0", 1576 | "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", 1577 | "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", 1578 | "dev": true, 1579 | "requires": { 1580 | "call-bind": "^1.0.2", 1581 | "get-intrinsic": "^1.1.1" 1582 | } 1583 | }, 1584 | "glob": { 1585 | "version": "7.2.3", 1586 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1587 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1588 | "dev": true, 1589 | "requires": { 1590 | "fs.realpath": "^1.0.0", 1591 | "inflight": "^1.0.4", 1592 | "inherits": "2", 1593 | "minimatch": "^3.1.1", 1594 | "once": "^1.3.0", 1595 | "path-is-absolute": "^1.0.0" 1596 | } 1597 | }, 1598 | "has": { 1599 | "version": "1.0.3", 1600 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1601 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1602 | "dev": true, 1603 | "requires": { 1604 | "function-bind": "^1.1.1" 1605 | } 1606 | }, 1607 | "has-bigints": { 1608 | "version": "1.0.2", 1609 | "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", 1610 | "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", 1611 | "dev": true 1612 | }, 1613 | "has-dynamic-import": { 1614 | "version": "2.0.1", 1615 | "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz", 1616 | "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==", 1617 | "dev": true, 1618 | "requires": { 1619 | "call-bind": "^1.0.2", 1620 | "get-intrinsic": "^1.1.1" 1621 | } 1622 | }, 1623 | "has-property-descriptors": { 1624 | "version": "1.0.0", 1625 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 1626 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 1627 | "dev": true, 1628 | "requires": { 1629 | "get-intrinsic": "^1.1.1" 1630 | } 1631 | }, 1632 | "has-symbols": { 1633 | "version": "1.0.3", 1634 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1635 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 1636 | "dev": true 1637 | }, 1638 | "has-tostringtag": { 1639 | "version": "1.0.0", 1640 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", 1641 | "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", 1642 | "dev": true, 1643 | "requires": { 1644 | "has-symbols": "^1.0.2" 1645 | } 1646 | }, 1647 | "ieee754": { 1648 | "version": "1.2.1", 1649 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1650 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 1651 | }, 1652 | "inflight": { 1653 | "version": "1.0.6", 1654 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1655 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1656 | "dev": true, 1657 | "requires": { 1658 | "once": "^1.3.0", 1659 | "wrappy": "1" 1660 | } 1661 | }, 1662 | "inherits": { 1663 | "version": "2.0.4", 1664 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1665 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1666 | }, 1667 | "internal-slot": { 1668 | "version": "1.0.3", 1669 | "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", 1670 | "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", 1671 | "dev": true, 1672 | "requires": { 1673 | "get-intrinsic": "^1.1.0", 1674 | "has": "^1.0.3", 1675 | "side-channel": "^1.0.4" 1676 | } 1677 | }, 1678 | "is-arguments": { 1679 | "version": "1.1.1", 1680 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", 1681 | "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", 1682 | "dev": true, 1683 | "requires": { 1684 | "call-bind": "^1.0.2", 1685 | "has-tostringtag": "^1.0.0" 1686 | } 1687 | }, 1688 | "is-bigint": { 1689 | "version": "1.0.4", 1690 | "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", 1691 | "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", 1692 | "dev": true, 1693 | "requires": { 1694 | "has-bigints": "^1.0.1" 1695 | } 1696 | }, 1697 | "is-boolean-object": { 1698 | "version": "1.1.2", 1699 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", 1700 | "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", 1701 | "dev": true, 1702 | "requires": { 1703 | "call-bind": "^1.0.2", 1704 | "has-tostringtag": "^1.0.0" 1705 | } 1706 | }, 1707 | "is-callable": { 1708 | "version": "1.2.7", 1709 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", 1710 | "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", 1711 | "dev": true 1712 | }, 1713 | "is-core-module": { 1714 | "version": "2.10.0", 1715 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", 1716 | "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", 1717 | "dev": true, 1718 | "requires": { 1719 | "has": "^1.0.3" 1720 | } 1721 | }, 1722 | "is-date-object": { 1723 | "version": "1.0.5", 1724 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", 1725 | "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", 1726 | "dev": true, 1727 | "requires": { 1728 | "has-tostringtag": "^1.0.0" 1729 | } 1730 | }, 1731 | "is-map": { 1732 | "version": "2.0.2", 1733 | "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", 1734 | "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", 1735 | "dev": true 1736 | }, 1737 | "is-negative-zero": { 1738 | "version": "2.0.2", 1739 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", 1740 | "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", 1741 | "dev": true 1742 | }, 1743 | "is-number-object": { 1744 | "version": "1.0.7", 1745 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", 1746 | "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", 1747 | "dev": true, 1748 | "requires": { 1749 | "has-tostringtag": "^1.0.0" 1750 | } 1751 | }, 1752 | "is-regex": { 1753 | "version": "1.1.4", 1754 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", 1755 | "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", 1756 | "dev": true, 1757 | "requires": { 1758 | "call-bind": "^1.0.2", 1759 | "has-tostringtag": "^1.0.0" 1760 | } 1761 | }, 1762 | "is-set": { 1763 | "version": "2.0.2", 1764 | "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", 1765 | "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", 1766 | "dev": true 1767 | }, 1768 | "is-shared-array-buffer": { 1769 | "version": "1.0.2", 1770 | "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", 1771 | "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", 1772 | "dev": true, 1773 | "requires": { 1774 | "call-bind": "^1.0.2" 1775 | } 1776 | }, 1777 | "is-string": { 1778 | "version": "1.0.7", 1779 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", 1780 | "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", 1781 | "dev": true, 1782 | "requires": { 1783 | "has-tostringtag": "^1.0.0" 1784 | } 1785 | }, 1786 | "is-symbol": { 1787 | "version": "1.0.4", 1788 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", 1789 | "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", 1790 | "dev": true, 1791 | "requires": { 1792 | "has-symbols": "^1.0.2" 1793 | } 1794 | }, 1795 | "is-typed-array": { 1796 | "version": "1.1.9", 1797 | "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", 1798 | "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", 1799 | "dev": true, 1800 | "requires": { 1801 | "available-typed-arrays": "^1.0.5", 1802 | "call-bind": "^1.0.2", 1803 | "es-abstract": "^1.20.0", 1804 | "for-each": "^0.3.3", 1805 | "has-tostringtag": "^1.0.0" 1806 | } 1807 | }, 1808 | "is-weakmap": { 1809 | "version": "2.0.1", 1810 | "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", 1811 | "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", 1812 | "dev": true 1813 | }, 1814 | "is-weakref": { 1815 | "version": "1.0.2", 1816 | "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", 1817 | "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", 1818 | "dev": true, 1819 | "requires": { 1820 | "call-bind": "^1.0.2" 1821 | } 1822 | }, 1823 | "is-weakset": { 1824 | "version": "2.0.2", 1825 | "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", 1826 | "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", 1827 | "dev": true, 1828 | "requires": { 1829 | "call-bind": "^1.0.2", 1830 | "get-intrinsic": "^1.1.1" 1831 | } 1832 | }, 1833 | "isarray": { 1834 | "version": "2.0.5", 1835 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", 1836 | "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", 1837 | "dev": true 1838 | }, 1839 | "jsonparse": { 1840 | "version": "1.0.0", 1841 | "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz", 1842 | "integrity": "sha1-JiL05mwI4arH7b63YFPJt+EhH3Y=" 1843 | }, 1844 | "jsonstream3": { 1845 | "version": "3.0.0", 1846 | "resolved": "https://registry.npmjs.org/jsonstream3/-/jsonstream3-3.0.0.tgz", 1847 | "integrity": "sha1-hW6jECnE1Azx3m3Zkob1nIYYWDM=", 1848 | "requires": { 1849 | "inherits": "^2.0.1", 1850 | "jsonparse": "~1.0.0", 1851 | "readable-stream": "^2.0.2" 1852 | }, 1853 | "dependencies": { 1854 | "isarray": { 1855 | "version": "1.0.0", 1856 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1857 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" 1858 | }, 1859 | "readable-stream": { 1860 | "version": "2.3.7", 1861 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1862 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1863 | "requires": { 1864 | "core-util-is": "~1.0.0", 1865 | "inherits": "~2.0.3", 1866 | "isarray": "~1.0.0", 1867 | "process-nextick-args": "~2.0.0", 1868 | "safe-buffer": "~5.1.1", 1869 | "string_decoder": "~1.1.1", 1870 | "util-deprecate": "~1.0.1" 1871 | } 1872 | }, 1873 | "safe-buffer": { 1874 | "version": "5.1.2", 1875 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1876 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1877 | }, 1878 | "string_decoder": { 1879 | "version": "1.1.1", 1880 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1881 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1882 | "requires": { 1883 | "safe-buffer": "~5.1.0" 1884 | } 1885 | } 1886 | } 1887 | }, 1888 | "minimatch": { 1889 | "version": "3.1.2", 1890 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1891 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1892 | "dev": true, 1893 | "requires": { 1894 | "brace-expansion": "^1.1.7" 1895 | } 1896 | }, 1897 | "minimist": { 1898 | "version": "1.2.6", 1899 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 1900 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 1901 | "dev": true 1902 | }, 1903 | "ms": { 1904 | "version": "2.0.0", 1905 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1906 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1907 | }, 1908 | "object-inspect": { 1909 | "version": "1.12.2", 1910 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 1911 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 1912 | "dev": true 1913 | }, 1914 | "object-is": { 1915 | "version": "1.1.5", 1916 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", 1917 | "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", 1918 | "dev": true, 1919 | "requires": { 1920 | "call-bind": "^1.0.2", 1921 | "define-properties": "^1.1.3" 1922 | } 1923 | }, 1924 | "object-keys": { 1925 | "version": "1.1.1", 1926 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1927 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 1928 | "dev": true 1929 | }, 1930 | "object.assign": { 1931 | "version": "4.1.4", 1932 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", 1933 | "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", 1934 | "dev": true, 1935 | "requires": { 1936 | "call-bind": "^1.0.2", 1937 | "define-properties": "^1.1.4", 1938 | "has-symbols": "^1.0.3", 1939 | "object-keys": "^1.1.1" 1940 | } 1941 | }, 1942 | "once": { 1943 | "version": "1.4.0", 1944 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1945 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1946 | "requires": { 1947 | "wrappy": "1" 1948 | } 1949 | }, 1950 | "path-is-absolute": { 1951 | "version": "1.0.1", 1952 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1953 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1954 | "dev": true 1955 | }, 1956 | "path-parse": { 1957 | "version": "1.0.7", 1958 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1959 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1960 | "dev": true 1961 | }, 1962 | "process": { 1963 | "version": "0.11.10", 1964 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 1965 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" 1966 | }, 1967 | "process-nextick-args": { 1968 | "version": "2.0.1", 1969 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1970 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 1971 | }, 1972 | "querystringparser": { 1973 | "version": "0.1.1", 1974 | "resolved": "https://registry.npmjs.org/querystringparser/-/querystringparser-0.1.1.tgz", 1975 | "integrity": "sha1-nl9OoURkHbpjjZ23GGnSZ1J9w4A=" 1976 | }, 1977 | "readable-stream": { 1978 | "version": "4.2.0", 1979 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", 1980 | "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", 1981 | "requires": { 1982 | "abort-controller": "^3.0.0", 1983 | "buffer": "^6.0.3", 1984 | "events": "^3.3.0", 1985 | "process": "^0.11.10" 1986 | } 1987 | }, 1988 | "regexp.prototype.flags": { 1989 | "version": "1.4.3", 1990 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", 1991 | "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", 1992 | "dev": true, 1993 | "requires": { 1994 | "call-bind": "^1.0.2", 1995 | "define-properties": "^1.1.3", 1996 | "functions-have-names": "^1.2.2" 1997 | } 1998 | }, 1999 | "resolve": { 2000 | "version": "2.0.0-next.4", 2001 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", 2002 | "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", 2003 | "dev": true, 2004 | "requires": { 2005 | "is-core-module": "^2.9.0", 2006 | "path-parse": "^1.0.7", 2007 | "supports-preserve-symlinks-flag": "^1.0.0" 2008 | } 2009 | }, 2010 | "resumer": { 2011 | "version": "0.0.0", 2012 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 2013 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 2014 | "dev": true, 2015 | "requires": { 2016 | "through": "~2.3.4" 2017 | } 2018 | }, 2019 | "safe-buffer": { 2020 | "version": "5.2.1", 2021 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2022 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 2023 | }, 2024 | "safe-regex-test": { 2025 | "version": "1.0.0", 2026 | "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", 2027 | "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", 2028 | "dev": true, 2029 | "requires": { 2030 | "call-bind": "^1.0.2", 2031 | "get-intrinsic": "^1.1.3", 2032 | "is-regex": "^1.1.4" 2033 | } 2034 | }, 2035 | "side-channel": { 2036 | "version": "1.0.4", 2037 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 2038 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 2039 | "dev": true, 2040 | "requires": { 2041 | "call-bind": "^1.0.0", 2042 | "get-intrinsic": "^1.0.2", 2043 | "object-inspect": "^1.9.0" 2044 | } 2045 | }, 2046 | "stream-shift": { 2047 | "version": "1.0.0", 2048 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", 2049 | "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" 2050 | }, 2051 | "string_decoder": { 2052 | "version": "1.3.0", 2053 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 2054 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 2055 | "requires": { 2056 | "safe-buffer": "~5.2.0" 2057 | } 2058 | }, 2059 | "string.prototype.trim": { 2060 | "version": "1.2.6", 2061 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.6.tgz", 2062 | "integrity": "sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ==", 2063 | "dev": true, 2064 | "requires": { 2065 | "call-bind": "^1.0.2", 2066 | "define-properties": "^1.1.4", 2067 | "es-abstract": "^1.19.5" 2068 | } 2069 | }, 2070 | "string.prototype.trimend": { 2071 | "version": "1.0.5", 2072 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", 2073 | "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", 2074 | "dev": true, 2075 | "requires": { 2076 | "call-bind": "^1.0.2", 2077 | "define-properties": "^1.1.4", 2078 | "es-abstract": "^1.19.5" 2079 | } 2080 | }, 2081 | "string.prototype.trimstart": { 2082 | "version": "1.0.5", 2083 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", 2084 | "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", 2085 | "dev": true, 2086 | "requires": { 2087 | "call-bind": "^1.0.2", 2088 | "define-properties": "^1.1.4", 2089 | "es-abstract": "^1.19.5" 2090 | } 2091 | }, 2092 | "supports-preserve-symlinks-flag": { 2093 | "version": "1.0.0", 2094 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 2095 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 2096 | "dev": true 2097 | }, 2098 | "tape": { 2099 | "version": "5.6.1", 2100 | "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.1.tgz", 2101 | "integrity": "sha512-reNzS3rzsJtKk0f+zJx2XlzIsjJXlIcOIrIxk5shHAG/DzW3BKyMg8UfN79oluYlcWo4lIt56ahLqwgpRT4idg==", 2102 | "dev": true, 2103 | "requires": { 2104 | "array.prototype.every": "^1.1.3", 2105 | "call-bind": "^1.0.2", 2106 | "deep-equal": "^2.0.5", 2107 | "defined": "^1.0.0", 2108 | "dotignore": "^0.1.2", 2109 | "for-each": "^0.3.3", 2110 | "get-package-type": "^0.1.0", 2111 | "glob": "^7.2.3", 2112 | "has": "^1.0.3", 2113 | "has-dynamic-import": "^2.0.1", 2114 | "inherits": "^2.0.4", 2115 | "is-regex": "^1.1.4", 2116 | "minimist": "^1.2.6", 2117 | "object-inspect": "^1.12.2", 2118 | "object-is": "^1.1.5", 2119 | "object-keys": "^1.1.1", 2120 | "object.assign": "^4.1.4", 2121 | "resolve": "^2.0.0-next.3", 2122 | "resumer": "^0.0.0", 2123 | "string.prototype.trim": "^1.2.6", 2124 | "through": "^2.3.8" 2125 | } 2126 | }, 2127 | "through": { 2128 | "version": "2.3.8", 2129 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 2130 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 2131 | "dev": true 2132 | }, 2133 | "unbox-primitive": { 2134 | "version": "1.0.2", 2135 | "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", 2136 | "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", 2137 | "dev": true, 2138 | "requires": { 2139 | "call-bind": "^1.0.2", 2140 | "has-bigints": "^1.0.2", 2141 | "has-symbols": "^1.0.3", 2142 | "which-boxed-primitive": "^1.0.2" 2143 | } 2144 | }, 2145 | "util-deprecate": { 2146 | "version": "1.0.2", 2147 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2148 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 2149 | }, 2150 | "which-boxed-primitive": { 2151 | "version": "1.0.2", 2152 | "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", 2153 | "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", 2154 | "dev": true, 2155 | "requires": { 2156 | "is-bigint": "^1.0.1", 2157 | "is-boolean-object": "^1.1.0", 2158 | "is-number-object": "^1.0.4", 2159 | "is-string": "^1.0.5", 2160 | "is-symbol": "^1.0.3" 2161 | } 2162 | }, 2163 | "which-collection": { 2164 | "version": "1.0.1", 2165 | "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", 2166 | "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", 2167 | "dev": true, 2168 | "requires": { 2169 | "is-map": "^2.0.1", 2170 | "is-set": "^2.0.1", 2171 | "is-weakmap": "^2.0.1", 2172 | "is-weakset": "^2.0.1" 2173 | } 2174 | }, 2175 | "which-typed-array": { 2176 | "version": "1.1.8", 2177 | "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", 2178 | "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", 2179 | "dev": true, 2180 | "requires": { 2181 | "available-typed-arrays": "^1.0.5", 2182 | "call-bind": "^1.0.2", 2183 | "es-abstract": "^1.20.0", 2184 | "for-each": "^0.3.3", 2185 | "has-tostringtag": "^1.0.0", 2186 | "is-typed-array": "^1.1.9" 2187 | } 2188 | }, 2189 | "wrappy": { 2190 | "version": "1.0.2", 2191 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2192 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 2193 | } 2194 | } 2195 | } 2196 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cartodb-tools", 3 | "version": "2.11.1", 4 | "description": "knex based sql library for cartodb", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bluebird": "^2.9.25", 13 | "debug": "^2.2.0", 14 | "duplexify": "^4.1.2", 15 | "inherits": "^2.0.1", 16 | "jsonstream3": "^3.0.0", 17 | "querystringparser": "^0.1.1", 18 | "readable-stream": "^4.2.0" 19 | }, 20 | "devDependencies": { 21 | "tape": "^5.6.1" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git@github.com:AppGeo/cartodb.git" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | cartodb tools 2 | === 3 | 4 | ```bash 5 | npm install cartodb-tools --save 6 | ``` 7 | 8 | some tools for working with cartodb, for now works only with api keys. 9 | 10 | API is shamelessly copied from [KNEX](http://knexjs.org/) as is much of the code, 11 | see the documentation over their for details, currently does not support table creation. 12 | 13 | One difference is that geojson geometries are treated as such and converted to 14 | geometries appropriate to the `the_geom` field in cartodb. 15 | 16 | 17 | ```js 18 | var cartodb = require('cartodb-tools')('username', 'api-key'); 19 | 20 | cartodb('myTable') 21 | .select('foo') 22 | .where('bar', 'baz') 23 | .then(function (resp) { 24 | //use resp 25 | }) 26 | .catch(function (err) { 27 | // something bad happened 28 | }); 29 | ``` 30 | 31 | Write Stream 32 | 33 | 34 | ```js 35 | var cartodb = require('cartodb-tools')('username', 'api-key') 36 | cartodb.createWriteStream('table_name', opts); 37 | // available options are `create` to create a new table 38 | ``` 39 | 40 | the query object has a few cartodb specific methods 41 | 42 | 43 | # batch 44 | 45 | the batch method will use the [carto batch api](https://carto.com/docs/carto-engine/sql-api/batch-queries/) method for doing the query, since this will never return results don't use it for selects, though you can if you want it's just kinda pointless 46 | 47 | ```js 48 | cartodb('myTable') 49 | .update({ 50 | foo: 'bar' 51 | }) 52 | .where('bar', 'baz') 53 | .batch() 54 | .then(function (resp) { 55 | //use resp 56 | }) 57 | ``` 58 | 59 | you can also use the .onSuccess or .onError method to run those queries if the first one failed or succeeded 60 | 61 | ```js 62 | cartodb('myTable') 63 | .update({ 64 | foo: 'bar' 65 | }) 66 | .where('fake collumn', 'baz') 67 | .batch() 68 | .onSuccess(cartodb('errors_log').insert({ 69 | error_message: 'NONE!', 70 | date: cartodb.raw('CURRENT_TIMESTAMP') 71 | })) 72 | .onError('INSERT INTO errors_log (job_id, error_message, date) VALUES (\'<%= job_id %>\', \'<%= error_message %>\', NOW())') 73 | .then(function (resp) { 74 | //use resp 75 | }) 76 | ``` 77 | 78 | By default raw queries are wrapped in a transaction, use `.noTransaction()` to avoid this, useful for queries that can't be in transactions 79 | 80 | ```js 81 | cartodb.raw('VACUUM ANALYZE').noTransaction().batch().then(function () { 82 | console.log('yay!'); 83 | }).catch(function () { 84 | console.log('no!'); 85 | }); 86 | ``` 87 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var config = require('./test.config.json'); 5 | var cartodb = require('./')(config.username, config.apikey); 6 | var TABLE_NAME = 'test_table'; 7 | test('basic', function (t) { 8 | t.test('clear', function (t) { 9 | t.plan(1); 10 | cartodb(TABLE_NAME).delete() 11 | .exec(function (err) { 12 | t.error(err); 13 | console.log('err', err && err.toString()); 14 | }); 15 | }); 16 | t.test('clear check', function (t) { 17 | t.plan(2); 18 | cartodb(TABLE_NAME).count() 19 | .exec(function (err, resp) { 20 | t.error(err); 21 | t.deepEquals([{count: 0}], resp); 22 | }); 23 | }); 24 | t.test('insert', function (t) { 25 | t.plan(1); 26 | cartodb.insert([ 27 | { 28 | ammount: 1, 29 | description: 'one', 30 | ifso: true 31 | }, 32 | { 33 | ammount: 2, 34 | description: 'two', 35 | ifso: false, 36 | name: 'even' 37 | }, 38 | { 39 | ammount: 3, 40 | description: 'three', 41 | ifso: true, 42 | updated_at2: new Date() 43 | }, 44 | { 45 | description: 'try to use $cartodb$ to escape', 46 | ifso: false, 47 | the_geom: {"type":"Point","coordinates":[-98.19805569,29.49655938]} 48 | } 49 | ]).into(TABLE_NAME).exec(function (err) { 50 | t.error(err, err && err.stack); 51 | }); 52 | }); 53 | t.test('insert check', function (t) { 54 | t.plan(2); 55 | cartodb.from(TABLE_NAME).count() 56 | .exec(function (err, resp) { 57 | t.error(err); 58 | t.deepEquals([{count: 4}], resp); 59 | }); 60 | }); 61 | t.test('select 1', function (t) { 62 | t.plan(1); 63 | cartodb.select('ammount').from(TABLE_NAME).where('ifso', true).then(function (resp) { 64 | if (!resp) { 65 | return t.ok(resp); 66 | } 67 | t.deepEquals(resp.sort(function (a, b) { 68 | return a.ammount - b.ammount; 69 | }), [ { ammount: 1 }, { ammount: 3 } ]); 70 | }).catch(function () { 71 | t.notOk(true); 72 | }); 73 | }); 74 | t.test('select 1 semi raw 1', function (t) { 75 | t.plan(1); 76 | cartodb.select('ammount').from(TABLE_NAME).whereRaw('??= ?', ['ifso', true]).then(function (resp) { 77 | if (!resp) { 78 | return t.ok(resp); 79 | } 80 | t.deepEquals(resp.sort(function (a, b) { 81 | return a.ammount - b.ammount; 82 | }), [ { ammount: 1 }, { ammount: 3 } ]); 83 | }).catch(function (e) { 84 | t.error(e); 85 | }); 86 | }); 87 | t.test('select 1 semi raw 2', function (t) { 88 | t.plan(1); 89 | cartodb.select('ammount').from(TABLE_NAME).whereRaw(':key: = :val', {key: 'ifso', val: true}).then(function (resp) { 90 | if (!resp) { 91 | return t.ok(resp); 92 | } 93 | t.deepEquals(resp.sort(function (a, b) { 94 | return a.ammount - b.ammount; 95 | }), [ { ammount: 1 }, { ammount: 3 } ]); 96 | }).catch(function (e) { 97 | t.error(e); 98 | }); 99 | }); 100 | t.test('select 1 raw', function (t) { 101 | t.plan(1); 102 | cartodb.raw('select ammount from test_table where ifso = true').then(function (resp) { 103 | if (!resp) { 104 | return t.ok(resp); 105 | } 106 | t.deepEquals(resp.sort(function (a, b) { 107 | return a.ammount - b.ammount; 108 | }), [ { ammount: 1 }, { ammount: 3 } ]); 109 | }).catch(function (e) { 110 | t.notOk(true, e); 111 | }); 112 | }); 113 | t.test('select 1 rawer', function (t) { 114 | t.plan(1); 115 | cartodb.raw('select ?? from ?? where ?? = ?', ['ammount', TABLE_NAME, 'ifso', true]).then(function (resp) { 116 | if (!resp) { 117 | return t.ok(resp); 118 | } 119 | t.deepEquals(resp.sort(function (a, b) { 120 | return a.ammount - b.ammount; 121 | }), [ { ammount: 1 }, { ammount: 3 } ]); 122 | }).catch(function (e) { 123 | t.notOk(true, e); 124 | }); 125 | }); 126 | t.test('select 1 rawest', function (t) { 127 | t.plan(1); 128 | cartodb.raw('select :field: from :table: where :col: = :val', { 129 | field: 'ammount', table: TABLE_NAME, col: 'ifso', val: true 130 | }).then(function (resp) { 131 | if (!resp) { 132 | return t.ok(resp); 133 | } 134 | t.deepEquals(resp.sort(function (a, b) { 135 | return a.ammount - b.ammount; 136 | }), [ { ammount: 1 }, { ammount: 3 } ]); 137 | }).catch(function (e) { 138 | t.notOk(true, e); 139 | }); 140 | }); 141 | t.test('select 2', function (t) { 142 | t.plan(1); 143 | cartodb.select('ammount').from(TABLE_NAME).where('updated_at2', '<', new Date()).then(function (resp) { 144 | if (!resp) { 145 | return t.ok(resp); 146 | } 147 | t.deepEquals(resp, [ { ammount: 3 } ]); 148 | }).catch(function () { 149 | t.notOk(true); 150 | }); 151 | }); 152 | t.test('update', function (t) { 153 | t.plan(1); 154 | cartodb(TABLE_NAME).update({ 155 | ifso: true 156 | }).where('name', 'even').exec(function (err) { 157 | t.error(err, err && err.stack); 158 | }); 159 | }); 160 | t.test('update 2', function (t) { 161 | t.plan(1); 162 | cartodb(TABLE_NAME).update({ 163 | the_geom: {"type":"MultiPoint","coordinates":[[-98.19805569,29.49655938],[-97,28]]} 164 | }).where({the_geom: {"type":"Point","coordinates":[-98.19805569,29.49655938]}}).exec(function (err) { 165 | t.error(err, err && err.stack); 166 | }); 167 | }); 168 | t.test('select 2', function (t) { 169 | t.plan(2); 170 | cartodb.select('ammount').from(TABLE_NAME).where('ifso', true).exec(function (err, resp) { 171 | t.error(err, err && err.stack); 172 | if (!resp) { 173 | return t.ok(resp); 174 | } 175 | t.deepEquals(resp.sort(function (a, b) { 176 | return a.ammount - b.ammount; 177 | }), [ { ammount: 1 }, { ammount: 2 }, { ammount: 3 } ]); 178 | }); 179 | }); 180 | t.test('check version', function (t) { 181 | t.plan(1); 182 | cartodb.raw('select version();').then(function () { 183 | t.ok(true);//, JSON.stringify(resp, false, 2)); 184 | }).catch(function (e) { 185 | t.error(e); 186 | }); 187 | }); 188 | t.test('table info', function (t) { 189 | t.plan(1); 190 | cartodb(cartodb.raw('INFORMATION_SCHEMA.COLUMNS')).select('column_name', 'data_type') 191 | .where({ 192 | table_name: TABLE_NAME 193 | }).then(function (resp) { 194 | t.ok(true, JSON.stringify(resp, false, 2)); 195 | }).catch(function (e) { 196 | t.error(e); 197 | }); 198 | }); 199 | t.test('select 2', function (t) { 200 | t.plan(2); 201 | cartodb.select('ammount').from(TABLE_NAME).whereRaw('ifso = ?', [true]).limit(1).exec(function (err, resp) { 202 | t.error(err, err && err.stack); 203 | if (!resp) { 204 | return t.ok(resp); 205 | } 206 | t.deepEquals(resp.sort(function (a, b) { 207 | return a.ammount - b.ammount; 208 | }), [ { ammount: 1 } ]); 209 | }); 210 | }); 211 | // t.test('create table', function (t) { 212 | // t.plan(1); 213 | // cartodb.schema.createTable('cartodb_tools_test_fin', function (table) { 214 | // table.boolean('bool'); 215 | // table.text('some_text'); 216 | // }).then(function (resp) { 217 | // t.ok(true, JSON.stringify(resp, false, 2)); 218 | // }).catch(function (e) { 219 | // t.error(e); 220 | // }); 221 | // }); 222 | // t.test('created table info', function (t) { 223 | // t.plan(1); 224 | // cartodb(cartodb.raw('INFORMATION_SCHEMA.COLUMNS')).select('column_name', 'data_type') 225 | // .where({ 226 | // table_name: 'cartodb_tools_test_fin' 227 | // }).then(function (resp) { 228 | // t.equals(resp.length, 5); 229 | // }).catch(function (e) { 230 | // t.error(e); 231 | // }); 232 | // }); 233 | t.test('drop table', function (t) { 234 | t.plan(1); 235 | cartodb.schema.dropTableIfExists('cartodb_tools_test_fin').then(function (resp) { 236 | t.ok(true, JSON.stringify(resp, false, 2)); 237 | }).catch(function (e) { 238 | t.error(e); 239 | }); 240 | }); 241 | }); 242 | test('advanced', function (t) { 243 | t.test('control', function (t) { 244 | t.plan(1); 245 | cartodb.raw('select true').then(function (r){ 246 | console.log(r); 247 | t.ok(true, 'works'); 248 | }).catch(function (e) { 249 | t.error(e); 250 | }) 251 | }); 252 | t.test('new way', function (t) { 253 | t.plan(1); 254 | cartodb.raw('select true').batch().then(function (r){ 255 | t.ok(true, 'works'); 256 | }).catch(function (e) { 257 | t.error(e, e.stack); 258 | }) 259 | }); 260 | // t.test('fallback', function (t) { 261 | // t.plan(1); 262 | // cartodb.raw('INSERT INTO errors_log (job_id, error_message, date) VALUES (\'first part!!!!\', \'no error\', NOW())') 263 | // .onSuccess(cartodb.raw('INSERT INTO errors_log (job_id, error_message, date) VALUES (\'success part!!!!\', \'no error\', NOW())')) 264 | // .onError(cartodb.raw('INSERT INTO errors_log (job_id, error_message, date) VALUES (\'<%= job_id %>\', \'<%= error_message %>\', NOW())')).batch().then(function (r){ 265 | // t.ok(true, 'works'); 266 | // }).catch(function (e) { 267 | // t.error(e, e.stack); 268 | // }) 269 | // }); 270 | }) 271 | --------------------------------------------------------------------------------