-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathquery.js
151 lines (151 loc) · 6.35 KB
/
query.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* This module provides a lazy, functional processing approach to working with NetSuite SuiteQL queries.
* It automatically handles paging behind the scenes allowing the developer to focus on 'per result' business logic.
*
* Use `LazyQuery.from()` to get started.
* Turn query results into plain objects using `nsQueryResult2obj()` and enables you to leverage
* the methods of [ImmutableJS](https://immutable-js.com) to process query results.
* @module
*/
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "N/query", "./EC_Logger"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LazyQuery = void 0;
exports.nsQueryResult2obj = nsQueryResult2obj;
const query = require("N/query");
const LogManager = require("./EC_Logger");
/**
* Rudimentary conversion of a NS query result to a simple flat plain javascript object. Suitable as an argument to `map()`
* @param r the query result to process
* @returns a simple javascript object representation of the query result as type `T`.
*
*
* @typeparam T declares the shape of the plain objects returned. e.g. `nsQueryResult2obj<{ companyname, memo }>` for a query
* that has columns _companyname_ and _memo_. Including an optional type here ensures strong typing on followup chained
* method calls.
*
* @example (using Immutable JS Sequence)
*
* ```typescript
*
* Seq(LazyQuery.from({query:'string'}).map(nsQueryResult2obj()).forEach(...)
*
* ```
*/
function nsQueryResult2obj(r) {
return r.asMap();
}
/**
*
* Makes a NetSuite query an ES2015 style Iterator. That is, it follows the Iterator Protocol for iterating
* over query results in a forward-only fashion. The result can be passed to any library
* that accepts Iterators (such as ImmutableJS)
* to provide easy chainable logic for arbitrary length result sets.
*
* @see LazySearch
*
* @example take the first result of a query as a plain object (ImmutableJS)
* ```typescript
* import {Seq} from './NFT-X.Y.Z/immutable'
* const oneResult = Seq(LazyQuery.from()).map(nsQueryResult2obj()).take(1)
* ```
*/
class LazyQuery {
/**
* Not meant to be used directly, use factory methods such as `load` or `from`
* @param q object of query and parameters
* @param pageSize optional pagesize, can be up to 1000
*/
constructor(q, pageSize = 500) {
if (pageSize > 1000)
throw new Error('page size must be <= 1000');
this.log = LogManager.getLogger(LazyQuery.LOGNAME);
if (!q.params)
this.pagedData = query.runSuiteQLPaged({ query: q.query, pageSize: pageSize });
else
this.pagedData = query.runSuiteQLPaged({ query: q.query, params: q.params, pageSize: pageSize });
this.iterator = this.pagedData.iterator();
// only load a page if we have record
if (this.pagedData.count > 0) {
this.currentPage = this.pagedData.fetch(0);
this.currentData = this.currentPage.data.results;
}
else {
this.currentData = [];
}
this.index = 0;
this.log.info(`lazy query `, `using page size ${this.pagedData.pageSize}, record count ${this.pagedData.count}`);
}
/**
* Creates a lazy query from an existing NS .
* @param q the SQL query and optional query parameters
* @param pageSize optional pagesize, can be up to 1000. Default is 500
* @returns Lazy Seq ready for processing
*
* @example create a query and begin lazy processing of results
*
* ```
* import {Seq} from './NFT-X.Y.Z/immutable'
* import * as query from 'N/query
* import {governanceRemains, LazyQuery, nsQueryResult2obj} from './NFT-X.Y.Z/query'
*
* Seq(LazyQuery.from({
* query: 'SELECT id FROM FOO WHERE name = ?',
* params: ['Farnsworth']
* }))
* .takeWhile(governanceRemains()) // process until we drop below default governance threshold
* .map(nsQueryResult2obj()) // convert query results to plain objects with properties
* .forEach( r => log.debug(r))
* ```
*/
static from(q, pageSize) {
return new LazyQuery(q, pageSize);
}
/**
* LazyQuery is both an iterable and an iterator for query results.
*/
[Symbol.iterator]() {
return this;
}
/**
* per the iterator protocol, retrieves the next element. Also returns `null` if done as the specification for
* the protocol says the value property is optional when 'done'
*
* You don't typically call this function yourself - libraries like ImmutableJS do.
*/
next() {
const atEndOfPage = this.index === this.currentData.length;
const done = !this.currentPage || (this.currentPage.isLast && atEndOfPage);
if (done)
return {
done: true,
value: null
};
// we've reached the end of the current page, read the next page (overwriting current) and start from its beginning
if (atEndOfPage) {
this.currentPage = this.pagedData.fetch(this.currentPage.pageRange.index + 1);
this.currentData = this.currentPage.data.results;
this.mappedData = this.currentPage.data.asMappedResults();
this.index = 0;
}
// return the next result from existing page (which may have been loaded immediately prior above)
return {
done: false,
value: this.currentData[this.index++]
};
}
}
exports.LazyQuery = LazyQuery;
/**
* the name of the custom logger for this component for independent logging control
*/
LazyQuery.LOGNAME = 'lazy';
});