unconventional 0.0.3 → 0.0.4

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.
Files changed (48) hide show
  1. package/dist/core/abstractbase.controller.d.ts +34 -0
  2. package/dist/core/abstractbase.controller.js +101 -10
  3. package/dist/core/api-error.js +5 -1
  4. package/dist/core/base.cache.d.ts +6 -0
  5. package/dist/core/base.cache.js +31 -14
  6. package/dist/core/base.model.js +51 -46
  7. package/dist/core/base.options.d.ts +12 -0
  8. package/dist/core/base.options.js +2 -1
  9. package/dist/core/base.service.d.ts +46 -0
  10. package/dist/core/base.service.js +82 -30
  11. package/dist/core/index.js +22 -6
  12. package/dist/core/pg.driver.d.ts +1 -0
  13. package/dist/core/pg.driver.js +6 -1
  14. package/dist/decorators/index.decorator.d.ts +10 -0
  15. package/dist/decorators/index.decorator.js +16 -2
  16. package/dist/decorators/index.js +20 -4
  17. package/dist/decorators/prop.decorator.d.ts +14 -0
  18. package/dist/decorators/prop.decorator.js +19 -1
  19. package/dist/decorators/timestamp.decorator.d.ts +8 -0
  20. package/dist/decorators/timestamp.decorator.js +14 -2
  21. package/dist/decorators/utils.d.ts +5 -0
  22. package/dist/decorators/utils.js +10 -1
  23. package/dist/index.js +21 -5
  24. package/dist/server.d.ts +11 -0
  25. package/dist/server.js +30 -10
  26. package/dist/types/api.types.js +11 -8
  27. package/dist/types/db.types.js +10 -7
  28. package/dist/types/decorator.types.d.ts +31 -0
  29. package/dist/types/decorator.types.js +9 -2
  30. package/dist/types/index.js +20 -4
  31. package/dist/types/server.types.js +2 -1
  32. package/dist/utils/api.utils.d.ts +15 -0
  33. package/dist/utils/api.utils.js +34 -8
  34. package/dist/utils/array.utils.d.ts +2 -0
  35. package/dist/utils/array.utils.js +9 -2
  36. package/dist/utils/cache.utils.js +9 -2
  37. package/dist/utils/crypto.utils.d.ts +1 -0
  38. package/dist/utils/crypto.utils.js +7 -1
  39. package/dist/utils/db.utils.d.ts +5 -0
  40. package/dist/utils/db.utils.js +55 -36
  41. package/dist/utils/function.utils.d.ts +1 -0
  42. package/dist/utils/function.utils.js +6 -3
  43. package/dist/utils/index.js +24 -8
  44. package/dist/utils/middleware.utils.d.ts +4 -0
  45. package/dist/utils/middleware.utils.js +9 -1
  46. package/dist/utils/server.utils.d.ts +3 -0
  47. package/dist/utils/server.utils.js +20 -9
  48. package/package.json +1 -1
