@snowtop/ent 0.1.0-alpha149 → 0.1.0-alpha150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/ent.js CHANGED
@@ -627,17 +627,18 @@ function buildQuery(options) {
627
627
  const fields = options.fields.join(", ");
628
628
  // always start at 1
629
629
  const whereClause = options.clause.clause(1);
630
- let query = `SELECT ${fields} FROM ${options.tableName} WHERE ${whereClause}`;
630
+ const parts = [];
631
+ parts.push(`SELECT ${fields} FROM ${options.tableName} WHERE ${whereClause}`);
631
632
  if (options.groupby) {
632
- query = `${query} GROUP BY ${options.groupby}`;
633
+ parts.push(`GROUP BY ${options.groupby}`);
633
634
  }
634
635
  if (options.orderby) {
635
- query = `${query} ORDER BY ${options.orderby}`;
636
+ parts.push(`ORDER BY ${options.orderby}`);
636
637
  }
637
638
  if (options.limit) {
638
- query = `${query} LIMIT ${options.limit}`;
639
+ parts.push(`LIMIT ${options.limit}`);
639
640
  }
640
- return query;
641
+ return parts.join(" ");
641
642
  }
642
643
  exports.buildQuery = buildQuery;
643
644
  // this is used for queries when we select multiple ids at once
@@ -1,13 +1,14 @@
1
1
  import { Data, EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, Viewer } from "../base";
2
2
  import { Clause } from "../clause";
3
3
  import { BaseEdgeQuery, IDInfo } from "./query";
4
- interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
4
+ export interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
5
5
  loadEntOptions: LoadEntOptions<TDest, TViewer>;
6
6
  clause: Clause;
7
7
  name: string;
8
8
  sortColumn?: string;
9
9
  sortColumnUnique?: boolean;
10
10
  orderByDirection?: "asc" | "desc";
11
+ nullsPlacement?: "first" | "last";
11
12
  disableTransformations?: boolean;
12
13
  }
13
14
  export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<any, TDest, Data> {
@@ -24,4 +25,3 @@ export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer exten
24
25
  dataToID(edge: Data): ID;
25
26
  protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
26
27
  }
27
- export {};
@@ -30,7 +30,11 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
30
30
  if (options.orderByDirection) {
31
31
  sortCol = `${sortCol} ${options.orderByDirection}`;
32
32
  }
33
- super(viewer, sortCol, unique);
33
+ super(viewer, {
34
+ sortCol,
35
+ cursorCol: unique,
36
+ nullsPlacement: options.nullsPlacement,
37
+ });
34
38
  this.viewer = viewer;
35
39
  this.options = options;
36
40
  this.clause = getClause(options);
@@ -29,6 +29,11 @@ export interface PaginationInfo {
29
29
  startCursor: string;
30
30
  endCursor: string;
31
31
  }
