@snowtop/ent 0.1.0-alpha53 → 0.1.0-alpha58

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 (40) hide show
  1. package/action/experimental_action.d.ts +1 -1
  2. package/action/orchestrator.js +21 -1
  3. package/core/base.d.ts +1 -1
  4. package/core/clause.d.ts +36 -7
  5. package/core/clause.js +133 -32
  6. package/core/config.d.ts +5 -2
  7. package/core/ent.d.ts +16 -3
  8. package/core/ent.js +147 -35
  9. package/core/loaders/assoc_count_loader.js +6 -1
  10. package/core/query/shared_assoc_test.d.ts +1 -1
  11. package/core/query/shared_assoc_test.js +17 -5
  12. package/core/query/shared_test.d.ts +3 -0
  13. package/core/query/shared_test.js +95 -17
  14. package/index.d.ts +5 -5
  15. package/index.js +7 -6
  16. package/package.json +1 -1
  17. package/parse_schema/parse.d.ts +8 -2
  18. package/parse_schema/parse.js +22 -2
  19. package/schema/field.js +4 -0
  20. package/schema/index.d.ts +1 -1
  21. package/schema/schema.d.ts +16 -0
  22. package/scripts/custom_graphql.js +2 -0
  23. package/scripts/read_schema.js +10 -1
  24. package/testutils/db/{test_db.d.ts → temp_db.d.ts} +15 -3
  25. package/testutils/db/{test_db.js → temp_db.js} +62 -15
  26. package/testutils/fake_data/fake_contact.d.ts +1 -1
  27. package/testutils/fake_data/fake_contact.js +2 -2
  28. package/testutils/fake_data/fake_event.d.ts +1 -1
  29. package/testutils/fake_data/fake_event.js +3 -3
  30. package/testutils/fake_data/fake_user.d.ts +1 -1
  31. package/testutils/fake_data/fake_user.js +2 -2
  32. package/testutils/fake_data/test_helpers.d.ts +2 -2
  33. package/testutils/fake_data/test_helpers.js +5 -5
  34. package/testutils/parse_sql.js +4 -0
  35. package/testutils/test_edge_global_schema.d.ts +15 -0
  36. package/testutils/test_edge_global_schema.js +58 -0
  37. package/testutils/write.d.ts +2 -2
  38. package/testutils/write.js +3 -3
  39. package/tsc/ast.d.ts +1 -0
  40. package/tsc/ast.js +3 -0
package/index.js CHANGED
@@ -25,8 +25,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
25
25
  return (mod && mod.__esModule) ? mod : { "default": mod };
26
26
  };
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.DenyIfViewerInboundEdgeDoesNotExistRule = exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = exports.AllowIfViewerOutboundEdgeExistsRule = exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.AllowIfFuncRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedOutRule = exports.DenyIfLoggedInRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = exports.DB = exports.getEdgeTypeInGroup = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadEdges = exports.loadEdgeDatas = exports.loadEdgeData = exports.AssocEdgeData = exports.AssocEdge = exports.DeleteNodeOperation = exports.EdgeOperation = exports.EditNodeOperation = exports.loadRows = exports.loadRow = exports.loadRowX = exports.performRawQuery = exports.loadEntXViaKey = exports.loadEntViaKey = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadEnts = exports.loadEntX = exports.loadCustomEnts = exports.loadCustomData = exports.loadEnt = void 0;
29
- exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = void 0;
28
+ exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = exports.AllowIfViewerOutboundEdgeExistsRule = exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.AllowIfFuncRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedOutRule = exports.DenyIfLoggedInRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = exports.DB = exports.setGlobalSchema = exports.getEdgeTypeInGroup = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadEdges = exports.loadEdgeDatas = exports.loadEdgeData = exports.AssocEdgeData = exports.AssocEdge = exports.DeleteNodeOperation = exports.EdgeOperation = exports.EditNodeOperation = exports.loadRows = exports.loadRow = exports.loadRowX = exports.performRawQuery = exports.loadEntXViaKey = exports.loadEntViaKey = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadEnts = exports.loadEntX = exports.loadCustomEnts = exports.loadCustomData = exports.loadEnt = void 0;
29
+ exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = exports.DenyIfViewerInboundEdgeDoesNotExistRule = void 0;
30
30
  __exportStar(require("./core/base"), exports);
31
31
  var ent_1 = require("./core/ent");
32
32
  Object.defineProperty(exports, "loadEnt", { enumerable: true, get: function () { return ent_1.loadEnt; } });
