@technicity/data-service-generator 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ import { IArgs, IOrderBy } from "./types";
2
+ export declare function getOrderBy(args: IArgs | undefined, primaryKey: string): {
3
+ orderBy: IOrderBy | undefined;
4
+ flip: boolean;
5
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOrderBy = void 0;
4
+ // https://gist.github.com/pcattori/2bb645d587e45c9fdbcabf5cef7a7106
5
+ function getOrderBy(args, primaryKey) {
6
+ let out = undefined;
7
+ let flip = false;
8
+ if (Array.isArray(args?.$orderBy)) {
9
+ out = args?.$orderBy.map((x) => {
10
+ const [column, direction] = Object.entries(x)[0];
11
+ return { column, direction };
12
+ });
13
+ }
14
+ else if (typeof args?.$orderBy === "object" && args.$orderBy != null) {
15
+ const [column, direction] = Object.entries(args.$orderBy)[0];
16
+ out = [{ column, direction }];
17
+ }
18
+ if (args?.$paginate?.first != null || args?.$paginate?.last != null) {
19
+ // If paginating and primaryKey is not in orderBy, add it to end.
20
+ // Not necessarily "asc"; see flip.
21
+ if (!out?.find((x) => x.column === primaryKey)) {
22
+ const orderByPrimaryKey = { column: primaryKey, direction: "asc" };
23
+ if (out == null) {
24
+ out = [orderByPrimaryKey];
25
+ }
26
+ else {
27
+ out = out.concat(orderByPrimaryKey);
28
+ }
29
+ }
30
+ flip = getFlip(args, out, primaryKey);
31
+ if (flip) {
32
+ out = flipOrderByDirection(out);
33
+ }
34
+ }
35
+ return { orderBy: out, flip };
36
+ }
37
+ exports.getOrderBy = getOrderBy;
38
+ function getFlip(args, orderBy, primaryKey) {
39
+ if (args?.$paginate?.first != null &&
40
+ orderBy?.find((x) => x.column === primaryKey)?.direction === "desc") {
41
+ return true;
42
+ }
43
+ if (args?.$paginate?.last != null &&
44
+ orderBy?.find((x) => x.column === primaryKey)?.direction === "asc") {
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ function flipOrderByDirection(orderBy) {
50
+ return orderBy.map((x) => ({ ...x, direction: flipDirection(x.direction) }));
51
+ }
52
+ function flipDirection(direction) {
53
+ return direction === "asc" ? "desc" : "asc";
54
+ }
package/dist/getSqlAst.js CHANGED
@@ -7,6 +7,7 @@ const TSqlString = require("tsqlstring");
7
7
  // @ts-ignore
8
8
  const alias_namespace_1 = require("join-monster/dist/alias-namespace");
9
9
  const _ = require("lodash/fp");
10
+ const getOrderBy_1 = require("./getOrderBy");
10
11
  const namespace = new alias_namespace_1.default(true);
11
12
  function getSqlAst(input) {
12
13
  const { table, fieldName, fields, args, grabMany, sqlJoin, sqlBatch, junction, getWhere, artifacts, rowWithCursorId, dialect, } = input;
@@ -15,7 +16,7 @@ function getSqlAst(input) {
15
16
  const format = dialect === "mysql"
16
17
  ? SqlString.format.bind(SqlString)
17
18
  : TSqlString.format.bind(TSqlString);
18
- const orderBy = args?.$orderBy == null ? undefined : getOrderBy(args, primaryKey);
19
+ const orderBy = input.orderBy ?? getOrderBy_1.getOrderBy(args, primaryKey)?.orderBy;
19
20
  let where = input.where;
20
21
  if (input.where == null) {
21
22
  where = (table, args) => {
@@ -24,7 +25,7 @@ function getSqlAst(input) {
24
25
  argsMapped = _.cloneDeep(argsMapped);
25
26
  argsMapped.$where = argsMapped.$where[0];
26
27
  }
27
- const whereResult = getWhere(table, argsMapped, primaryKey, dialect, orderBy, rowWithCursorId);
28
+ const whereResult = getWhere(table, argsMapped, dialect, orderBy, rowWithCursorId);
28
29
  if (whereResult == null) {
29
30
  return undefined;
30
31
  }
@@ -111,7 +112,7 @@ function getSqlAst(input) {
111
112
  }
112
113
  const argsMapped = _.cloneDeep(args);
113
114
  argsMapped.$where = argsMapped.$where[1];
114
- const whereResult = getWhere(table, argsMapped, artifacts[relationField.junctionTable].primaryKey, dialect, orderBy, rowWithCursorId);
115
+ const whereResult = getWhere(table, argsMapped, dialect, orderBy, rowWithCursorId);
115
116
  if (whereResult == null) {
116
117
  return undefined;
117
118
  }
@@ -198,34 +199,3 @@ function columnToASTChild(columnName, namespace, fromOtherTable) {
198
199
  function toClumsyName(keyArr) {
199
200
  return keyArr.map((name) => name.slice(0, 3)).join("#");
200
201
  }
201
- function getOrderBy(args, primaryKey) {
202
- let out = undefined;
203
- if (Array.isArray(args.$orderBy)) {
204
- out = args.$orderBy.map((x) => {
205
- const [column, direction] = Object.entries(x)[0];
206
- return { column, direction };
207
- });
208
- }
209
- else {
210
- const [column, direction] = Object.entries(args.$orderBy)[0];
211
- out = [{ column, direction }];
212
- }
213
- if (args?.$paginate?.first != null) {
214
- out = out
215
- .filter((x) => x.column !== primaryKey)
216
- // id needs to be last
217
- .concat({ column: primaryKey, direction: "asc" });
218
- }
219
- else if (args?.$paginate?.last != null) {
220
- out = out
221
- .filter((x) => x.column !== primaryKey)
222
- // Need to flip if we're paginating backwards.
223
- .map((x) => ({
224
- column: x.column,
225
- direction: x.direction === "asc" ? "desc" : "asc",
226
- }))
227
- // id needs to be last
228
- .concat({ column: primaryKey, direction: "desc" });
229
- }
230
- return out;
231
- }
@@ -1,2 +1,2 @@
1
1
  import type { IOrderBy, IDialect } from "./types";
2
- export declare function getWhere(table: string, args: any, primaryKey: string, dialect: IDialect, orderBy?: IOrderBy | undefined, rowWithCursorId?: any): string | null;
2
+ export declare function getWhere(table: string, args: any, dialect: IDialect, orderBy?: IOrderBy | undefined, rowWithCursorId?: any): string | null;
package/dist/getWhere.js CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getWhere = void 0;
4
4
  const stringifyWhere_1 = require("./stringifyWhere");
5
- function getWhere(table, args, primaryKey, dialect, orderBy, rowWithCursorId) {
5
+ function getWhere(table, args, dialect, orderBy, rowWithCursorId) {
6
6
  if (args?.$where == null && args?.$paginate == null) {
7
7
  return null;
8
8
  }
@@ -13,7 +13,6 @@ function getWhere(table, args, primaryKey, dialect, orderBy, rowWithCursorId) {
13
13
  dialect,
14
14
  args,
15
15
  orderBy,
16
- primaryKey,
17
16
  rowWithCursorId,
18
17
  }) || null);
19
18
  }
@@ -66,7 +66,6 @@ class RuntimeKSQL {
66
66
  return resolved;
67
67
  }
68
68
  else {
69
- const primaryKey = input.artifacts[input.table].primaryKey;
70
69
  const table = input.table;
71
70
  const tableKSQL = getKSQLTablename(input.table);
72
71
  if (input.args?.$where) {
@@ -75,7 +74,7 @@ class RuntimeKSQL {
75
74
  delete input.args.$where[k];
76
75
  }
77
76
  }
78
- const where = getWhere_1.getWhere(tableKSQL, input.args, primaryKey, "mysql");
77
+ const where = getWhere_1.getWhere(tableKSQL, input.args, "mysql");
79
78
  if (!where) {
80
79
  throw new Error("Invalid $where");
81
80
  }
@@ -18,9 +18,11 @@ const runTransforms_1 = require("../runTransforms");
18
18
  const addNullFallbacks_1 = require("../addNullFallbacks");
19
19
  const SDKNotFoundError_1 = require("../SDKNotFoundError");
20
20
  const stringifyWhere_1 = require("../stringifyWhere");
21
+ const getOrderBy_1 = require("../getOrderBy");
21
22
  async function resolve(input, dbCall, formatQuery, options) {
22
23
  const context = {};
23
24
  const kind = input.kind;
25
+ const primaryKey = input.artifacts[input.table].primaryKey;
24
26
  let rowWithCursorId = undefined;
25
27
  if (kind === "listPaginated") {
26
28
  if (input.args?.$paginate == null) {
@@ -31,7 +33,6 @@ async function resolve(input, dbCall, formatQuery, options) {
31
33
  const cursor = input.args.$paginate.after != null
32
34
  ? input.args.$paginate.after
33
35
  : input.args.$paginate.before;
34
- const primaryKey = input.artifacts[input.table].primaryKey;
35
36
  rowWithCursorId = await dbCall(formatQuery("SELECT * FROM ?? WHERE ?? = ?", [
36
37
  input.table,
37
38
  primaryKey,
@@ -42,10 +43,12 @@ async function resolve(input, dbCall, formatQuery, options) {
42
43
  // we need to read the query AST and build a new "SQL AST" from which the SQL and
43
44
  // const sqlAST = queryAST.queryASTToSqlAST(resolveInfo, options, context);
44
45
  const fields = input.fields ?? getScalarFields(input.table, input.artifacts);
46
+ const orderByListPaginatedRootResult = kind === "listPaginated" ? getOrderBy_1.getOrderBy(input.args, primaryKey) : undefined;
45
47
  const sqlAST = getSqlAst_1.getSqlAst({
46
48
  ...input,
47
49
  fields,
48
50
  getWhere: getWhere_1.getWhere,
51
+ orderBy: orderByListPaginatedRootResult?.orderBy,
49
52
  rowWithCursorId,
50
53
  dialect: options.dialect,
51
54
  });
@@ -110,7 +113,7 @@ async function resolve(input, dbCall, formatQuery, options) {
110
113
  // return true;
111
114
  // });
112
115
  if (kind === "listPaginated") {
113
- data = await wrapListPaginated(data, input.args, (xs) => {
116
+ data = await wrapListPaginated(data, input.args, orderByListPaginatedRootResult.flip, (xs) => {
114
117
  postProcess(xs, fields, shouldRemoveExtraKeys);
115
118
  }, sqlAST, dbCall, input.artifacts[input.table].primaryKey, context, options);
116
119
  }
@@ -125,8 +128,7 @@ exports.resolve = resolve;
125
128
  // Not recursive at the moment; only supported at the root.
126
129
  // TODO - remove if support for pagination for mysql dialect
127
130
  // is added (I doubt it)
128
- async function wrapListPaginated(data, args, cb, sqlAST, dbCall, primaryKey, context, options) {
129
- const flip = typeof args.$paginate.first === "number" ? false : true;
131
+ async function wrapListPaginated(data, args, flip, cb, sqlAST, dbCall, primaryKey, context, options) {
130
132
  const limit = flip ? args.$paginate.last : args.$paginate.first;
131
133
  const hasMoreResults = data.length === limit + 1;
132
134
  if (hasMoreResults) {
@@ -138,10 +140,10 @@ async function wrapListPaginated(data, args, cb, sqlAST, dbCall, primaryKey, con
138
140
  }
139
141
  const hasPreviousPage = flip ? hasMoreResults : false;
140
142
  const hasNextPage = flip ? false : hasMoreResults;
141
- const startId = data?.[0]?.[primaryKey];
142
- const endId = data?.[data.length - 1]?.[primaryKey];
143
- const startCursor = startId == null ? null : cursor_1.encodeCursor(startId);
144
- const endCursor = endId == null ? null : cursor_1.encodeCursor(endId);
143
+ const startKey = data?.[0]?.[primaryKey];
144
+ const endKey = data?.[data.length - 1]?.[primaryKey];
145
+ const startCursor = startKey == null ? null : cursor_1.encodeCursor(startKey);
146
+ const endCursor = endKey == null ? null : cursor_1.encodeCursor(endKey);
145
147
  // Replace field selection with `COUNT(*)`
146
148
  const fieldNameTotalCount = "totalCount";
147
149
  const sqlASTTotalCount = { ...sqlAST };
@@ -222,7 +224,7 @@ async function patch(input) {
222
224
  async function _patch() {
223
225
  const { dbCall, formatQuery } = input;
224
226
  const tableArtifacts = input.artifacts[input.table];
225
- const where = getWhere_1.getWhere(input.table, input.args, tableArtifacts.primaryKey, input.dialect);
227
+ const where = getWhere_1.getWhere(input.table, input.args, input.dialect);
226
228
  if (where == null) {
227
229
  throw new Error("Null where");
228
230
  }
@@ -319,7 +321,7 @@ async function patchList(input) {
319
321
  async function _patchList() {
320
322
  const { dbCall, formatQuery } = input;
321
323
  const tableArtifacts = input.artifacts[input.table];
322
- const where = getWhere_1.getWhere(input.table, input.args, tableArtifacts.primaryKey, input.dialect);
324
+ const where = getWhere_1.getWhere(input.table, input.args, input.dialect);
323
325
  if (where == null) {
324
326
  throw new Error("Null where");
325
327
  }
@@ -382,8 +384,7 @@ async function del(input) {
382
384
  exports.del = del;
383
385
  async function deleteList(input) {
384
386
  const { dbCall, formatQuery } = input;
385
- const tableArtifacts = input.artifacts[input.table];
386
- const where = getWhere_1.getWhere(input.table, input.args, tableArtifacts.primaryKey, input.dialect);
387
+ const where = getWhere_1.getWhere(input.table, input.args, input.dialect);
387
388
  if (where == null) {
388
389
  throw new Error("Null where");
389
390
  }
@@ -10,7 +10,6 @@ export declare function stringifyWhere(input: {
10
10
  table: string;
11
11
  dialect: IDialect;
12
12
  args: IArgs;
13
- primaryKey: string;
14
13
  orderBy?: IOrderBy | undefined;
15
14
  rowWithCursorId?: any;
16
15
  }): string;
@@ -5,9 +5,8 @@ const _ = require("lodash/fp");
5
5
  const MySqlString = require("sqlstring");
6
6
  // @ts-ignore
7
7
  const TSqlString = require("tsqlstring");
8
- const cursor_1 = require("./cursor");
9
8
  function stringifyWhere(input) {
10
- const { where, table, dialect, args, primaryKey, orderBy, rowWithCursorId, } = input;
9
+ const { where, table, dialect, args, orderBy, rowWithCursorId } = input;
11
10
  const escapeId = getEscapeId(dialect);
12
11
  const escape = getEscape(dialect);
13
12
  let result = _stringifyWhere(where, table, escapeId, escape, "");
@@ -15,8 +14,6 @@ function stringifyWhere(input) {
15
14
  table,
16
15
  args,
17
16
  orderBy,
18
- primaryKey,
19
- dialect,
20
17
  escapeId,
21
18
  escape,
22
19
  rowWithCursorId,
@@ -162,54 +159,46 @@ function getOperatorNeq(value) {
162
159
  // return { k, v };
163
160
  // }
164
161
  function stringifyPaginationWhere(input) {
165
- const { table, args, orderBy, primaryKey, dialect, escapeId, escape, rowWithCursorId, } = input;
166
- if (args?.$paginate?.after != null || args?.$paginate?.before != null) {
167
- const idDir = args.$paginate.after != null ? "asc" : "desc";
168
- const cursor = args.$paginate.after != null
169
- ? args.$paginate.after
170
- : args.$paginate.before;
171
- const getCompOp = (dir) => (dir === "asc" ? ">" : "<");
172
- if (orderBy == null) {
173
- return `${table}.${escapeId(primaryKey)} ${getCompOp(idDir)} ${cursor_1.decodeCursor(cursor)}`;
162
+ const { table, args, orderBy, escapeId, escape, rowWithCursorId } = input;
163
+ if (args?.$paginate?.after == null && args?.$paginate?.before == null) {
164
+ return "";
165
+ }
166
+ if (rowWithCursorId == null) {
167
+ return "";
168
+ }
169
+ // orderBy should never be null because of getOrderBy, but add a check.
170
+ if (orderBy == null) {
171
+ throw new Error("orderBy cannot be null when paginating");
172
+ }
173
+ function getCompOp(dir) {
174
+ return dir === "asc" ? ">" : "<";
175
+ }
176
+ function printValue(v) {
177
+ if (v === true) {
178
+ v = 1;
174
179
  }
175
- else {
176
- const orders = orderBy
177
- .filter((x) => x.column !== primaryKey)
178
- .concat({ column: primaryKey, direction: "asc" });
179
- function printValue(v) {
180
- if (v === true) {
181
- v = 1;
182
- }
183
- if (v === false) {
184
- v = 0;
185
- }
186
- return escape(v);
187
- }
188
- const cond = orders
189
- .map(({ direction }, i) => {
190
- const a = orders
191
- .slice(0, i + 1)
192
- .map(({ column: col2 }, j, arr) => {
193
- const field = `${table}.${escapeId(col2)}`;
194
- const op = j === arr.length - 1 ? getCompOp(direction) : "=";
195
- let v = rowWithCursorId[col2];
196
- // TODO?
197
- if (dialect === "mssql" && v instanceof Date) {
198
- // Clone, since setMinutes mutates
199
- v = new Date(v.valueOf());
200
- v.setMinutes(v.getMinutes() + new Date().getTimezoneOffset());
201
- }
202
- v = printValue(v);
203
- return `${field} ${op} ${v}`;
204
- })
205
- .join(" AND ");
206
- return "(" + a + ")";
207
- })
208
- .join(" OR ");
209
- return "(" + cond + ")";
180
+ if (v === false) {
181
+ v = 0;
210
182
  }
183
+ return escape(v);
211
184
  }
212
- return "";
185
+ // https://gist.github.com/pcattori/2bb645d587e45c9fdbcabf5cef7a7106
186
+ const cond = orderBy
187
+ .map(({ column, direction }, i) => {
188
+ let a = orderBy.slice(0, i).map(({ column: col2 }) => {
189
+ const field = `${table}.${escapeId(col2)}`;
190
+ const op = "=";
191
+ const v = printValue(rowWithCursorId[col2]);
192
+ return `${field} ${op} ${v}`;
193
+ });
194
+ const field = `${table}.${escapeId(column)}`;
195
+ const op = getCompOp(direction);
196
+ const v = printValue(rowWithCursorId[column]);
197
+ a.push(`${field} ${op} ${v}`);
198
+ return "(" + a.join(" AND ") + ")";
199
+ })
200
+ .join(" OR ");
201
+ return "(" + cond + ")";
213
202
  }
214
203
  function getEscapeId(dialect) {
215
204
  if (dialect === "mysql") {
package/dist/types.d.ts CHANGED
@@ -64,6 +64,7 @@ export declare type IGetSQLASTInput = {
64
64
  junction?: IJunction;
65
65
  grabMany: boolean;
66
66
  getWhere: typeof getWhere;
67
+ orderBy?: IOrderBy | undefined;
67
68
  rowWithCursorId?: any;
68
69
  artifacts: IArtifacts;
69
70
  dialect: IDialect;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technicity/data-service-generator",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "main": "./dist/index.js",
5
5
  "files": [
6
6
  "dist"