@coderich/autograph 0.12.0 → 0.13.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.
Files changed (56) hide show
  1. package/index.js +4 -6
  2. package/package.json +30 -44
  3. package/src/data/DataLoader.js +77 -70
  4. package/src/data/Emitter.js +89 -0
  5. package/src/data/Loader.js +33 -0
  6. package/src/data/Pipeline.js +84 -101
  7. package/src/data/Resolver.js +304 -0
  8. package/src/data/Transaction.js +49 -0
  9. package/src/query/Query.js +159 -335
  10. package/src/query/QueryBuilder.js +228 -114
  11. package/src/query/QueryResolver.js +110 -205
  12. package/src/query/QueryResolverTransaction.js +16 -0
  13. package/src/schema/Schema.js +602 -0
  14. package/src/service/AppService.js +38 -0
  15. package/src/service/ErrorService.js +7 -0
  16. package/CHANGELOG.md +0 -41
  17. package/LICENSE +0 -21
  18. package/README.md +0 -76
  19. package/src/.DS_Store +0 -0
  20. package/src/core/.DS_Store +0 -0
  21. package/src/core/Boom.js +0 -9
  22. package/src/core/EventEmitter.js +0 -95
  23. package/src/core/Resolver.js +0 -124
  24. package/src/core/Schema.js +0 -55
  25. package/src/core/ServerResolver.js +0 -15
  26. package/src/data/.DS_Store +0 -0
  27. package/src/data/DataService.js +0 -120
  28. package/src/data/DataTransaction.js +0 -161
  29. package/src/data/Field.js +0 -83
  30. package/src/data/Model.js +0 -214
  31. package/src/data/TreeMap.js +0 -78
  32. package/src/data/Type.js +0 -50
  33. package/src/driver/.DS_Store +0 -0
  34. package/src/driver/MongoDriver.js +0 -227
  35. package/src/driver/index.js +0 -11
  36. package/src/graphql/.DS_Store +0 -0
  37. package/src/graphql/ast/.DS_Store +0 -0
  38. package/src/graphql/ast/Field.js +0 -206
  39. package/src/graphql/ast/Model.js +0 -145
  40. package/src/graphql/ast/Node.js +0 -291
  41. package/src/graphql/ast/Schema.js +0 -133
  42. package/src/graphql/ast/Type.js +0 -26
  43. package/src/graphql/ast/TypeDefApi.js +0 -93
  44. package/src/graphql/extension/.DS_Store +0 -0
  45. package/src/graphql/extension/api.js +0 -193
  46. package/src/graphql/extension/framework.js +0 -71
  47. package/src/graphql/extension/type.js +0 -34
  48. package/src/query/.DS_Store +0 -0
  49. package/src/query/QueryBuilderTransaction.js +0 -26
  50. package/src/query/QueryService.js +0 -111
  51. package/src/service/.DS_Store +0 -0
  52. package/src/service/app.service.js +0 -319
  53. package/src/service/decorator.service.js +0 -114
  54. package/src/service/event.service.js +0 -66
  55. package/src/service/graphql.service.js +0 -92
  56. package/src/service/schema.service.js +0 -95
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 coderich
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/README.md DELETED
@@ -1,76 +0,0 @@
1
- # AutoGraph
2
- ### Instantly Build [Relay-Compliant](https://relay.dev/docs/en/graphql-server-specification.html) GraphQL APIs
3
-
4
- **AutoGraph** is a powerful **framework** to *instantly* build **Relay-Compliant GraphQL APIs** that adhere to *standards and best practice*. It provides a robust set of **directives** that encapsulates *data access*, *validation*, *transformations*, and so much more!
5
-
6
-
7
- #### Features
8
- - Instantly Connected Relay-Compliant GraphQL APIs
9
- - Extensible Validation & Transformation Logic
10
- - Unified Data Access / Abstraction Layer
11
- - Memoized Caching (via [DataLoader](https://www.npmjs.com/package/dataloader))
12
- - Transactions, Pagination, and more!
13
-
14
- #### Installation
15
-
16
- ```sh
17
- npm i @coderich/autograph --save
18
- ```
19
-
20
- ## Schema API
21
- #### Custom Types
22
- ```gql
23
- scalar AutoGraphMixed
24
- enum AutoGraphScopeEnum { private protected public restricted }
25
- enum AutoGraphOnDeleteEnum { cascade nullify restrict }
26
- enum AutoGraphIndexEnum { unique }
27
- ```
28
- #### Custom Directives
29
- ##### @model
30
- | arg | type | description |
31
- | :--- | :--- | :--- |
32
- | `id` | `String` | Specify database id field name (default: `id`)
33
- | `meta` | `String` | Define a model
34
- | `alias` | `String` | Specify database table name (default models's name)
35
- | `scope` | `AutoGraphScopeEnum` | Access scope for this model (default `protected`)
36
- | `driver` | `String` | Specify database driver (default `default`)
37
- | `namespace` | `String` | Define a custom namespace
38
- | `createdAt` | `String` | TBD
39
- | `updatedAt` | `String` | TBD
40
-
41
- ##### @field
42
- | arg | type | description |
43
- | :--- | :--- | :--- |
44
- | `alias` | `String` | Specify database field name (default field's name)
45
- | `scope` | `AutoGraphScopeEnum` | Access scope for this field (default `protected`)
46
- | `enforce` | `[AutoGraphEnforceEnum!]` | List of `Rules` to enforce
47
- | `noRepeat` | `Boolean` | TBD
48
- | `onDelete` | `AutoGraphOnDeleteEnum` | Specify *onDelete* behavior
49
- | `transform` | `[AutoGraphTransformEnum!]` | List of `Transformers` to apply
50
- | `materializeBy` | `String` | Define a virtual field
51
-
52
- ##### @index
53
- | arg | type | description |
54
- | :--- | :--- | :--- |
55
- | `on` | `[String!]!` | The field names to use for this index
56
- | `type` | `AutoGraphIndexEnum!` | The type of index to create
57
- | `name` | `String` | The name of the index
58
-
59
- ## Data API
60
- #### Data Access
61
- #### Data Validation
62
- #### Data Transformation
63
-
64
-
65
- Each `Resolver` treats your schema definition as a *graph of connected nodes*. To begin a *query* or *mutation*, you must first identify a node in the graph as your starting point.
66
-
67
- ##### .match
68
- Identify a node, returns a `QueryBuilder`.
69
- ```
70
- const queryBuilder = resolver.match('Person');
71
- ```
72
- ##### .transaction
73
- Identify a node, returns a `Transaction`.
74
- ```
75
- const txn = resolver.transaction('Person');
76
- ```
package/src/.DS_Store DELETED
Binary file
Binary file
package/src/core/Boom.js DELETED
@@ -1,9 +0,0 @@
1
- const Boom = require('@hapi/boom');
2
-
3
- /**
4
- * Boom.
5
- *
6
- * Standardizing how known/expected errors are thrown (such as Rule validation errors). This allows
7
- * upstream applications to more easily decide what to show to end-users and what to hide.
8
- */
9
- module.exports = Boom;
@@ -1,95 +0,0 @@
1
- const EventEmitter = require('events');
2
- const { ensureArray } = require('../service/app.service');
3
-
4
- /**
5
- * EventEmitter.
6
- *
7
- * The difference is that I'm looking at each raw listeners to determine how many arguments it's expecting.
8
- * If it expects more than 1 we block and wait for it to finish.
9
- */
10
- module.exports = class extends EventEmitter {
11
- emit(event, data) {
12
- return Promise.all(this.rawListeners(event).map((wrapper) => {
13
- return new Promise((resolve, reject) => {
14
- const next = result => resolve(result); // If a result is passed this will bypass middleware thunk()
15
- const numArgs = (wrapper.listener || wrapper).length;
16
- Promise.resolve(wrapper(data, next)).catch(e => reject(e));
17
- if (numArgs < 2) next();
18
- });
19
- })).then((results) => {
20
- return results.find(r => r !== undefined); // There can be only one (result)
21
- });
22
- }
23
-
24
- /**
25
- * Syntactic sugar to listen on keys
26
- */
27
- onKeys(on, keys, fn) {
28
- const numArgs = fn.length;
29
-
30
- return super.on(on, async (event, next) => {
31
- const { key } = event;
32
-
33
- if (ensureArray(keys).indexOf(key) > -1) {
34
- await fn(event, next);
35
- if (numArgs < 2) next();
36
- } else {
37
- next();
38
- }
39
- });
40
- }
41
-
42
- /**
43
- * Syntactic sugar to listen once keys
44
- */
45
- onceKeys(once, keys, fn) {
46
- const numArgs = fn.length;
47
-
48
- return super.once(once, async (event, next) => {
49
- const { key } = event;
50
-
51
- if (ensureArray(keys).indexOf(key) > -1) {
52
- await fn(event, next);
53
- if (numArgs < 2) next();
54
- } else {
55
- next();
56
- }
57
- });
58
- }
59
-
60
- /**
61
- * Syntactic sugar to listen on models
62
- */
63
- onModels(on, models, fn) {
64
- const numArgs = fn.length;
65
-
66
- return super.on(on, async (event, next) => {
67
- const { model } = event;
68
-
69
- if (ensureArray(models).indexOf(`${model}`) > -1) {
70
- await fn(event, next);
71
- if (numArgs < 2) next();
72
- } else {
73
- next();
74
- }
75
- });
76
- }
77
-
78
- /**
79
- * Syntactic sugar to listen once models
80
- */
81
- onceModels(once, models, fn) {
82
- const numArgs = fn.length;
83
-
84
- return super.once(once, async (event, next) => {
85
- const { model } = event;
86
-
87
- if (ensureArray(models).indexOf(`${model}`) > -1) {
88
- await fn(event, next);
89
- if (numArgs < 2) next();
90
- } else {
91
- next();
92
- }
93
- });
94
- }
95
- };
@@ -1,124 +0,0 @@
1
- const Model = require('../data/Model');
2
- const DataLoader = require('../data/DataLoader');
3
- const DataTransaction = require('../data/DataTransaction');
4
- const Query = require('../query/Query');
5
- const QueryBuilder = require('../query/QueryBuilder');
6
- const { finalizeResults } = require('../data/DataService');
7
- const { createSystemEvent } = require('../service/event.service');
8
-
9
- module.exports = class Resolver {
10
- constructor(schema, context = {}) {
11
- this.schema = schema;
12
- this.context = context;
13
- this.models = schema.getModels();
14
- this.loaders = this.models.reduce((prev, model) => prev.set(`${model}`, new DataLoader(this, model)), new Map());
15
- }
16
-
17
- getSchema() {
18
- return this.schema;
19
- }
20
-
21
- getContext() {
22
- return this.context;
23
- }
24
-
25
- /**
26
- * Creates and returns a QueryBuilder for a given model
27
- */
28
- match(model) {
29
- return new QueryBuilder(this, this.toModelEntity(model));
30
- }
31
-
32
- /**
33
- * Returns a user-defined Map (repository) of custom named queries.
34
- */
35
- named(model) {
36
- return this.toModel(model).getNamedQueries();
37
- }
38
-
39
- /**
40
- * Returns the raw client driver associated with the model.
41
- */
42
- raw(model) {
43
- return this.toModelEntity(model).raw();
44
- }
45
-
46
- /**
47
- * Creates and returns a Transaction to run multiple queries
48
- */
49
- transaction(parentTxn) {
50
- return new DataTransaction(this, parentTxn);
51
- }
52
-
53
- disconnect(model) {
54
- return this.toModelEntity(model).getDriver().disconnect();
55
- }
56
-
57
- resolve(query) {
58
- const { model, crud, method } = query.toObject();
59
-
60
- switch (crud) {
61
- case 'create': case 'update': case 'delete': {
62
- return model.getDriver().resolve(query.toDriver()).then((data) => {
63
- this.clear(model);
64
- const rs = model.shapeObject(model.getShape(), data, query);
65
- return finalizeResults(rs, query);
66
- });
67
- }
68
- default: {
69
- const key = model.idKey();
70
- const { where } = query.toDriver();
71
- const lookupValue = where[key];
72
-
73
- // This is a shortcut to prevent making unnecessary query
74
- if (Object.prototype.hasOwnProperty.call(where, key) && (lookupValue == null || (Array.isArray(lookupValue) && lookupValue.length === 0))) {
75
- switch (method) {
76
- case 'count': return Promise.resolve(0);
77
- case 'findMany': return Promise.resolve([]);
78
- default: return Promise.resolve(null);
79
- }
80
- }
81
-
82
- // Go through DataLoader to cache results
83
- return this.loaders.get(`${model}`).load(query);
84
- }
85
- }
86
- }
87
-
88
- toModel(model) {
89
- return model instanceof Model ? model : this.schema.getModel(model);
90
- }
91
-
92
- toModelMarked(model) {
93
- const marked = this.toModel(model);
94
- if (!marked) throw new Error(`${model} is not defined in schema`);
95
- if (!marked.isMarkedModel()) throw new Error(`${model} is not a marked model`);
96
- return marked;
97
- }
98
-
99
- toModelEntity(model) {
100
- const entity = this.toModel(model);
101
- if (!entity) throw new Error(`${model} is not defined in schema`);
102
- if (!entity.isEntity()) throw new Error(`${model} is not an entity`);
103
- return entity;
104
- }
105
-
106
- toResultSet(model, data, method) {
107
- model = this.toModel(model);
108
- const query = new Query({ model, resolver: this, context: this.context, method });
109
- const result = model.deserialize(data, query);
110
- const event = { result, query, ...query.doc(result).merged(result).toObject() };
111
- return createSystemEvent('Response', event, () => result);
112
- }
113
-
114
- // DataLoader Proxy Methods
115
- clear(model) {
116
- this.loaders.get(`${model}`).clearAll();
117
- return this;
118
- }
119
-
120
- clearAll() {
121
- this.models.forEach(model => this.clear(model));
122
- return this;
123
- }
124
- };
@@ -1,55 +0,0 @@
1
- const Model = require('../data/Model');
2
- const Schema = require('../graphql/ast/Schema');
3
- const { identifyOnDeletes } = require('../service/schema.service');
4
- const { eventEmitter } = require('../service/event.service');
5
-
6
- // Export class
7
- module.exports = class extends Schema {
8
- constructor(schema, stores) {
9
- super(schema);
10
-
11
- // Create drivers
12
- this.drivers = Object.entries(stores).reduce((prev, [key, value]) => {
13
- const { Driver } = value;
14
-
15
- return Object.assign(prev, {
16
- [key]: {
17
- dao: new Driver(value, this),
18
- idKey: Driver.idKey,
19
- idValue: Driver.idValue,
20
- },
21
- });
22
- }, {});
23
- }
24
-
25
- setup() {
26
- return eventEmitter.emit('setup', this).then(() => {
27
- const entities = this.models.filter(m => m.isEntity());
28
-
29
- // Create model indexes
30
- return Promise.all(entities.map(async (model) => {
31
- const key = model.getKey();
32
- const indexes = model.getIndexes();
33
- const driver = model.getDriver();
34
- if (driver.createCollection) await driver.createCollection(key);
35
- return driver.createIndexes(key, indexes);
36
- }));
37
- });
38
- }
39
-
40
- disconnect() {
41
- return Promise.all(Object.values(this.drivers).map(({ dao }) => dao.disconnect()));
42
- }
43
-
44
- initialize() {
45
- super.initialize();
46
- this.models = super.getModels().map(model => new Model(this, model, this.drivers[model.getDriverName()]));
47
- return this;
48
- }
49
-
50
- finalize() {
51
- super.finalize();
52
- this.models.forEach(model => model.referentialIntegrity(identifyOnDeletes(this.models, model)));
53
- return this;
54
- }
55
- };
@@ -1,15 +0,0 @@
1
- const { unrollGuid, guidToId } = require('../service/app.service');
2
-
3
- module.exports = class ServerResolver {
4
- constructor() {
5
- // Queries
6
- this.get = ({ autograph }, model, { id: guid }, required = false, query) => autograph.resolver.match(model).id(guidToId(autograph, guid)).select(query.fields).one({ required });
7
- this.query = ({ autograph }, model, args, query) => autograph.resolver.match(model).select(query.fields).merge(args).many();
8
- this.count = ({ autograph }, model, args, query) => autograph.resolver.match(model).merge(args).count();
9
-
10
- // Mutations
11
- this.create = ({ autograph }, model, { input, meta }, query) => autograph.resolver.match(model).select(query.fields).meta(meta).save(unrollGuid(autograph, model, input));
12
- this.delete = ({ autograph }, model, { id: guid, meta }, query) => autograph.resolver.match(model).id(guidToId(autograph, guid)).select(query.fields).meta(meta).remove();
13
- this.update = ({ autograph }, model, { id: guid, meta, input }, query) => autograph.resolver.match(model).id(guidToId(autograph, guid)).select(query.fields).meta(meta).save(unrollGuid(autograph, model, input));
14
- }
15
- };
Binary file
@@ -1,120 +0,0 @@
1
- const { get, remove } = require('lodash');
2
- const { map, isPlainObject, objectContaining, mergeDeep, ensureArray, keyPaths } = require('../service/app.service');
3
-
4
- exports.finalizeResults = (rs, query) => {
5
- const { model, resolver } = query.toObject();
6
-
7
- return map(exports.paginateResults(rs, query), (doc) => {
8
- return Object.defineProperties(doc, {
9
- $model: { value: model },
10
- $save: { value: input => resolver.match(model).id(doc.id).save({ ...doc, ...input }) },
11
- $remove: { value: (...args) => resolver.match(model).id(doc.id).remove(...args) },
12
- $delete: { value: (...args) => resolver.match(model).id(doc.id).delete(...args) },
13
- $lookup: { value: (fieldName, args) => model.getFieldByName(fieldName).resolve(resolver, doc, args) },
14
- // $resolve: { value: (fieldName, args) => model.getFieldByName(fieldName).resolve(resolver, doc, args) },
15
- });
16
- });
17
- };
18
-
19
- /**
20
- * This is cursor-style pagination only
21
- * You add 2 extra records to the result in order to determine previous/next
22
- */
23
- exports.paginateResults = (rs, query) => {
24
- const { first, after, last, before, sort } = query.toObject();
25
- const isPaginating = Boolean(first || last || after || before);
26
-
27
- // Return right away if not paginating
28
- if (!isPaginating) return rs;
29
-
30
- let hasNextPage = false;
31
- let hasPreviousPage = false;
32
- const limiter = first || last;
33
- const sortPaths = keyPaths(sort);
34
-
35
- // Add $cursor data
36
- map(rs, (doc) => {
37
- const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(doc, path) }), {});
38
- Object.defineProperty(doc, '$cursor', { get() { return Buffer.from(JSON.stringify(sortValues)).toString('base64'); } });
39
- });
40
-
41
- // First try to take off the "bookends" ($gte | $lte)
42
- if (rs.length && rs[0].$cursor === after) {
43
- rs.shift();
44
- hasPreviousPage = true;
45
- }
46
-
47
- if (rs.length && rs[rs.length - 1].$cursor === before) {
48
- rs.pop();
49
- hasNextPage = true;
50
- }
51
-
52
- // Next, remove any overage
53
- const overage = rs.length - (limiter - 2);
54
-
55
- if (overage > 0) {
56
- if (first) {
57
- rs.splice(-overage);
58
- hasNextPage = true;
59
- } else if (last) {
60
- rs.splice(0, overage);
61
- hasPreviousPage = true;
62
- } else {
63
- rs.splice(-overage);
64
- hasNextPage = true;
65
- }
66
- }
67
-
68
- // Add $pageInfo
69
- return Object.defineProperties(rs, {
70
- $pageInfo: {
71
- get() {
72
- return {
73
- startCursor: get(rs, '0.$cursor', ''),
74
- endCursor: get(rs, `${rs.length - 1}.$cursor`, ''),
75
- hasPreviousPage,
76
- hasNextPage,
77
- };
78
- },
79
- },
80
- });
81
- };
82
-
83
- exports.spliceEmbeddedArray = (array, from, to) => {
84
- const op = from && to ? 'edit' : (from ? 'pull' : 'push'); // eslint-disable-line no-nested-ternary
85
-
86
- // Convenience so the user does not have to explicity type out the same value over and over to replace
87
- if (from && from.length > 1 && to && to.length === 1) to = Array.from(from).fill(to[0]);
88
-
89
- switch (op) {
90
- case 'edit': {
91
- array.forEach((el, j) => {
92
- ensureArray(from).forEach((val, k) => {
93
- if (objectContaining(el, val)) array[j] = isPlainObject(el) ? mergeDeep(el, ensureArray(to)[k]) : ensureArray(to)[k];
94
- });
95
- });
96
- break;
97
- }
98
- // case 'edit': {
99
- // ensureArray(from).forEach((f, i) => {
100
- // const t = ensureArray(to)[i];
101
- // const indexes = array.map((el, j) => (el === f ? j : -1)).filter(index => index !== -1);
102
- // indexes.forEach(index => (array[index] = t));
103
- // });
104
- // break;
105
- // }
106
- case 'push': {
107
- array.push(...to);
108
- break;
109
- }
110
- case 'pull': {
111
- remove(array, el => from.find(val => objectContaining(el, val)));
112
- break;
113
- }
114
- default: {
115
- break;
116
- }
117
- }
118
-
119
- return array;
120
- };
@@ -1,161 +0,0 @@
1
- const { flatten } = require('lodash');
2
- const TreeMap = require('./TreeMap');
3
- const QueryBuilderTransaction = require('../query/QueryBuilderTransaction');
4
-
5
- module.exports = class DataTransaction {
6
- constructor(resolver, parentTxn) {
7
- const txnMap = (parentTxn || {}).txnMap || (() => {
8
- let resolve, reject;
9
- const map = new TreeMap();
10
- map.promise = new Promise((good, bad) => { resolve = good; reject = bad; });
11
- map.resolve = resolve;
12
- map.reject = reject;
13
-
14
- map.ready = () => {
15
- const elements = map.elements();
16
- const notReady = elements.filter(el => !el.marker);
17
- if (notReady.length) return [undefined, undefined];
18
- let rollbackIndex = elements.findIndex(el => el.marker === 'rollback');
19
- if (rollbackIndex === -1) rollbackIndex = Infinity;
20
- return [elements.slice(0, rollbackIndex), elements.slice(rollbackIndex)];
21
- };
22
-
23
- map.perform = () => {
24
- const [commits, rollbacks] = map.ready();
25
-
26
- if (commits && rollbacks) {
27
- const rollbackData = flatten(rollbacks.map(tnx => tnx.data));
28
- const commitData = flatten(commits.map(tnx => tnx.data));
29
-
30
- Promise.all(rollbackData.map(rbd => rbd.$rollback())).then(() => {
31
- if (commits.length) resolver.clearAll();
32
- Promise.all(commitData.map(cd => cd.$commit())).then(d => map.resolve(d));
33
- }).catch(e => map.reject(e));
34
- }
35
-
36
- return map.promise;
37
- };
38
-
39
- return map;
40
- })();
41
-
42
- // Create txn
43
- const txn = ((data, driverMap, txMap) => {
44
- return {
45
- get match() {
46
- return (modelName) => {
47
- const model = resolver.toModelMarked(modelName);
48
- const driver = model.getDriver();
49
- if (!driverMap.has(driver)) driverMap.set(driver, []);
50
- const op = new QueryBuilderTransaction(resolver, model, this);
51
- driverMap.get(driver).push(op);
52
- return op;
53
- };
54
- },
55
- get exec() {
56
- return () => {
57
- return Promise.all(Array.from(driverMap.entries()).map(([driver, ops]) => {
58
- if (driver.getDirectives().transactions === false) {
59
- return Promise.all(ops.map(op => op.exec())).then((results) => {
60
- results.$commit = () => resolver.clearAll();
61
- results.$rollback = () => resolver.clearAll();
62
- return results;
63
- });
64
- }
65
-
66
- return driver.transaction(ops);
67
- })).then((results) => {
68
- data = results;
69
- return flatten(results);
70
- });
71
- };
72
- },
73
- get run() {
74
- return () => {
75
- return this.exec().then((results) => {
76
- if (txMap.root(this) === this) return this.commit().then(() => results);
77
- this.commit();
78
- return results;
79
- }).catch((e) => {
80
- if (txMap.root(this) === this) return this.rollback().then(() => Promise.reject(e));
81
- this.rollback();
82
- throw e;
83
- });
84
- };
85
- },
86
- get commit() {
87
- return () => {
88
- if (this.marker !== 'rollback') this.marker = 'commit';
89
- return txMap.perform();
90
- };
91
- },
92
- get rollback() {
93
- return () => {
94
- this.marker = 'rollback';
95
- return txMap.perform();
96
- };
97
- },
98
- get data() {
99
- return data;
100
- },
101
- get txnMap() {
102
- return txMap;
103
- },
104
- };
105
- })([], new Map(), txnMap);
106
-
107
- // Save txn to map
108
- txnMap.add(parentTxn, txn);
109
-
110
- // Return to caller
111
- return txn;
112
- }
113
-
114
- // match(modelish) {
115
- // const model = this.resolver.toModelMarked(modelish);
116
- // const driver = model.getDriver();
117
- // if (!this.driverMap.has(driver)) this.driverMap.set(driver, []);
118
- // const op = new QueryBuilderTransaction(model, this.resolver, this);
119
- // this.driverMap.get(driver).push(op);
120
- // return op;
121
- // }
122
-
123
- // exec() {
124
- // return Promise.all(Array.from(this.driverMap.entries()).map(([driver, ops]) => {
125
- // if (driver.getDirectives().transactions === false) {
126
- // return Promise.all(ops.map(op => op.exec())).then((results) => {
127
- // results.$commit = () => this.resolver.clearAll();
128
- // results.$rollback = () => this.resolver.clearAll();
129
- // return results;
130
- // });
131
- // }
132
-
133
- // return driver.transaction(ops);
134
- // })).then((results) => {
135
- // this.data = results;
136
- // return flatten(results);
137
- // });
138
- // }
139
-
140
- // run() {
141
- // return this.exec().then((results) => {
142
- // if (this.txMap.root(this) === this) return this.commit().then(() => results);
143
- // this.commit();
144
- // return results;
145
- // }).catch((e) => {
146
- // if (this.txMap.root(this) === this) return this.rollback().then(() => Promise.reject(e));
147
- // this.rollback();
148
- // throw e;
149
- // });
150
- // }
151
-
152
- // commit() {
153
- // if (this.marker !== 'rollback') this.marker = 'commit';
154
- // return this.txMap.perform();
155
- // }
156
-
157
- // rollback() {
158
- // this.marker = 'rollback';
159
- // return this.txMap.perform();
160
- // }
161
- };