@snowtop/ent 0.1.0-alpha2 → 0.1.0-alpha3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.1.0-alpha2",
3
+ "version": "0.1.0-alpha3",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,4 +1,4 @@
1
- import { Schema, Field, AssocEdge, AssocEdgeGroup, Action } from "../schema";
1
+ import { Schema, Field, AssocEdge, AssocEdgeGroup, Action, Type } from "../schema";
2
2
  import { ActionField } from "../schema/schema";
3
3
  declare enum NullableResult {
4
4
  CONTENTS = "contents",
@@ -32,12 +32,18 @@ interface ProcessedPattern {
32
32
  assocEdges: ProcessedAssocEdge[];
33
33
  fields: ProcessedField[];
34
34
  }
35
- declare type ProcessedField = Omit<Field, "defaultValueOnEdit" | "defaultValueOnCreate"> & {
35
+ declare type ProcessedType = Omit<Type, "subFields" | "listElemType" | "unionFields"> & {
36
+ subFields?: ProcessedField[];
37
+ listElemType?: ProcessedType;
38
+ unionFields?: ProcessedField[];
39
+ };
40
+ declare type ProcessedField = Omit<Field, "defaultValueOnEdit" | "defaultValueOnCreate" | "type"> & {
36
41
  name: string;
37
42
  hasDefaultValueOnCreate?: boolean;
38
43
  hasDefaultValueOnEdit?: boolean;
39
44
  patternName?: string;
40
45
  derivedFields?: ProcessedField[];
46
+ type: ProcessedType;
41
47
  };
42
48
  interface patternsDict {
43
49
  [key: string]: ProcessedPattern;
@@ -18,6 +18,7 @@ function processFields(src, patternName) {
18
18
  }
19
19
  for (const name in m) {
20
20
  const field = m[name];
21
+ //@ts-ignore type and other changed fields with different type in ProcessedField vs Field
21
22
  let f = { name, ...field };
22
23
  f.hasDefaultValueOnCreate = field.defaultValueOnCreate != undefined;
23
24
  f.hasDefaultValueOnEdit = field.defaultValueOnEdit != undefined;
@@ -48,6 +49,18 @@ function processFields(src, patternName) {
48
49
  if (field.getDerivedFields) {
49
50
  f.derivedFields = processFields(field.getDerivedFields(name));
50
51
  }
52
+ if (field.type.subFields) {
53
+ f.type.subFields = processFields(field.type.subFields);
54
+ }
55
+ if (field.type.unionFields) {
56
+ f.type.unionFields = processFields(field.type.unionFields);
57
+ }
58
+ if (field.type.listElemType &&
59
+ field.type.listElemType.subFields &&
60
+ // check to avoid ts-ignore below. exists just for tsc
61
+ f.type.listElemType) {
62
+ f.type.listElemType.subFields = processFields(field.type.listElemType.subFields);
63
+ }
51
64
  ret.push(f);
52
65
  }
53
66
  return ret;
package/schema/field.d.ts CHANGED
@@ -146,7 +146,7 @@ export declare class ListField extends BaseField {
146
146
  validate(validator: (val: any[]) => boolean): this;
147
147
  valid(val: any): Promise<boolean>;
148
148
  private postgresVal;
149
- format(val: any): any;
149
+ format(val: any, nested?: boolean): any;
150
150
  minLen(l: number): this;
151
151
  maxLen(l: number): this;
152
152
  length(l: number): this;
package/schema/field.js CHANGED
@@ -597,13 +597,17 @@ class ListField extends BaseField {
597
597
  }
598
598
  return JSON.stringify(val);
599
599
  }
600
- format(val) {
600
+ format(val, nested) {
601
601
  if (!Array.isArray(val)) {
602
602
  throw new Error(`need an array to format`);
603
603
  }
604
604
  const elemDBType = this.type.listElemType.dbType;
605
605
  const jsonType = elemDBType === "JSON" || elemDBType === "JSONB";
606
- const postgres = db_1.default.getDialect() === db_1.Dialect.Postgres;
606
+ // postgres ish doesn't apply when nested
607
+ const postgres = !nested && db_1.default.getDialect() === db_1.Dialect.Postgres;
608
+ if (nested && !this.field.format) {
609
+ return val;
610
+ }
607
611
  if (!postgres && !this.field.format) {
608
612
  return JSON.stringify(val);
609
613
  }
@@ -629,6 +633,10 @@ class ListField extends BaseField {
629
633
  if (postgres) {
630
634
  return postgresRet + "}";
631
635
  }
636
+ // don't JSON.stringify if nested
637
+ if (nested) {
638
+ return ret;
639
+ }
632
640
  return JSON.stringify(ret);
633
641
  }
634
642
  minLen(l) {
package/schema/index.d.ts CHANGED
@@ -4,3 +4,5 @@ export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBTy
4
4
  export { Timestamps, Node, BaseEntSchema, BaseEntSchemaWithTZ, } from "./base_schema";
5
5
  export * from "./field";
6
6
  export * from "./json_field";
7
+ export * from "./struct_field";
8
+ export * from "./union_field";
package/schema/index.js CHANGED
@@ -26,3 +26,5 @@ Object.defineProperty(exports, "BaseEntSchema", { enumerable: true, get: functio
26
26
  Object.defineProperty(exports, "BaseEntSchemaWithTZ", { enumerable: true, get: function () { return base_schema_1.BaseEntSchemaWithTZ; } });
27
27
  __exportStar(require("./field"), exports);
28
28
  __exportStar(require("./json_field"), exports);
29
+ __exportStar(require("./struct_field"), exports);
30
+ __exportStar(require("./union_field"), exports);
@@ -97,6 +97,8 @@ export interface Type {
97
97
  values?: string[];
98
98
  enumMap?: EnumMap;
99
99
  importType?: ImportType;
100
+ subFields?: FieldMap;
101
+ unionFields?: FieldMap;
100
102
  }
101
103
  export interface ForeignKey {
102
104
  schema: string;
@@ -149,7 +151,7 @@ export interface PolymorphicOptions {
149
151
  export interface Field extends FieldOptions {
150
152
  type: Type;
151
153
  valid?(val: any): Promise<boolean> | boolean;
152
- format?(val: any): any;
154
+ format?(val: any, nested?: boolean): any;
153
155
  logValue(val: any): any;
154
156
  }
155
157
  export interface SchemaConstructor {
@@ -0,0 +1,17 @@
1
+ import { BaseField, ListField } from "./field";
2
+ import { FieldOptions, Field, Type, FieldMap } from "./schema";
3
+ export interface StructOptions extends FieldOptions {
4
+ tsType: string;
5
+ fields: FieldMap;
6
+ graphQLType?: string;
7
+ jsonNotJSONB?: boolean;
8
+ }
9
+ export declare class StructField extends BaseField implements Field {
10
+ private options;
11
+ type: Type;
12
+ constructor(options: StructOptions);
13
+ format(obj: any, nested?: boolean): string | Object;
14
+ valid(obj: any): Promise<boolean>;
15
+ }
16
+ export declare function StructType(options: StructOptions): StructField & StructOptions;
17
+ export declare function StructListType(options: StructOptions): ListField;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StructListType = exports.StructType = exports.StructField = void 0;
4
+ const field_1 = require("./field");
5
+ const schema_1 = require("./schema");
6
+ const camel_case_1 = require("camel-case");
7
+ class StructField extends field_1.BaseField {
8
+ constructor(options) {
9
+ super();
10
+ this.options = options;
11
+ this.type = {
12
+ dbType: schema_1.DBType.JSONB,
13
+ };
14
+ this.type.subFields = options.fields;
15
+ this.type.type = options.tsType;
16
+ this.type.graphQLType = options.graphQLType || options.tsType;
17
+ if (options.jsonNotJSONB) {
18
+ this.type.dbType = schema_1.DBType.JSON;
19
+ }
20
+ }
21
+ // right now, we store things in the db in lowerCase format
22
+ // this will lead to issues if field changes.
23
+ // TODO: use storageKey and convert back...
24
+ format(obj, nested) {
25
+ if (!(obj instanceof Object)) {
26
+ throw new Error("valid was not called");
27
+ }
28
+ let ret = {};
29
+ for (const k in this.options.fields) {
30
+ // TODO more #510
31
+ let dbKey = (0, camel_case_1.camelCase)(k);
32
+ let val = obj[dbKey];
33
+ // for tests with snake_case
34
+ if (val === undefined && obj[k] !== undefined) {
35
+ val = obj[k];
36
+ dbKey = k;
37
+ }
38
+ if (val === undefined) {
39
+ continue;
40
+ }
41
+ const field = this.options.fields[k];
42
+ if (field.format) {
43
+ // indicate nested so this isn't JSON stringified
44
+ ret[dbKey] = field.format(val, true);
45
+ }
46
+ else {
47
+ ret[dbKey] = val;
48
+ }
49
+ }
50
+ // don't json.stringify if nested
51
+ if (nested) {
52
+ return ret;
53
+ }
54
+ return JSON.stringify(ret);
55
+ }
56
+ async valid(obj) {
57
+ if (!(obj instanceof Object)) {
58
+ return false;
59
+ }
60
+ let promises = [];
61
+ // TODO probably need to support optional fields...
62
+ let valid = true;
63
+ for (const k in this.options.fields) {
64
+ const field = this.options.fields[k];
65
+ // TODO more #510
66
+ let dbKey = (0, camel_case_1.camelCase)(k);
67
+ let val = obj[dbKey];
68
+ // for tests with snake_case
69
+ if (val === undefined && obj[k] !== undefined) {
70
+ val = obj[k];
71
+ dbKey = k;
72
+ }
73
+ if (val === undefined || val === null) {
74
+ // nullable, nothing to do here
75
+ if (field.nullable) {
76
+ continue;
77
+ }
78
+ valid = false;
79
+ break;
80
+ }
81
+ if (!field.valid) {
82
+ continue;
83
+ }
84
+ promises.push(field.valid(val));
85
+ }
86
+ if (!valid) {
87
+ return valid;
88
+ }
89
+ const ret = await Promise.all(promises);
90
+ return ret.every((v) => v);
91
+ }
92
+ }
93
+ exports.StructField = StructField;
94
+ function StructType(options) {
95
+ let result = new StructField(options);
96
+ return Object.assign(result, options);
97
+ }
98
+ exports.StructType = StructType;
99
+ function StructListType(options) {
100
+ return new field_1.ListField(StructType(options), options);
101
+ }
102
+ exports.StructListType = StructListType;
@@ -0,0 +1,22 @@
1
+ import { StructField } from "./struct_field";
2
+ import { FieldOptions, Type } from "./schema";
3
+ import { BaseField, ListField } from "./field";
4
+ export declare type StructMap = {
5
+ [key: string]: StructField;
6
+ };
7
+ export interface UnionOptions extends FieldOptions {
8
+ tsType: string;
9
+ fields: StructMap;
10
+ graphQLType?: string;
11
+ jsonNotJSONB?: boolean;
12
+ }
13
+ export declare class UnionField extends BaseField implements FieldOptions {
14
+ private options;
15
+ type: Type;
16
+ m: Map<Object, string>;
17
+ constructor(options: UnionOptions);
18
+ format(obj: any, nested?: boolean): string | Object;
19
+ valid(obj: any): Promise<boolean>;
20
+ }
21
+ export declare function UnionType(options: UnionOptions): UnionField & UnionOptions;
22
+ export declare function UnionListType(options: UnionOptions): ListField;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnionListType = exports.UnionType = exports.UnionField = void 0;
4
+ const schema_1 = require("./schema");
5
+ const field_1 = require("./field");
6
+ class UnionField extends field_1.BaseField {
7
+ constructor(options) {
8
+ super();
9
+ this.options = options;
10
+ this.type = {
11
+ dbType: schema_1.DBType.JSONB,
12
+ };
13
+ this.m = new Map();
14
+ this.type.unionFields = options.fields;
15
+ this.type.type = options.tsType;
16
+ this.type.graphQLType = options.graphQLType || options.tsType;
17
+ // TODO should throw if not nested?
18
+ if (options.jsonNotJSONB) {
19
+ this.type.dbType = schema_1.DBType.JSON;
20
+ }
21
+ }
22
+ format(obj, nested) {
23
+ if (!(obj instanceof Object)) {
24
+ throw new Error("valid was not called");
25
+ }
26
+ for (const k in this.options.fields) {
27
+ const field = this.options.fields[k];
28
+ const fmt = field.format(obj, nested);
29
+ if (fmt !== "{}") {
30
+ return fmt;
31
+ }
32
+ }
33
+ // TODO need better logic here
34
+ // maybe add something ignored to the objec that indicates which key?
35
+ // or store in map
36
+ throw new Error(`couldn't format union`);
37
+ }
38
+ async valid(obj) {
39
+ if (!(obj instanceof Object)) {
40
+ return false;
41
+ }
42
+ let promises = [];
43
+ for (const k in this.options.fields) {
44
+ const field = this.options.fields[k];
45
+ promises.push(field.valid(obj));
46
+ }
47
+ const ret = await Promise.all(promises);
48
+ // only 1 should be valid
49
+ return ret.filter((v) => v).length === 1;
50
+ }
51
+ }
52
+ exports.UnionField = UnionField;
53
+ function UnionType(options) {
54
+ let result = new UnionField(options);
55
+ return Object.assign(result, options);
56
+ }
57
+ exports.UnionType = UnionType;
58
+ function UnionListType(options) {
59
+ return new field_1.ListField(UnionType(options), options);
60
+ }
61
+ exports.UnionListType = UnionListType;