@@ -1,22 +1,26 @@
1
- import { AndOr, OneOrMany, SqlDirection } from "unconventional-pg-queries";
2
- import { NullSqlOperators, ValidSortDirections, ValidSqlOperators, andOrPattern } from "../types/db.types";
3
- import { RelationType } from "../types/decorator.types";
4
- import { parseExpandString, splitExpandUnit } from "./api.utils";
5
- import { equalArrays } from "./array.utils";
6
- import { APIError } from "../core/api-error";
7
- export function getExpand(model, expand) {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildFilter = exports.getConflict = exports.getReturn = exports.getPage = exports.getOrder = exports.getWhere = exports.getExpand = void 0;
4
+ const unconventional_pg_queries_1 = require("unconventional-pg-queries");
5
+ const db_types_1 = require("../types/db.types");
6
+ const decorator_types_1 = require("../types/decorator.types");
7
+ const api_utils_1 = require("./api.utils");
8
+ const array_utils_1 = require("./array.utils");
9
+ const api_error_1 = require("../core/api-error");
10
+ /** Converts a stringified list of relational fields to an array of data needed to expand those fields in a SQL environment */
11
+ function getExpand(model, expand) {
8
12
  if (!expand)
9
13
  return {};
10
14
  const propSummary = model.schema.props;
11
15
  const expansions = {};
12
- const parts = parseExpandString(expand);
16
+ const parts = (0, api_utils_1.parseExpandString)(expand);
13
17
  parts.forEach((field) => {
14
- const { parent, children } = splitExpandUnit(field);
18
+ const { parent, children } = (0, api_utils_1.splitExpandUnit)(field);
15
19
  const relation = propSummary[parent]?.relation;
16
20
  if (!relation)
17
- throw APIError.errInvalidQueryParameter(`Invalid expansion: ${parent}`);
21
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid expansion: ${parent}`);
18
22
  expansions[parent] = {
19
- type: [RelationType.HasOne, RelationType.BelongsTo].includes(relation.type) ? OneOrMany.One : OneOrMany.Many,
23
+ type: [decorator_types_1.RelationType.HasOne, decorator_types_1.RelationType.BelongsTo].includes(relation.type) ? unconventional_pg_queries_1.OneOrMany.One : unconventional_pg_queries_1.OneOrMany.Many,
20
24
  fromTable: model.collection,
21
25
  fromField: relation.from.toString(),
22
26
  toTable: relation.model.collection,
@@ -29,73 +33,84 @@ export function getExpand(model, expand) {
29
33
  });
30
34
  return expansions;
31
35
  }
32
- export function getWhere(model, filterString) {
36
+ exports.getExpand = getExpand;
37
+ /** Converts a string of filters to an array of 'where' clause outlines for a SQL environment */
38
+ function getWhere(model, filterString) {
33
39
  if (!filterString)
34
40
  return [];
35
41
  const propSummary = model.schema.props;
36
42
  const wheres = [];
37
43
  if (filterString) {
38
- filterString.split(andOrPattern).forEach((filter) => {
44
+ filterString.split(db_types_1.andOrPattern).forEach((filter) => {
45
+ // Handle logically combined clauses
39
46
  let andOr = undefined;
40
- if (filter.startsWith(AndOr.And)) {
41
- filter = filter.substring(AndOr.And.length + 1);
42
- andOr = AndOr.And;
47
+ if (filter.startsWith(unconventional_pg_queries_1.AndOr.And)) {
48
+ filter = filter.substring(unconventional_pg_queries_1.AndOr.And.length + 1);
49
+ andOr = unconventional_pg_queries_1.AndOr.And;
43
50
  }
44
- else if (filter.startsWith(AndOr.Or)) {
45
- filter = filter.substring(AndOr.Or.length + 1);
46
- andOr = AndOr.Or;
51
+ else if (filter.startsWith(unconventional_pg_queries_1.AndOr.Or)) {
52
+ filter = filter.substring(unconventional_pg_queries_1.AndOr.Or.length + 1);
53
+ andOr = unconventional_pg_queries_1.AndOr.Or;
47
54
  }
48
55
  let field = filter.substring(0, filter.indexOf(' '));
49
56
  let value = filter.substring(filter.lastIndexOf(' ') + 1);
50
57
  let operator = filter.substring(filter.indexOf(' ') + 1, filter.lastIndexOf(' '));
51
58
  let jsonPath = [];
59
+ // Handle IS NULL and IS NOT NULL, which don't have values
52
60
  if (operator.startsWith('IS')) {
53
61
  operator = `${operator} ${value}`;
54
62
  value = null;
55
63
  }
64
+ // Handle JSON path
56
65
  if (field.includes('.')) {
57
66
  jsonPath = field.split('.');
58
67
  field = jsonPath.shift();
59
68
  }
60
69
  if (!propSummary[field])
61
- throw APIError.errInvalidQueryParameter(`Invalid filter: '${field}'`);
62
- if (!ValidSqlOperators.includes(operator))
63
- throw APIError.errInvalidQueryParameter(`Invalid operator in filter: '${operator}'`);
64
- if (!value && !NullSqlOperators.includes(operator))
65
- throw APIError.errInvalidQueryParameter(`Invalid value in filter: '${value}'`);
70
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid filter: '${field}'`);
71
+ if (!db_types_1.ValidSqlOperators.includes(operator))
72
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid operator in filter: '${operator}'`);
73
+ if (!value && !db_types_1.NullSqlOperators.includes(operator))
74
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid value in filter: '${value}'`);
66
75
  wheres.push({ field, jsonPath, operator: operator, value, andOr });
67
76
  });
68
77
  }
69
78
  return wheres;
70
79
  }