32
+ interface EdgeQueryOptions {
33
+ cursorCol: string;
34
+ sortCol: string;
35
+ nullsPlacement?: "first" | "last";
36
+ }
32
37
  export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> implements EdgeQuery<TSource, TDest, TEdge> {
33
38
  viewer: Viewer;
34
39
  private filters;
@@ -42,7 +47,9 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
42
47
  private sortCol;
43
48
  private cursorCol;
44
49
  private defaultDirection?;
50
+ private edgeQueryOptions;
45
51
  constructor(viewer: Viewer, sortCol: string, cursorCol: string);
52
+ constructor(viewer: Viewer, options: EdgeQueryOptions);
46
53
  protected getSortCol(): string;
47
54
  getPrivacyPolicy(): PrivacyPolicy<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>>;
48
55
  abstract sourceEnt(id: ID): Promise<Ent | null>;
@@ -76,3 +83,4 @@ export interface IDInfo {
76
83
  id: ID;
77
84
  invalidated?: boolean;
78
85
  }
86
+ export {};
@@ -99,9 +99,19 @@ class FirstFilter {
99
99
  // we sort by most recent first
100
100
  // so when paging, we fetch afterCursor X
101
101
  const less = orderby === "DESC";
102
+ let nullsPlacement = "";
103
+ if (this.options.nullsPlacement) {
104
+ if (this.options.nullsPlacement === "first") {
105
+ nullsPlacement = " NULLS FIRST";
106
+ }
107
+ else {
108
+ nullsPlacement = " NULLS LAST";
109
+ }
110
+ }
102
111
  if (this.options.cursorCol !== this.sortCol) {
103
112
  // we also sort unique col in same direction since it doesn't matter...
104
- options.orderby = `${this.sortCol} ${orderby}, ${this.options.cursorCol} ${orderby}`;
113
+ // nulls placement only affects sortCol. assumption is cursorCol will not be null and no need for that
114
+ options.orderby = `${this.sortCol} ${orderby}${nullsPlacement}, ${this.options.cursorCol} ${orderby}`;
105
115
  if (this.offset) {
106
116
  const res = this.edgeQuery.getTableName();
107
117
  const tableName = util_1.types.isPromise(res) ? await res : res;
@@ -110,7 +120,7 @@ class FirstFilter {
110
120
  }
111
121
  }
112
122
  else {
113
- options.orderby = `${this.sortCol} ${orderby}`;
123
+ options.orderby = `${this.sortCol}${nullsPlacement} ${orderby}`;
114
124
  if (this.offset) {
115
125
  let clauseFn = less ? clause.Less : clause.Greater;
116
126
  let val = this.options.sortColTime
@@ -205,7 +215,7 @@ class LastFilter {
205
215
  }
206
216
  }
207
217
  class BaseEdgeQuery {
208
- constructor(viewer, sortCol, cursorCol) {
218
+ constructor(viewer, sortColOrOptions, cursorColMaybe) {
209
219
  this.viewer = viewer;
210
220
  this.filters = [];
211
221
  this.edges = new Map();
@@ -262,6 +272,21 @@ class BaseEdgeQuery {
262
272
  await Promise.all(promises);
263
273
  return results;
264
274
  };
275
+ let sortCol;
276
+ let cursorCol;
277
+ if (typeof sortColOrOptions === "string") {
278
+ sortCol = sortColOrOptions;
279
+ cursorCol = cursorColMaybe;
280
+ this.edgeQueryOptions = {
281
+ cursorCol,
282
+ sortCol,
283
+ };
284
+ }
285
+ else {
286
+ sortCol = sortColOrOptions.sortCol;
287
+ cursorCol = sortColOrOptions.cursorCol;
288
+ this.edgeQueryOptions = sortColOrOptions;
289
+ }
265
290
  let m = orderbyRegex.exec(sortCol);
266
291
  if (!m) {
267
292
  throw new Error(`invalid sort column ${sortCol}`);
@@ -294,6 +319,7 @@ class BaseEdgeQuery {
294
319
  sortCol: this.sortCol,
295
320
  cursorCol: this.cursorCol,
296
321
  defaultDirection: this.defaultDirection,
322
+ nullsPlacement: this.edgeQueryOptions.nullsPlacement,
297
323
  query: this,
298
324
  }));
299
325
  return this;
@@ -306,6 +332,7 @@ class BaseEdgeQuery {
306
332
  sortCol: this.sortCol,
307
333
  cursorCol: this.cursorCol,
308
334
  defaultDirection: this.defaultDirection,
335
+ nullsPlacement: this.edgeQueryOptions.nullsPlacement,
309
336
  query: this,
310
337
  }));
311
338
  return this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.1.0-alpha149",
3
+ "version": "0.1.0-alpha150",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -257,7 +257,7 @@ async function createAllEvents(opts) {
257
257
  const input = opts.eventInputs?.[idx];
258
258
  const builder = (0, fake_event_1.getEventBuilder)(user.viewer, getEventInput(user, input));
259
259
  await builder.saveX();
260
- return await builder.editedEntX();
260
+ return builder.editedEntX();
261
261
  }));
262
262
  expect(events.length).toBe(opts.howMany);
263
263
  return [user, events];