@@ -57,6 +57,7 @@ Object.defineProperty(exports, "loadRawEdgeCountX", { enumerable: true, get: fun
57
57
  Object.defineProperty(exports, "loadEdgeForID2", { enumerable: true, get: function () { return ent_1.loadEdgeForID2; } });
58
58
  Object.defineProperty(exports, "loadNodesByEdge", { enumerable: true, get: function () { return ent_1.loadNodesByEdge; } });
59
59
  Object.defineProperty(exports, "getEdgeTypeInGroup", { enumerable: true, get: function () { return ent_1.getEdgeTypeInGroup; } });
60
+ Object.defineProperty(exports, "setGlobalSchema", { enumerable: true, get: function () { return ent_1.setGlobalSchema; } });
60
61
  const db_1 = __importDefault(require("./core/db"));
61
62
  exports.DB = db_1.default;
62
63
  __exportStar(require("./core/loaders"), exports);
@@ -116,10 +117,10 @@ const query = {
116
117
  LessEq: q.LessEq,
117
118
  ArrayEq: q.ArrayEq,
118
119
  ArrayNotEq: q.ArrayNotEq,
119
- ArrayGreater: q.ArrayGreater,
120
- ArrayLess: q.ArrayLess,
121
- ArrayGreaterEq: q.ArrayGreaterEq,
122
- ArrayLessEq: q.ArrayLessEq,
120
+ PostgresArrayContainsValue: q.PostgresArrayContainsValue,
121
+ PostgresArrayContains: q.PostgresArrayContains,
122
+ PostgresArrayNotContainsValue: q.PostgresArrayNotContainsValue,
123
+ PostgresArrayNotContains: q.PostgresArrayNotContains,
123
124
  TsQuery: q.TsQuery,
124
125
  PlainToTsQuery: q.PlainToTsQuery,
125
126
  PhraseToTsQuery: q.PhraseToTsQuery,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.1.0-alpha53",
3
+ "version": "0.1.0-alpha58",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import { Schema, Field, AssocEdge, AssocEdgeGroup, Action } from "../schema";
2
- import { ActionField, Type } from "../schema/schema";
2
+ import { ActionField, Type, GlobalSchema } from "../schema/schema";
3
3
  declare enum NullableResult {
4
4
  CONTENTS = "contents",
5
5
  CONTENTS_AND_LIST = "contentsAndList",
@@ -61,9 +61,15 @@ interface patternsDict {
61
61
  interface Result {
62
62
  schemas: schemasDict;
63
63
  patterns: patternsDict;
64
+ globalSchema?: ProcessedGlobalSchema;
64
65
  }
65
66
  declare type PotentialSchemas = {
66
67
  [key: string]: any;
67
68
  };
68
- export declare function parseSchema(potentialSchemas: PotentialSchemas): Result;
69
+ export declare function parseSchema(potentialSchemas: PotentialSchemas, globalSchema?: GlobalSchema): Result;
70
+ interface ProcessedGlobalSchema {
71
+ globalEdges: ProcessedAssocEdge[];
72
+ extraEdgeFields: ProcessedField[];
73
+ initForEdges?: boolean;
74
+ }
69
75
  export {};
@@ -172,9 +172,13 @@ function processAction(action) {
172
172
  ret.actionOnlyFields = actionOnlyFields;
173
173
  return ret;
174
174
  }
175
- function parseSchema(potentialSchemas) {
175
+ function parseSchema(potentialSchemas, globalSchema) {
176
176
  let schemas = {};
177
177
  let patterns = {};
178
+ let parsedGlobalSchema;
179
+ if (globalSchema) {
180
+ parsedGlobalSchema = parseGlobalSchema(globalSchema);
181
+ }
178
182
  for (const key in potentialSchemas) {
179
183
  const value = potentialSchemas[key];
180
184
  let schema;
@@ -234,6 +238,22 @@ function parseSchema(potentialSchemas) {
234
238
  }
235
239
  schemas[key] = processedSchema;
236
240
  }
237
- return { schemas, patterns };
241
+ return { schemas, patterns, globalSchema: parsedGlobalSchema };
238
242
  }
239
243
  exports.parseSchema = parseSchema;
244
+ function parseGlobalSchema(s) {
245
+ const ret = {
246
+ globalEdges: [],
247
+ extraEdgeFields: [],
248
+ initForEdges: !!s.extraEdgeFields ||
249
+ s.transformEdgeRead !== undefined ||
250
+ s.transformEdgeWrite !== undefined,
251
+ };
252
+ if (s.extraEdgeFields) {
253
+ ret.extraEdgeFields = processFields(s.extraEdgeFields);
254
+ }
255
+ if (s.edges) {
256
+ ret.globalEdges = processEdges(s.edges);
257
+ }
258
+ return ret;
259
+ }
package/schema/field.js CHANGED
@@ -25,6 +25,7 @@ const snake_case_1 = require("snake-case");
25
25
  const db_1 = __importStar(require("../core/db"));
26
26
  const schema_1 = require("./schema");
27
27
  const util_1 = require("util");
28
+ const uuid_1 = require("uuid");
28
29
  class BaseField {
29
30
  logValue(val) {
30
31
  if (this.sensitive) {
@@ -92,6 +93,9 @@ class UUIDField extends BaseField {
92
93
  return val.placeholderID !== undefined;
93
94
  }
94
95
  async valid(val) {
96
+ if (typeof val === "string" && !(0, uuid_1.validate)(val)) {
97
+ return false;
98
+ }
95
99
  if (!this.options?.fieldEdge?.enforceSchema) {
96
100
  return true;
97
101
  }
package/schema/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Schema from "./schema";
2
2
  export { Schema };
3
- export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, getFieldsWithPrivacy, getStorageKey, ActionOperation, Action, EdgeAction, NoFields, FieldMap, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, getTransformedReadClause, getObjectLoaderProperties, } from "./schema";
3
+ export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, getFieldsWithPrivacy, getStorageKey, ActionOperation, Action, EdgeAction, NoFields, FieldMap, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, EdgeUpdateOperation, TransformedEdgeUpdateOperation, getTransformedReadClause, getObjectLoaderProperties, GlobalSchema, } from "./schema";
4
4
  export { Timestamps, Node, BaseEntSchema, BaseEntSchemaWithTZ, EntSchema, EntSchemaWithTZ, SchemaConfig, } from "./base_schema";
5
5
  export * from "./field";
6
6
  export * from "./json_field";
@@ -1,6 +1,7 @@
1
1
  import { Data, Ent, LoaderInfo, PrivacyPolicy, Viewer } from "../core/base";
2
2
  import { Builder } from "../action/action";
3
3
  import { Clause } from "../core/clause";
4
+ import { AssocEdgeInput } from "../core/ent";
4
5
  export declare type FieldMap = {
5
6
  [key: string]: Field;
6
7
  };
@@ -11,6 +12,12 @@ interface FieldInfo {
11
12
  export declare type FieldInfoMap = {
12
13
  [key: string]: FieldInfo;
13
14
  };
15
+ export interface GlobalSchema {
16
+ edges?: Edge[];
17
+ extraEdgeFields?: FieldMap;
18
+ transformEdgeRead?: () => Clause;
19
+ transformEdgeWrite?: (stmt: EdgeUpdateOperation) => TransformedEdgeUpdateOperation | null;
20
+ }
14
21
  export default interface Schema {
15
22
  fields: FieldMap | Field[];
16
23
  tableName?: string;
@@ -82,6 +89,14 @@ export declare enum SQLStatementOperation {
82
89
  Update = "update",
83
90
  Delete = "delete"
84
91
  }
92
+ export interface EdgeUpdateOperation {
93
+ op: SQLStatementOperation;
94
+ edge: AssocEdgeInput;
95
+ }
96
+ export interface TransformedEdgeUpdateOperation {
97
+ op: SQLStatementOperation;
98
+ data?: Data;
99
+ }
85
100
  export interface UpdateOperation<TEnt extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
86
101
  op: SQLStatementOperation;
87
102
  builder: Builder<TEnt, TViewer>;
@@ -271,6 +286,7 @@ export interface Index {
271
286
  columns: string[];
272
287
  unique?: boolean;
273
288
  fulltext?: FullText;
289
+ indexType?: "gin" | "btree";
274
290
  }
275
291
  export interface ForeignKeyInfo {
276
292
  tableName: string;
@@ -237,6 +237,8 @@ async function main() {
237
237
  (0, graphql_1.addCustomType)({
238
238
  importPath: MODULE_PATH,
239
239
  // for go tests...
240
+ // TODO need a flag that only does this for go tests
241
+ // breaks when running locally sometimes...
240
242
  secondaryImportPath: "../graphql/scalars/time",
241
243
  type: "GraphQLTime",
242
244
  });
@@ -28,18 +28,27 @@ const pascal_case_1 = require("pascal-case");
28
28
  const minimist_1 = __importDefault(require("minimist"));
29
29
  const process_1 = require("process");
30
30
  const parse_1 = require("../parse_schema/parse");
31
+ const ast_1 = require("../tsc/ast");
31
32
  function main() {
32
33
  const options = (0, minimist_1.default)(process.argv.slice(2));
33
34
  if (!options.path) {
34
35
  throw new Error("path required");
35
36
  }
37
+ const customInfo = (0, ast_1.getCustomInfo)();
38
+ const globalSchemaPath = customInfo.globalSchemaPath || "__global__schema.ts";
39
+ let globalSchema;
36
40
  const r = /(\w+).ts/;
41
+ // do we still even need this...
37
42
  const paths = glob_1.default.sync(path.join(options.path, "*.ts"), {
38
43
  ignore: [`\d+_read_schema.ts`],
39
44
  });
40
45
  let potentialSchemas = {};
41
46
  for (const p of paths) {
42
47
  const basename = path.basename(p);
48
+ if (basename === globalSchemaPath) {
49
+ globalSchema = require(p).default;
50
+ continue;
51
+ }
43
52
  const match = r.exec(basename);
44
53
  if (!match) {
45
54
  throw new Error(`non-typescript file ${p} returned by glob`);
@@ -61,7 +70,7 @@ function main() {
61
70
  potentialSchemas[(0, pascal_case_1.pascalCase)(schema)] = s;
62
71
  }
63
72
  // console.log(potentialSchemas);
64
- const result = (0, parse_1.parseSchema)(potentialSchemas);
73
+ const result = (0, parse_1.parseSchema)(potentialSchemas, globalSchema);
65
74
  console.log(JSON.stringify(result));
66
75
  }
67
76
  try {
@@ -1,6 +1,7 @@
1
1
  import { Client as PGClient } from "pg";
2
2
  import { Dialect } from "../../core/db";
3
3
  import { Database as SqliteDatabase } from "better-sqlite3";
4
+ import { Field } from "../../schema";
4
5
  import { BuilderSchema } from "../builder";
5
6
  import { Ent } from "../../core/base";
6
7
  interface SchemaItem {
@@ -12,6 +13,7 @@ interface Column extends SchemaItem {
12
13
  primaryKey?: boolean;
13
14
  unique?: boolean;
14
15
  default?: string;
16
+ index?: boolean | indexOptions;
15
17
  foreignKey?: {
16
18
  table: string;
17
19
  col: string;
@@ -20,21 +22,29 @@ interface Column extends SchemaItem {
20
22
  interface Constraint extends SchemaItem {
21
23
  generate(): string;
22
24
  }
25
+ interface Index extends SchemaItem {
26
+ generate(): string;
27
+ }
23
28
  export interface CoreConcept {
24
29
  name: string;
25
30
  create(): string;
31
+ postCreate?(): string[];
26
32
  drop(): string;
27
33
  }
28
34
  export interface Table extends CoreConcept {
29
35
  columns: Column[];
30
36
  constraints?: Constraint[];
31
37
  }
32
- declare type options = Pick<Column, "nullable" | "primaryKey" | "default" | "foreignKey" | "unique">;
38
+ declare type options = Pick<Column, "nullable" | "primaryKey" | "default" | "foreignKey" | "unique" | "index">;
33
39
  export declare function primaryKey(name: string, cols: string[]): Constraint;
34
40
  export declare function foreignKey(name: string, cols: string[], fkey: {
35
41
  table: string;
36
42
  cols: string[];
37
43
  }): Constraint;
44
+ interface indexOptions {
45
+ type: string;
46
+ }
47
+ export declare function index(tableName: string, cols: string[], opts?: indexOptions): Index;
38
48
  export declare function uniqueIndex(name: string): Constraint;
39
49
  export declare function uuid(name: string, opts?: options): Column;
40
50
  export declare function text(name: string, opts?: options): Column;
@@ -72,6 +82,7 @@ export declare class TempDB {
72
82
  getDialect(): Dialect;
73
83
  getTables(): Map<string, CoreConcept>;
74
84
  beforeAll(setupConnString?: boolean): Promise<void>;
85
+ createImpl(table: CoreConcept): Promise<void>;
75
86
  getSqliteClient(): SqliteDatabase;
76
87
  getPostgresClient(): PGClient;
77
88
  afterAll(): Promise<void>;
@@ -81,10 +92,11 @@ export declare class TempDB {
81
92
  create(...tables: CoreConcept[]): Promise<void>;
82
93
  }
83
94
  export declare function assoc_edge_config_table(): Table;
84
- export declare function assoc_edge_table(name: string): Table;
95
+ export declare function assoc_edge_table(name: string, global?: boolean): Table;
85
96
  interface sqliteSetupOptions {
86
97
  disableDeleteAfterEachTest?: boolean;
87
98
  }
88
- export declare function setupSqlite(connString: string, tables: () => Table[], opts?: sqliteSetupOptions): void;
99
+ export declare function setupSqlite(connString: string, tables: () => Table[], opts?: sqliteSetupOptions): TempDB;
89
100
  export declare function getSchemaTable(schema: BuilderSchema<Ent>, dialect: Dialect): Table;
101
+ export declare function getColumnFromField(fieldName: string, f: Field, dialect: Dialect): Column;
90
102
  export {};
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.getSchemaTable = exports.setupSqlite = exports.assoc_edge_table = exports.assoc_edge_config_table = exports.TempDB = exports.enumType = exports.table = exports.boolList = exports.dateList = exports.timetzList = exports.timeList = exports.timestamptzList = exports.timestampList = exports.uuidList = exports.integerList = exports.textList = exports.jsonb = exports.json = exports.float = exports.integer = exports.bool = exports.date = exports.timetz = exports.time = exports.timestamptz = exports.timestamp = exports.enumCol = exports.text = exports.uuid = exports.uniqueIndex = exports.foreignKey = exports.primaryKey = void 0;
25
+ exports.getColumnFromField = exports.getSchemaTable = exports.setupSqlite = exports.assoc_edge_table = exports.assoc_edge_config_table = exports.TempDB = exports.enumType = exports.table = exports.boolList = exports.dateList = exports.timetzList = exports.timeList = exports.timestamptzList = exports.timestampList = exports.uuidList = exports.integerList = exports.textList = exports.jsonb = exports.json = exports.float = exports.integer = exports.bool = exports.date = exports.timetz = exports.time = exports.timestamptz = exports.timestamp = exports.enumCol = exports.text = exports.uuid = exports.uniqueIndex = exports.index = exports.foreignKey = exports.primaryKey = void 0;
26
26
  const pg_1 = require("pg");
27
27
  const db_1 = __importStar(require("../../core/db"));
28
28
  // this should only be used in tests so we expect to be able to import without shenanigans
@@ -32,6 +32,7 @@ const fs = __importStar(require("fs"));
32
32
  const schema_1 = require("../../schema");
33
33
  const snake_case_1 = require("snake-case");
34
34
  const builder_1 = require("../builder");
35
+ const test_edge_global_schema_1 = require("../test_edge_global_schema");
35
36
  function primaryKey(name, cols) {
36
37
  return {
37
38
  name: name,
@@ -50,6 +51,16 @@ function foreignKey(name, cols, fkey) {
50
51
  };
51
52
  }
52
53
  exports.foreignKey = foreignKey;
54
+ function index(tableName, cols, opts) {
55
+ const name = `${tableName}_${cols.join("_")}_idx`;
56
+ return {
57
+ name,
58
+ generate() {
59
+ return `CREATE INDEX ${name} ON ${tableName} USING ${opts?.type || "btree"} (${cols.join(",")});`;
60
+ },
61
+ };
62
+ }
63
+ exports.index = index;
53
64
  function uniqueIndex(name) {
54
65
  return {
55
66
  name: "",
@@ -248,9 +259,24 @@ exports.boolList = boolList;
248
259
  function table(name, ...items) {
249
260
  let cols = [];
250
261
  let constraints = [];
262
+ let indexes = [];
251
263
  for (const item of items) {
252
264
  if (item.datatype !== undefined) {
253
265
  const col = item;
266
+ if (col.index) {
267
+ let opts = {
268
+ type: "btree",
269
+ };
270
+ if (col.index === true) {
271
+ opts = {
272
+ type: "btree",
273
+ };
274
+ }
275
+ else {
276
+ opts = col.index;
277
+ }
278
+ indexes.push(index(name, [col.name], opts));
279
+ }
254
280
  // add it as a constraint
255
281
  if (col.foreignKey) {
256
282
  constraints.push(foreignKey(`${name}_${col.name}_fkey`, [col.name], {
@@ -288,6 +314,9 @@ function table(name, ...items) {
288
314
  constraints.forEach((constraint) => schemaStr.push(constraint.generate()));
289
315
  return `CREATE TABLE IF NOT EXISTS ${name} (\n ${schemaStr})`;
290
316
  },
317
+ postCreate() {
318
+ return indexes.map((index) => index.generate());
319
+ },
291
320
  drop() {
292
321
  return `DROP TABLE IF EXISTS ${name}`;
293
322
  },
@@ -376,11 +405,24 @@ class TempDB {
376
405
  this.sqlite = (0, better_sqlite3_1.default)(filePath);
377
406
  }
378
407
  for (const [_, table] of this.tables) {
379
- if (this.dialect == db_1.Dialect.Postgres) {
380
- await this.dbClient.query(table.create());
408
+ await this.createImpl(table);
409
+ }
410
+ }
411
+ async createImpl(table) {
412
+ if (this.dialect == db_1.Dialect.Postgres) {
413
+ await this.dbClient.query(table.create());
414
+ if (table.postCreate) {
415
+ for (const q of table.postCreate()) {
416
+ await this.dbClient.query(q);
417
+ }
381
418
  }
382
- else {
383
- this.sqlite.exec(table.create());
419
+ }
420
+ else {
421
+ this.sqlite.exec(table.create());
422
+ if (table.postCreate) {
423
+ for (const q of table.postCreate()) {
424
+ this.sqlite.exec(q);
425
+ }
384
426
  }
385
427
  }
386
428
  }
@@ -431,12 +473,7 @@ class TempDB {
431
473
  if (this.tables.has(table.name)) {
432
474
  throw new Error(`table with name ${table.name} already exists`);
433
475
  }
434
- if (this.dialect === db_1.Dialect.Postgres) {
435
- await this.dbClient.query(table.create());
436
- }
437
- else {
438
- this.sqlite.exec(table.create());
439
- }
476
+ await this.createImpl(table);
440
477
  this.tables.set(table.name, table);
441
478
  }
442
479
  }
@@ -448,18 +485,26 @@ function assoc_edge_config_table() {
448
485
  text("edge_type", { primaryKey: true }), text("edge_name"), bool("symmetric_edge", { default: "FALSE" }), text("inverse_edge_type", { nullable: true }), text("edge_table"), timestamptz("created_at"), timestamptz("updated_at"));
449
486
  }
450
487
  exports.assoc_edge_config_table = assoc_edge_config_table;
451
- function assoc_edge_table(name) {
452
- return table(name, uuid("id1"), text("id1_type"),
488
+ // if global flag is true, add any column from testEdgeGlobalSchema
489
+ // up to caller to set/clear that as needed
490
+ function assoc_edge_table(name, global) {
491
+ const t = table(name, uuid("id1"), text("id1_type"),
453
492
  // same as in assoc_edge_config_table
454
493
  text("edge_type"), uuid("id2"), text("id2_type"), timestamptz("time"), text("data", { nullable: true }), primaryKey(`${name}_pkey`, ["id1", "id2", "edge_type"]));
494
+ if (global) {
495
+ for (const k in test_edge_global_schema_1.testEdgeGlobalSchema.extraEdgeFields) {
496
+ const col = getColumnFromField(k, test_edge_global_schema_1.testEdgeGlobalSchema.extraEdgeFields[k], db_1.Dialect.Postgres);
497
+ t.columns.push(col);
498
+ }
499
+ }
500
+ return t;
455
501
  }
456
502
  exports.assoc_edge_table = assoc_edge_table;
457
503
  function setupSqlite(connString, tables, opts) {
458
- let tdb;
504
+ let tdb = new TempDB(db_1.Dialect.SQLite, tables());
459
505
  beforeAll(async () => {
460
506
  process.env.DB_CONNECTION_STRING = connString;
461
507
  (0, config_1.loadConfig)();
462
- tdb = new TempDB(db_1.Dialect.SQLite, tables());
463
508
  await tdb.beforeAll();
464
509
  const conn = db_1.default.getInstance().getConnection();
465
510
  expect(conn.db.memory).toBe(false);
@@ -483,6 +528,7 @@ function setupSqlite(connString, tables, opts) {
483
528
  await tdb.afterAll();
484
529
  fs.rmSync(tdb.getSqliteClient().name);
485
530
  });
531
+ return tdb;
486
532
  }
487
533
  exports.setupSqlite = setupSqlite;
488
534
  function getSchemaTable(schema, dialect) {
@@ -549,6 +595,7 @@ function getColumnFromField(fieldName, f, dialect) {
549
595
  return getColumn(fieldName, f, fn);
550
596
  }
551
597
  }
598
+ exports.getColumnFromField = getColumnFromField;
552
599
  function getColumn(fieldName, f, col) {
553
600
  return col(storageKey(fieldName, f), buildOpts(f));
554
601
  }
@@ -16,7 +16,7 @@ export declare class FakeContact implements Ent {
16
16
  getPrivacyPolicy(): PrivacyPolicy<this>;
17
17
  constructor(viewer: Viewer, data: Data);
18
18
  static getFields(): string[];
19
- static getTestTable(): import("../db/test_db").Table;
19
+ static getTestTable(): import("../db/temp_db").Table;
20
20
  static loaderOptions(): LoadEntOptions<FakeContact>;
21
21
  static load(v: Viewer, id: ID): Promise<FakeContact | null>;
22
22
  static loadX(v: Viewer, id: ID): Promise<FakeContact>;
@@ -6,7 +6,7 @@ const privacy_1 = require("../../core/privacy");
6
6
  const builder_1 = require("../builder");
7
7
  const schema_1 = require("../../schema");
8
8
  const const_1 = require("./const");
9
- const test_db_1 = require("../db/test_db");
9
+ const temp_db_1 = require("../db/temp_db");
10
10
  const loaders_1 = require("../../core/loaders");
11
11
  const convert_1 = require("../../core/convert");
12
12
  const action_1 = require("../../action");
@@ -40,7 +40,7 @@ class FakeContact {
40
40
  ];
41
41
  }
42
42
  static getTestTable() {
43
- return (0, test_db_1.table)("fake_contacts", (0, test_db_1.uuid)("id", { primaryKey: true }), (0, test_db_1.timestamptz)("created_at"), (0, test_db_1.timestamptz)("updated_at"), (0, test_db_1.text)("first_name"), (0, test_db_1.text)("last_name"), (0, test_db_1.text)("email_address"), (0, test_db_1.uuid)("user_id"));
43
+ return (0, temp_db_1.table)("fake_contacts", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"), (0, temp_db_1.text)("first_name"), (0, temp_db_1.text)("last_name"), (0, temp_db_1.text)("email_address"), (0, temp_db_1.uuid)("user_id"));
44
44
  }
45
45
  static loaderOptions() {
46
46
  return {
@@ -17,7 +17,7 @@ export declare class FakeEvent implements Ent {
17
17
  getPrivacyPolicy(): PrivacyPolicy<this>;
18
18
  constructor(viewer: Viewer, data: Data);
19
19
  private static getFields;
20
- static getTestTable(): import("../db/test_db").Table;
20
+ static getTestTable(): import("../db/temp_db").Table;
21
21
  static loaderOptions(): LoadEntOptions<FakeEvent>;
22
22
  static load(v: Viewer, id: ID): Promise<FakeEvent | null>;
23
23
  static loadX(v: Viewer, id: ID): Promise<FakeEvent>;
@@ -6,7 +6,7 @@ const privacy_1 = require("../../core/privacy");
6
6
  const builder_1 = require("../builder");
7
7
  const schema_1 = require("../../schema");
8
8
  const const_1 = require("./const");
9
- const test_db_1 = require("../db/test_db");
9
+ const temp_db_1 = require("../db/temp_db");
10
10
  const loaders_1 = require("../../core/loaders");
11
11
  const convert_1 = require("../../core/convert");
12
12
  const action_1 = require("../../action");
@@ -42,9 +42,9 @@ class FakeEvent {
42
42
  ];
43
43
  }
44
44
  static getTestTable() {
45
- return (0, test_db_1.table)("fake_events", (0, test_db_1.uuid)("id", { primaryKey: true }), (0, test_db_1.timestamptz)("created_at"), (0, test_db_1.timestamptz)("updated_at"),
45
+ return (0, temp_db_1.table)("fake_events", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"),
46
46
  // TODO index:true
47
- (0, test_db_1.timestamptz)("start_time"), (0, test_db_1.timestamptz)("end_time", { nullable: true }), (0, test_db_1.text)("location"), (0, test_db_1.text)("title"), (0, test_db_1.text)("description", { nullable: true }), (0, test_db_1.uuid)("user_id"));
47
+ (0, temp_db_1.timestamptz)("start_time"), (0, temp_db_1.timestamptz)("end_time", { nullable: true }), (0, temp_db_1.text)("location"), (0, temp_db_1.text)("title"), (0, temp_db_1.text)("description", { nullable: true }), (0, temp_db_1.uuid)("user_id"));
48
48
  }
49
49
  static loaderOptions() {
50
50
  return {
@@ -26,7 +26,7 @@ export declare class FakeUser implements Ent {
26
26
  getPrivacyPolicy(): PrivacyPolicy<this>;
27
27
  constructor(viewer: Viewer, data: Data);
28
28
  static getFields(): string[];
29
- static getTestTable(): import("../db/test_db").Table;
29
+ static getTestTable(): import("../db/temp_db").Table;
30
30
  static loaderOptions(): LoadEntOptions<FakeUser>;
31
31
  static load(v: Viewer, id: ID): Promise<FakeUser | null>;
32
32
  static loadX(v: Viewer, id: ID): Promise<FakeUser>;
@@ -8,7 +8,7 @@ const schema_1 = require("../../schema");
8
8
  const internal_1 = require("./internal");
9
9
  const const_1 = require("./const");
10
10
  const viewer_1 = require("../../core/viewer");
11
- const test_db_1 = require("../db/test_db");
11
+ const temp_db_1 = require("../db/temp_db");
12
12
  const loaders_1 = require("../../core/loaders");
13
13
  const convert_1 = require("../../core/convert");
14
14
  const action_1 = require("../../action");
@@ -74,7 +74,7 @@ class FakeUser {
74
74
  ];
75
75
  }
76
76
  static getTestTable() {
77
- return (0, test_db_1.table)("fake_users", (0, test_db_1.uuid)("id", { primaryKey: true }), (0, test_db_1.timestamptz)("created_at"), (0, test_db_1.timestamptz)("updated_at"), (0, test_db_1.text)("first_name"), (0, test_db_1.text)("last_name"), (0, test_db_1.text)("email_address"), (0, test_db_1.text)("phone_number"), (0, test_db_1.text)("password"));
77
+ return (0, temp_db_1.table)("fake_users", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"), (0, temp_db_1.text)("first_name"), (0, temp_db_1.text)("last_name"), (0, temp_db_1.text)("email_address"), (0, temp_db_1.text)("phone_number"), (0, temp_db_1.text)("password"));
78
78
  }
79
79
  static loaderOptions() {
80
80
  return {
@@ -1,6 +1,6 @@
1
1
  import { Data, Ent } from "../../core/base";
2
2
  import { AssocEdge } from "../../core/ent";
3
- import { TempDB } from "../db/test_db";
3
+ import { TempDB } from "../db/temp_db";
4
4
  import { FakeUser, UserCreateInput, ContactCreateInput, FakeContact } from ".";
5
5
  import { EventCreateInput, FakeEvent } from "./fake_event";
6
6
  import { BuilderSchema } from "../builder";
@@ -20,7 +20,7 @@ export declare function createEdges(): Promise<void>;
20
20
  export declare function edgeTableNames(): string[];
21
21
  export declare function createTestEvent(user: FakeUser, input?: Partial<EventCreateInput>): Promise<FakeEvent>;
22
22
  export declare function setupTempDB(): Promise<TempDB>;
23
- export declare function tempDBTables(): import("../db/test_db").Table[];
23
+ export declare function tempDBTables(global?: boolean): import("../db/temp_db").Table[];
24
24
  interface options {
25
25
  howMany: number;
26
26
  interval: number;
@@ -6,7 +6,7 @@ const viewer_1 = require("../../core/viewer");
6
6
  const ent_1 = require("../../core/ent");
7
7
  const snake_case_1 = require("snake-case");
8
8
  const write_1 = require("../write");
9
- const test_db_1 = require("../db/test_db");
9
+ const temp_db_1 = require("../db/temp_db");
10
10
  const _1 = require(".");
11
11
  const fake_event_1 = require("./fake_event");
12
12
  const const_1 = require("./const");
@@ -209,21 +209,21 @@ async function createTestEvent(user, input) {
209
209
  }
210
210
  exports.createTestEvent = createTestEvent;
211
211
  async function setupTempDB() {
212
- const tdb = new test_db_1.TempDB(tempDBTables());
212
+ const tdb = new temp_db_1.TempDB(tempDBTables());
213
213
  await tdb.beforeAll();
214
214
  // create once
215
215
  await createEdges();
216
216
  return tdb;
217
217
  }
218
218
  exports.setupTempDB = setupTempDB;
219
- function tempDBTables() {
219
+ function tempDBTables(global = false) {
220
220
  const tables = [
221
221
  _1.FakeUser.getTestTable(),
222
222
  _1.FakeContact.getTestTable(),
223
223
  fake_event_1.FakeEvent.getTestTable(),
224
- (0, test_db_1.assoc_edge_config_table)(),
224
+ (0, temp_db_1.assoc_edge_config_table)(),
225
225
  ];
226
- edgeTableNames().forEach((tableName) => tables.push((0, test_db_1.assoc_edge_table)(tableName)));
226
+ edgeTableNames().forEach((tableName) => tables.push((0, temp_db_1.assoc_edge_table)(tableName, global)));
227
227
  return tables;
228
228
  }
229
229
  exports.tempDBTables = tempDBTables;
@@ -307,6 +307,10 @@ function getOp(where, values) {
307
307
  return new AndOp([getOp(where.left, values), getOp(where.right, values)]);
308
308
  case "OR":
309
309
  return new OrOp([getOp(where.left, values), getOp(where.right, values)]);
310
+ case "IS":
311
+ if (where.right?.value === null) {
312
+ return new EqOp(getColumnFromRef(where.left), null);
313
+ }
310
314
  default:
311
315
  console.log(where);
312
316
  throw new Error(`unsupported op ${where.operator}`);
@@ -0,0 +1,15 @@
1
+ import { EdgeUpdateOperation, TransformedEdgeUpdateOperation } from "../schema";
2
+ import * as clause from "../core/clause";
3
+ import { AssocEdge } from "../core/ent";
4
+ import { Data } from "../core/base";
5
+ export declare class EdgeWithDeletedAt extends AssocEdge {
6
+ deletedAt: Date | null;
7
+ constructor(data: Data);
8
+ }
9
+ export declare const testEdgeGlobalSchema: {
10
+ extraEdgeFields: {
11
+ deletedAt: import("../schema").TimestampField;
12
+ };
13
+ transformEdgeRead(): clause.Clause;
14
+ transformEdgeWrite(stmt: EdgeUpdateOperation): TransformedEdgeUpdateOperation | null;
15
+ };