71
- export function getOrder(model, sort) {
80
+ exports.getWhere = getWhere;
81
+ /** Converts a stringified list of fields to order ascending or descending to an array of order data for a SQL environment */
82
+ function getOrder(model, sort) {
72
83
  if (!sort)
73
- return [{ field: model.idField, direction: SqlDirection.Asc }];
84
+ return [{ field: model.idField, direction: unconventional_pg_queries_1.SqlDirection.Asc }];
74
85
  const propSummary = model.schema.props;
75
86
  const orders = [];
76
87
  sort.split(',').forEach((item) => {
77
88
  let [field, direction] = item.split(' ');
78
89
  let jsonPath = [];
79
- direction ||= SqlDirection.Asc;
90
+ direction ||= unconventional_pg_queries_1.SqlDirection.Asc;
91
+ // Handle JSON path
80
92
  if (field.includes('.')) {
81
93
  jsonPath = field.split('.');
82
94
  field = jsonPath.shift();
83
95
  }
84
96
  if (!propSummary[field])
85
- throw APIError.errInvalidQueryParameter(`Invalid orderBy field: '${field}'`);
86
- if (!ValidSortDirections.includes(direction.toUpperCase()))
87
- throw APIError.errInvalidQueryParameter(`Invalid orderBy direction: '${direction}'`);
97
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid orderBy field: '${field}'`);
98
+ if (!db_types_1.ValidSortDirections.includes(direction.toUpperCase()))
99
+ throw api_error_1.APIError.errInvalidQueryParameter(`Invalid orderBy direction: '${direction}'`);
88
100
  orders.push({ field, jsonPath, direction: direction.toUpperCase() });
89
101
  });
90
102
  return orders;
91
103
  }
92
- export function getPage(model, cursor) {
104
+ exports.getOrder = getOrder;
105
+ function getPage(model, cursor) {
93
106
  if (!cursor)
94
107
  return undefined;
95
108
  const pagination = { field: model.idField, cursor };
96
109
  return pagination;
97
110
  }
98
- export function getReturn(model) {
111
+ exports.getPage = getPage;
112
+ /** Retrieves all non-relational fields from a model for the 'returning' clause of a SQL call */
113
+ function getReturn(model) {
99
114
  const propSummary = model.schema.props;
100
115
  const fields = [];
101
116
  Object.entries(propSummary).forEach(([field, summary]) => {
@@ -104,24 +119,28 @@ export function getReturn(model) {
104
119
  });
105
120
  return fields;
106
121
  }
107
- export function getConflict(model, action, constraint) {
122
+ exports.getReturn = getReturn;
123
+ function getConflict(model, action, constraint) {
108
124
  if (!constraint)
109
125
  return undefined;
110
126
  const indexes = model.schema.indexes;
111
127
  for (const index of indexes) {
112
128
  const keys = Object.keys(index.definition);
113
- if (equalArrays(keys, constraint))
129
+ if ((0, array_utils_1.equalArrays)(keys, constraint))
114
130
  return { action, constraint: keys };
115
131
  }
116
132
  return undefined;
117
133
  }
118
- export function buildFilter(field, operator, value) {
134
+ exports.getConflict = getConflict;
135
+ /** A type-safe way to build filter strings */
136
+ function buildFilter(field, operator, value) {
119
137
  let formatted = `${value}`;
120
138
  if (typeof value === 'string')
121
139
  formatted = `'${value}'`;
122
140
  else if (Array.isArray(value))
123
141
  formatted = (typeof value[0] === 'string') ? `('${value.join("','")}')` : `(${value.join()})`;
124
- else if (value == null || NullSqlOperators.includes(operator))
142
+ else if (value == null || db_types_1.NullSqlOperators.includes(operator))
125
143
  formatted = '';
126
144
  return `${field} ${operator} ${formatted}`;
127
145
  }
146
+ exports.buildFilter = buildFilter;
@@ -6,5 +6,6 @@ interface CFFunctionDefinition {
6
6
  routeRegistrationFn: (server: BackendServer) => void;
7
7
  }
8
8
  export type CFFunctionHandler = (config: CFFunctionDefinition) => PagesFunction<{}>;
9
+ /** A Cloudflare Pages function handler configured with routes, a database connection, middleware, cors, and error handling OOTB. */
9
10
  declare const functionHandler: CFFunctionHandler;
10
11
  export default functionHandler;
@@ -1,6 +1,9 @@
1
- import { BackendServer } from "../server";
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const server_1 = require("../server");
4
+ /** A Cloudflare Pages function handler configured with routes, a database connection, middleware, cors, and error handling OOTB. */
2
5
  const functionHandler = (config) => {
3
- const server = new BackendServer();
6
+ const server = new server_1.BackendServer();
4
7
  let handler;
5
8
  return async (eventContext) => {
6
9
  if (!server.configured) {
@@ -11,4 +14,4 @@ const functionHandler = (config) => {
11
14
  return await handler(eventContext);
12
15
  };
13
16
  };
14
- export default functionHandler;
17
+ exports.default = functionHandler;
@@ -1,8 +1,24 @@
1
- export * from './api.utils';
2
- export * from './array.utils';
3
- export * from './cache.utils';
4
- export * from './crypto.utils';
5
- export * from './db.utils';
6
- export * from './function.utils';
7
- export * from './middleware.utils';
8
- export * from './server.utils';
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api.utils"), exports);
18
+ __exportStar(require("./array.utils"), exports);
19
+ __exportStar(require("./cache.utils"), exports);
20
+ __exportStar(require("./crypto.utils"), exports);
21
+ __exportStar(require("./db.utils"), exports);
22
+ __exportStar(require("./function.utils"), exports);
23
+ __exportStar(require("./middleware.utils"), exports);
24
+ __exportStar(require("./server.utils"), exports);
@@ -1,3 +1,7 @@
1
1
  import { Input, MiddlewareHandler } from "hono";
2
2
  import { BaseHandler, Env } from "../types/api.types";
3
+ /**
4
+ * Combines any number of RequestHandlers into one function that performs
5
+ * the logical OR of their results.
6
+ */
3
7
  export declare function Or<E extends Env = Env, P extends string = any, I extends Input = Input, T extends BaseHandler<E, P, I> | MiddlewareHandler<E, P, I> = MiddlewareHandler<E, P, I>>(...methods: Array<T>): MiddlewareHandler<E, P, I>;
@@ -1,4 +1,11 @@
1
- export function Or(...methods) {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Or = void 0;
4
+ /**
5
+ * Combines any number of RequestHandlers into one function that performs
6
+ * the logical OR of their results.
7
+ */
8
+ function Or(...methods) {
2
9
  return async (ctx, next) => {
3
10
  const halt = async () => { };
4
11
  const promises = methods.map(x => x(ctx, halt));
@@ -8,3 +15,4 @@ export function Or(...methods) {
8
15
  await next();
9
16
  };
10
17
  }
18
+ exports.Or = Or;
@@ -1,4 +1,7 @@
1
1
  import { DBFactory } from "../types";
2
+ /** Default CORS middleware permitting all origins and methods */
2
3
  export declare const defaultCors: import("hono").MiddlewareHandler;
4
+ /** Binds the database proxy to the BaseModel */
3
5
  export declare const bindDatabase: (getDB: DBFactory) => (ctx: any, next: any) => Promise<void>;
6
+ /** Catches and formats errors in a standard way */
4
7
  export declare const defaultErrorHandler: (err: any, ctx: any) => any;
@@ -1,19 +1,29 @@
1
- import { cors } from "hono/cors";
2
- import BaseModel from "../core/base.model";
3
- import { APIError } from "../core";
4
- export const defaultCors = cors({
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.defaultErrorHandler = exports.bindDatabase = exports.defaultCors = void 0;
7
+ const cors_1 = require("hono/cors");
8
+ const base_model_1 = __importDefault(require("../core/base.model"));
9
+ const core_1 = require("../core");
10
+ /** Default CORS middleware permitting all origins and methods */
11
+ exports.defaultCors = (0, cors_1.cors)({
5
12
  origin: "*",
6
13
  allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
7
14
  });
8
- export const bindDatabase = (getDB) => {
15
+ /** Binds the database proxy to the BaseModel */
16
+ const bindDatabase = (getDB) => {
9
17
  return async (ctx, next) => {
10
- if (!BaseModel.db)
11
- BaseModel.db = getDB(ctx);
18
+ if (!base_model_1.default.db)
19
+ base_model_1.default.db = getDB(ctx);
12
20
  await next();
13
21
  };
14
22
  };
15
- export const defaultErrorHandler = (err, ctx) => {
16
- if (err instanceof APIError) {
23
+ exports.bindDatabase = bindDatabase;
24
+ /** Catches and formats errors in a standard way */
25
+ const defaultErrorHandler = (err, ctx) => {
26
+ if (err instanceof core_1.APIError) {
17
27
  ctx.status(err.statusCode || 500);
18
28
  return ctx.json({
19
29
  error_code: err.name,
@@ -25,3 +35,4 @@ export const defaultErrorHandler = (err, ctx) => {
25
35
  ctx.status(500);
26
36
  return ctx.json({ error: err.message });
27
37
  };
38
+ exports.defaultErrorHandler = defaultErrorHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unconventional",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "A complete server built on Cloudflare Pages Functions",
5
5
  "keywords": [
6
6
  "cloudflare",