mythix-orm 1.0.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 (124) hide show
  1. package/.eslintrc.js +94 -0
  2. package/.vscode/launch.json +34 -0
  3. package/.vscode/settings.json +10 -0
  4. package/LICENSE +21 -0
  5. package/README.md +15 -0
  6. package/lib/connection/connection-base.js +877 -0
  7. package/lib/connection/index.js +11 -0
  8. package/lib/connection/literals/average-literal.js +14 -0
  9. package/lib/connection/literals/count-literal.js +18 -0
  10. package/lib/connection/literals/distinct-literal.js +14 -0
  11. package/lib/connection/literals/index.js +23 -0
  12. package/lib/connection/literals/literal-base.js +62 -0
  13. package/lib/connection/literals/literal-field-base.js +45 -0
  14. package/lib/connection/literals/literal.js +11 -0
  15. package/lib/connection/literals/max-literal.js +14 -0
  16. package/lib/connection/literals/min-literal.js +14 -0
  17. package/lib/connection/literals/sum-literal.js +14 -0
  18. package/lib/connection/query-generator-base.js +864 -0
  19. package/lib/errors/base-error.js +14 -0
  20. package/lib/errors/connection/access-denied-error.js +13 -0
  21. package/lib/errors/connection/connection-acquire-timeout-error.js +13 -0
  22. package/lib/errors/connection/connection-refused-error.js +13 -0
  23. package/lib/errors/connection/connection-timed-out-error.js +13 -0
  24. package/lib/errors/connection/host-not-found-error.js +13 -0
  25. package/lib/errors/connection/host-not-reachable-error.js +13 -0
  26. package/lib/errors/connection/index.js +19 -0
  27. package/lib/errors/connection/invalid-connection-error.js +13 -0
  28. package/lib/errors/connection-base-error.js +13 -0
  29. package/lib/errors/database/exclusion-constraint-error.js +13 -0
  30. package/lib/errors/database/foreign-key-constraint-error.js +13 -0
  31. package/lib/errors/database/index.js +13 -0
  32. package/lib/errors/database/timeout-error.js +13 -0
  33. package/lib/errors/database/unknown-constraint-error.js +13 -0
  34. package/lib/errors/database-base-error.js +17 -0
  35. package/lib/errors/index.js +44 -0
  36. package/lib/field.js +18 -0
  37. package/lib/index.js +43 -0
  38. package/lib/model.js +1374 -0
  39. package/lib/proxy-class/index.js +3 -0
  40. package/lib/proxy-class/proxy-class.js +269 -0
  41. package/lib/query-engine/field-scope.js +99 -0
  42. package/lib/query-engine/index.js +13 -0
  43. package/lib/query-engine/model-scope.js +198 -0
  44. package/lib/query-engine/query-engine-base.js +325 -0
  45. package/lib/query-engine/query-engine.js +212 -0
  46. package/lib/types/concrete/bigint-type.js +62 -0
  47. package/lib/types/concrete/blob-type.js +46 -0
  48. package/lib/types/concrete/boolean-type.js +41 -0
  49. package/lib/types/concrete/char-type.js +39 -0
  50. package/lib/types/concrete/date-type.js +87 -0
  51. package/lib/types/concrete/datetime-type.js +92 -0
  52. package/lib/types/concrete/float-type.js +47 -0
  53. package/lib/types/concrete/foreign-key-type.js +208 -0
  54. package/lib/types/concrete/index.js +53 -0
  55. package/lib/types/concrete/integer-type.js +51 -0
  56. package/lib/types/concrete/string-type.js +44 -0
  57. package/lib/types/concrete/text-type.js +44 -0
  58. package/lib/types/concrete/uuid-base.js +77 -0
  59. package/lib/types/concrete/uuid-v1-type.js +99 -0
  60. package/lib/types/concrete/uuid-v3-type.js +108 -0
  61. package/lib/types/concrete/uuid-v4-type.js +90 -0
  62. package/lib/types/concrete/uuid-v5-type.js +108 -0
  63. package/lib/types/concrete/xid-type.js +58 -0
  64. package/lib/types/helpers/default-helpers.js +127 -0
  65. package/lib/types/helpers/index.js +35 -0
  66. package/lib/types/index.js +94 -0
  67. package/lib/types/type.js +244 -0
  68. package/lib/types/virtual/index.js +14 -0
  69. package/lib/types/virtual/model-type.js +141 -0
  70. package/lib/types/virtual/models-type.js +264 -0
  71. package/lib/types/virtual/relational-type-base.js +323 -0
  72. package/lib/utils/index.js +65 -0
  73. package/lib/utils/misc-utils.js +73 -0
  74. package/lib/utils/model-utils.js +704 -0
  75. package/lib/utils/query-utils.js +186 -0
  76. package/package.json +63 -0
  77. package/playground/test01.js +15 -0
  78. package/spec/connection/connection-base-spec.js +126 -0
  79. package/spec/connection/literals/average-literal-spec.js +45 -0
  80. package/spec/connection/literals/count-literal-spec.js +42 -0
  81. package/spec/connection/literals/distinct-literal-spec.js +42 -0
  82. package/spec/connection/literals/literal-spec.js +26 -0
  83. package/spec/connection/literals/max-literal-spec.js +42 -0
  84. package/spec/connection/literals/min-literal-spec.js +42 -0
  85. package/spec/connection/literals/sum-literal-spec.js +42 -0
  86. package/spec/helpers/default-helpers-spec.js +108 -0
  87. package/spec/model-spec.js +736 -0
  88. package/spec/proxy-class/proxy-class-spec.js +173 -0
  89. package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_chain_query_conditions-001.snapshot +94 -0
  90. package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_call-001.snapshot +35 -0
  91. package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_construct_a_query_context_with_a_model_sub-001.snapshot +35 -0
  92. package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_set_a_default_scope_on_a_model-001.snapshot +57 -0
  93. package/spec/query-engine/__snapshots__/QueryEngine-operations-query_operations_and_chaining-can_unscope_default_scope_on_a_model-001.snapshot +35 -0
  94. package/spec/query-engine/query-engine-spec.js +99 -0
  95. package/spec/support/jasmine.json +13 -0
  96. package/spec/support/models/blob-test-model.js +19 -0
  97. package/spec/support/models/extended-user-model.js +38 -0
  98. package/spec/support/models/index.js +27 -0
  99. package/spec/support/models/number-model.js +24 -0
  100. package/spec/support/models/role-model.js +26 -0
  101. package/spec/support/models/role-thing-model.js +41 -0
  102. package/spec/support/models/scoped-user-model.js +13 -0
  103. package/spec/support/models/time-model.js +36 -0
  104. package/spec/support/models/user-model.js +70 -0
  105. package/spec/support/models/user-role-model.js +36 -0
  106. package/spec/support/models/user-thing-model.js +46 -0
  107. package/spec/support/models/validation-test-model.js +40 -0
  108. package/spec/support/snapshots.js +293 -0
  109. package/spec/support/test-helpers.js +13 -0
  110. package/spec/types/concrete/bigint-type-spec.js +84 -0
  111. package/spec/types/concrete/boolean-type-spec.js +83 -0
  112. package/spec/types/concrete/date-type-spec.js +85 -0
  113. package/spec/types/concrete/datetime-type-spec.js +87 -0
  114. package/spec/types/concrete/float-type-spec.js +71 -0
  115. package/spec/types/concrete/foreign-key-type-spec.js +64 -0
  116. package/spec/types/concrete/integer-type-spec.js +71 -0
  117. package/spec/types/concrete/string-type-spec.js +91 -0
  118. package/spec/types/concrete/uuid-v1-type-spec.js +73 -0
  119. package/spec/types/concrete/uuid-v4-type-spec.js +65 -0
  120. package/spec/types/type-spec.js +101 -0
  121. package/spec/types/virtual/model-types-spec.js +401 -0
  122. package/spec/utils/misc-utils-spec.js +61 -0
  123. package/spec/utils/model-utils-spec.js +55 -0
  124. package/spec/utils/query-utils-spec.js +105 -0
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class RoleThing extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.UUIDV4,
9
+ defaultValue: Types.UUIDV4.Default.UUIDV4,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'roleID': {
14
+ type: Types.FOREIGN_KEY('Role:id', { onDelete: 'CASCADE', onUpdate: 'CASCADE' }),
15
+ allowNull: true,
16
+ index: true,
17
+ },
18
+ 'userThing': {
19
+ type: Types.Model('UserThing', ({ UserThing, userQuery, self }) => {
20
+ return UserThing.$.roleThingID.EQ(self.id).MERGE(userQuery);
21
+ }),
22
+ },
23
+ 'role': {
24
+ type: Types.Model('Role', ({ Role, userQuery, self }) => {
25
+ return Role.$.id.EQ(self.roleID).MERGE(userQuery);
26
+ }),
27
+ },
28
+ 'user': {
29
+ type: Types.Model('User', ({ UserThing, User, userQuery, self }) => {
30
+ return User
31
+ .$.id
32
+ .EQ(UserThing.userID)
33
+ .UserThing.roleThingID
34
+ .EQ(self.id)
35
+ .MERGE(userQuery);
36
+ }),
37
+ },
38
+ };
39
+ }
40
+
41
+ module.exports = RoleThing;
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const User = require('./user-model');
4
+
5
+ class ScopedUser extends User {
6
+ static fields = User.mergeFields();
7
+
8
+ static defaultScope(queryEngine) {
9
+ return queryEngine.firstName.EQ('Bob');
10
+ }
11
+ }
12
+
13
+ module.exports = ScopedUser;
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class Time extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.XID,
9
+ defaultValue: Types.XID.Default.XID,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'datetime': {
14
+ type: Types.DATETIME,
15
+ defaultValue: Types.DATETIME.Default.NOW,
16
+ index: true,
17
+ },
18
+ 'datetimeLocal': {
19
+ type: Types.DATETIME,
20
+ defaultValue: Types.DATETIME.Default.NOW.LOCAL,
21
+ index: true,
22
+ },
23
+ 'date': {
24
+ type: Types.DATE,
25
+ defaultValue: Types.DATE.Default.NOW,
26
+ index: true,
27
+ },
28
+ 'dateLocal': {
29
+ type: Types.DATE,
30
+ defaultValue: Types.DATE.Default.NOW.LOCAL,
31
+ index: true,
32
+ },
33
+ };
34
+ }
35
+
36
+ module.exports = Time;
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class User extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.UUIDV4,
9
+ defaultValue: Types.UUIDV4.Default.UUIDV4,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'firstName': {
14
+ type: Types.STRING(64),
15
+ allowNull: true,
16
+ index: true,
17
+ },
18
+ 'lastName': {
19
+ type: Types.STRING(64),
20
+ allowNull: true,
21
+ index: true,
22
+ },
23
+ 'primaryRoleID': {
24
+ type: Types.FOREIGN_KEY('Role:id', { onDelete: 'SET NULL', onUpdate: 'SET NULL' }),
25
+ allowNull: true,
26
+ },
27
+ 'roles': {
28
+ type: Types.Models('Role', ({ Role, UserRole, userQuery, self }) => {
29
+ return Role
30
+ .$.id
31
+ .EQ(UserRole.$.roleID)
32
+ .UserRole.userID
33
+ .EQ(self.id)
34
+ .MERGE(userQuery);
35
+ }),
36
+ },
37
+ 'userRoles': {
38
+ type: Types.Models('UserRole', ({ UserRole, userQuery, self }) => {
39
+ return UserRole.$.userID.EQ(self.id).MERGE(userQuery);
40
+ }),
41
+ },
42
+ 'userThing': {
43
+ type: Types.Model('UserThing', ({ UserThing, userQuery, self }) => {
44
+ return UserThing
45
+ .$.userID
46
+ .EQ(self.id)
47
+ .MERGE(userQuery);
48
+ }),
49
+ },
50
+ 'userThingRole': {
51
+ type: Types.Model('Role', ({ Role, UserThing, RoleThing, userQuery, self }) => {
52
+ return Role
53
+ .$.id
54
+ .EQ(RoleThing.$.roleID)
55
+ .RoleThing.id
56
+ .EQ(UserThing.$.roleThingID)
57
+ .UserThing.userID
58
+ .EQ(self.id)
59
+ .MERGE(userQuery);
60
+ }),
61
+ },
62
+ 'primaryRole': {
63
+ type: Types.Model('Role', ({ Role, userQuery, self }) => {
64
+ return Role.$.id.EQ(self.primaryRoleID).MERGE(userQuery);
65
+ }),
66
+ },
67
+ };
68
+ }
69
+
70
+ module.exports = User;
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class UserRole extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.UUIDV4,
9
+ defaultValue: Types.UUIDV4.Default.UUIDV4,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'roleID': {
14
+ type: Types.FOREIGN_KEY('Role:id', { onDelete: 'CASCADE', onUpdate: 'CASCADE' }),
15
+ allowNull: false,
16
+ index: true,
17
+ },
18
+ 'userID': {
19
+ type: Types.FOREIGN_KEY('User:id', { onDelete: 'CASCADE', onUpdate: 'CASCADE' }),
20
+ allowNull: false,
21
+ index: true,
22
+ },
23
+ 'role': {
24
+ type: Types.Model('Role', ({ Role, userQuery, self }) => {
25
+ return Role.$.id.EQ(self.roleID).MERGE(userQuery);
26
+ }),
27
+ },
28
+ 'user': {
29
+ type: Types.Model('User', ({ User, userQuery, self }) => {
30
+ return User.$.id.EQ(self.userID).MERGE(userQuery);
31
+ }),
32
+ },
33
+ };
34
+ }
35
+
36
+ module.exports = UserRole;
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class UserThing extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.UUIDV4,
9
+ defaultValue: Types.UUIDV4.Default.UUIDV4,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'userID': {
14
+ type: Types.FOREIGN_KEY('User:id', { onDelete: 'CASCADE', onUpdate: 'CASCADE' }),
15
+ allowNull: false,
16
+ index: true,
17
+ },
18
+ 'roleThingID': {
19
+ type: Types.FOREIGN_KEY('RoleThing:id', { onDelete: 'CASCADE', onUpdate: 'CASCADE' }),
20
+ allowNull: false,
21
+ index: true,
22
+ },
23
+ 'roleThing': {
24
+ type: Types.Model('RoleThing', ({ RoleThing, userQuery, self }) => {
25
+ return RoleThing.$.id.EQ(self.roleThingID).MERGE(userQuery);
26
+ }),
27
+ },
28
+ 'role': {
29
+ type: Types.Model('Role', ({ Role, RoleThing, userQuery, self }) => {
30
+ return Role
31
+ .$.id
32
+ .EQ(RoleThing.$.roleID)
33
+ .RoleThing.id
34
+ .EQ(self.roleThingID)
35
+ .MERGE(userQuery);
36
+ }),
37
+ },
38
+ 'user': {
39
+ type: Types.Model('User', ({ User, userQuery, self }) => {
40
+ return User.$.id.EQ(self.userID).MERGE(userQuery);
41
+ }),
42
+ },
43
+ };
44
+ }
45
+
46
+ module.exports = UserThing;
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const { Model, Types } = require('../../../lib');
4
+
5
+ class ValidationTest extends Model {
6
+ static fields = {
7
+ 'id': {
8
+ type: Types.XID,
9
+ defaultValue: Types.XID.Default.XID,
10
+ allowNull: false,
11
+ primaryKey: true,
12
+ },
13
+ 'number': {
14
+ type: Types.STRING,
15
+ index: true,
16
+ validate: async (value) => {
17
+ if (!(/^\d+$/).test(value))
18
+ throw new Error('Number expected');
19
+ },
20
+ },
21
+ 'boolean': {
22
+ type: Types.STRING,
23
+ index: true,
24
+ validate: async (value) => {
25
+ if (!(/^(true|false)$/).test(value))
26
+ throw new Error('Boolean expected');
27
+ },
28
+ },
29
+ 'date': {
30
+ type: Types.STRING,
31
+ index: true,
32
+ validate: async (value) => {
33
+ if (!(/^\d{4}-\d{2}-\d{2}$/).test(value))
34
+ throw new Error('Invalid date');
35
+ },
36
+ },
37
+ };
38
+ }
39
+
40
+ module.exports = ValidationTest;
@@ -0,0 +1,293 @@
1
+ 'use strict';
2
+
3
+ const jsDiff = require('diff');
4
+ const colors = require('colors/safe');
5
+ const Path = require('path');
6
+ const FileSystem = require('fs');
7
+
8
+ const MAX_FILE_NAME_LENGTH = 100;
9
+
10
+ function showDiff(fileName, c1, c2) {
11
+ jsDiff.createPatch(fileName, c1 || '', c2 || '').replace(/.*/g, function(m) {
12
+ if (!m)
13
+ return;
14
+
15
+ let c = m.charAt(0);
16
+ let out = m;
17
+
18
+ if (c === '-')
19
+ console.log(colors.red(out));
20
+ else if (c === '+')
21
+ console.log(colors.green(out));
22
+ else
23
+ console.log(out);
24
+ });
25
+ }
26
+
27
+ function serialize(value) {
28
+ if (value == null)
29
+ return ('' + value);
30
+
31
+ if (typeof value === 'boolean' || value instanceof Boolean)
32
+ return ('' + value);
33
+
34
+ if (typeof value === 'number' || value instanceof Number)
35
+ return ('' + value);
36
+
37
+ if (typeof value === 'bigint')
38
+ return `BigInt(${value})`;
39
+
40
+ if (typeof value === 'string' || value instanceof String)
41
+ return `"${value.replace(/"/g, '\\"')}"`;
42
+
43
+ return JSON.stringify(value, undefined, 2);
44
+ }
45
+
46
+ const specFileCache = {};
47
+ const callCountCache = {};
48
+
49
+ function getSnapshotNameAndPath() {
50
+ const getFileName = (stackLine) => {
51
+ let fileName;
52
+
53
+ stackLine.replace(/\(([^(]+):\d+:\d+\)$/, (_, str) => {
54
+ fileName = str;
55
+ });
56
+
57
+ return fileName;
58
+ };
59
+
60
+ const getLineNumber = (stackLine) => {
61
+ let number;
62
+
63
+ stackLine.replace(/(\d+):\d+\)$/, (_, numStr) => {
64
+ number = parseInt(numStr, 10);
65
+ });
66
+
67
+ return number;
68
+ };
69
+
70
+ const getBacktraceFile = () => {
71
+ const matchesPatterns = (patterns, fileName) => {
72
+ for (let i = 0, il = patterns.length; i < il; i++) {
73
+ let pattern = patterns[i];
74
+ if (pattern.test(fileName))
75
+ return true;
76
+ }
77
+
78
+ return false;
79
+ };
80
+
81
+ let specFilePatterns = [ /-spec\.js/ ];
82
+ let stack = (new Error()).stack.split(/\s+at\s+/g).slice(1).map((part) => part.trim());
83
+ let file;
84
+
85
+ for (let i = 0, il = stack.length; i < il; i++) {
86
+ let stackLine = stack[i];
87
+ let fileName = getFileName(stackLine);
88
+ if (!matchesPatterns(specFilePatterns, fileName))
89
+ continue;
90
+
91
+ let lineNumber = getLineNumber(stackLine);
92
+
93
+ if (!file) {
94
+ file = {
95
+ lineNumbers: [ lineNumber ],
96
+ fileName,
97
+ };
98
+ } else {
99
+ file.lineNumbers.push(lineNumber);
100
+ }
101
+ }
102
+
103
+ return file;
104
+ };
105
+
106
+ const getSpecFileStructure = (fileName) => {
107
+ if (specFileCache[fileName])
108
+ return specFileCache[fileName];
109
+
110
+ let contents = FileSystem.readFileSync(fileName, 'utf8');
111
+ let lines = contents.split(/\n/g);
112
+
113
+ lines = lines.map((line, lineIndex) => {
114
+ let specName;
115
+ let indentAmount;
116
+
117
+ line.replace(/([\s\t]*)f?(?:describe|it)\s*\(\s*(['"])((?:\\.|.)*?)\2/, (m, indent, q, name) => {
118
+ specName = name.replace(/\\(.)/g, '$1');
119
+ indentAmount = indent.replace(/\t/g, ' ').length;
120
+ });
121
+
122
+ if (!specName)
123
+ return;
124
+
125
+ return { specName, indentAmount, lineNumber: lineIndex + 1 };
126
+ }).filter(Boolean);
127
+
128
+ let nodes = [];
129
+ let currentChildren = nodes;
130
+ let previousNode;
131
+ let parent = null;
132
+
133
+ for (let i = 0, il = lines.length; i < il; i++) {
134
+ let line = lines[i];
135
+ let { specName, indentAmount, lineNumber } = line;
136
+
137
+ if (previousNode) {
138
+ if (previousNode.indentAmount < indentAmount) {
139
+ parent = previousNode;
140
+ currentChildren = previousNode.children;
141
+ } else if (previousNode.indentAmount > indentAmount) {
142
+ parent = previousNode.parent;
143
+ while (parent && parent.indentAmount >= indentAmount)
144
+ parent = parent.parent;
145
+
146
+ currentChildren = (parent) ? parent.children : nodes;
147
+ }
148
+ }
149
+
150
+ let node = { parent, indentAmount, name: specName, lineNumber, children: [] };
151
+ currentChildren.push(node);
152
+
153
+ previousNode = node;
154
+ }
155
+
156
+ specFileCache[fileName] = nodes;
157
+
158
+ return nodes;
159
+ };
160
+
161
+ const findCorrectNode = (nodes, lineNumber, parentNode) => {
162
+ const findChildNode = (nodes, lineNumber) => {
163
+ for (let i = 0, il = nodes.length; i < il; i++) {
164
+ let node = nodes[i];
165
+ let childNode = findCorrectNode(node.children, lineNumber, node);
166
+ if (childNode)
167
+ return childNode;
168
+ }
169
+ };
170
+
171
+ const findLargerNode = (nodes, lineNumber) => {
172
+ for (let i = 0, il = nodes.length; i < il; i++) {
173
+ let node = nodes[i];
174
+ if (node.lineNumber > lineNumber)
175
+ return i;
176
+ }
177
+
178
+ return -1;
179
+ };
180
+
181
+ let childNode = findChildNode(nodes, lineNumber);
182
+ if (childNode) {
183
+ while (childNode.lineNumber > lineNumber)
184
+ childNode = childNode.parent;
185
+
186
+ return childNode;
187
+ }
188
+
189
+ let largerNodeIndex = findLargerNode(nodes, lineNumber);
190
+ if (largerNodeIndex <= 0)
191
+ return (largerNodeIndex === 0) ? parentNode : undefined;
192
+
193
+ return nodes[largerNodeIndex - 1];
194
+ };
195
+
196
+ const getLastNode = (nodes) => {
197
+ if (!nodes.length)
198
+ return;
199
+
200
+ let lastNode = nodes[nodes.length - 1];
201
+ if (lastNode.children.length > 0)
202
+ return getLastNode(lastNode.children);
203
+
204
+ return lastNode;
205
+ };
206
+
207
+ const getNodePath = (_node) => {
208
+ if (!_node)
209
+ return;
210
+
211
+ let node = _node;
212
+ let path = [ node.name ];
213
+
214
+ while (node && node.parent) {
215
+ node = node.parent;
216
+ path.push(node.name);
217
+ }
218
+
219
+ return path.reverse().join('/');
220
+ };
221
+
222
+ const getCorrectNodePath = (nodes, lineNumbers) => {
223
+ let nodePaths = lineNumbers.map((lineNumber) => {
224
+ let node = findCorrectNode(nodes, lineNumber);
225
+ if (!node)
226
+ node = getLastNode(nodes);
227
+
228
+ return getNodePath(node);
229
+ }).filter(Boolean);
230
+
231
+ let nodePath = nodePaths.sort((a, b) => {
232
+ if (a.length === b.length)
233
+ return 0;
234
+
235
+ return (a.length < b.length) ? 1 : -1;
236
+ })[0];
237
+
238
+ let callCount = callCountCache[nodePath];
239
+ if (!callCount)
240
+ callCount = 0;
241
+
242
+ callCount++;
243
+ callCountCache[nodePath] = callCount;
244
+
245
+ nodePath = nodePath.replace(/[^\w/]+/g, '_').replace(/\//g, '-');
246
+ if (nodePath.length > MAX_FILE_NAME_LENGTH) {
247
+ nodePath = nodePath.substring(0, MAX_FILE_NAME_LENGTH);
248
+ nodePath = nodePath.replace(/^[^0-9a-zA-Z]+/, '').replace(/[^0-9a-zA-Z]+$/, '');
249
+ }
250
+
251
+ // eslint-disable-next-line no-magic-numbers
252
+ return (`${nodePath}-${('' + callCount).padStart(3, '0')}.snapshot`);
253
+ };
254
+
255
+ const getSnapshotDetails = () => {
256
+ let { fileName, lineNumbers } = getBacktraceFile();
257
+ let nodes = getSpecFileStructure(fileName);
258
+ let name = getCorrectNodePath(nodes, lineNumbers);
259
+
260
+ return { path: Path.dirname(fileName), name };
261
+ };
262
+
263
+ let structure = getSnapshotDetails();
264
+ return structure;
265
+ }
266
+
267
+ function matchesSnapshot(value) {
268
+ let { name, path } = getSnapshotNameAndPath();
269
+ let snapshotPath = Path.join(path, '__snapshots__');
270
+ let fullPath = Path.join(snapshotPath, name);
271
+
272
+ try {
273
+ FileSystem.mkdirSync(snapshotPath);
274
+ } catch (error) {
275
+ if (error.code !== 'EEXIST')
276
+ throw error;
277
+ }
278
+
279
+ let serializedValue = serialize(value);
280
+ if (!FileSystem.existsSync(fullPath))
281
+ FileSystem.writeFileSync(fullPath, serializedValue, 'utf8');
282
+
283
+ let storedValue = FileSystem.readFileSync(fullPath, 'utf8');
284
+
285
+ if (storedValue !== serializedValue) {
286
+ showDiff(fullPath, storedValue, serializedValue);
287
+ return false;
288
+ }
289
+
290
+ return true;
291
+ }
292
+
293
+ module.exports = matchesSnapshot;
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const UUID_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
4
+ const XID_REGEXP = /^[0-9abcdefghjkmnpqrstvwxyz]{20}$/;
5
+ const ISO8601_TIME_REGEXP = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
6
+ const ISO8601_DATE_REGEXP = /\d{4}-\d{2}-\d{2}T00:00:00.000Z/;
7
+
8
+ module.exports = {
9
+ UUID_REGEXP,
10
+ XID_REGEXP,
11
+ ISO8601_TIME_REGEXP,
12
+ ISO8601_DATE_REGEXP,
13
+ };
@@ -0,0 +1,84 @@
1
+ /* eslint-disable no-magic-numbers */
2
+
3
+ 'use strict';
4
+
5
+ /* global describe, it, expect, beforeAll */
6
+
7
+ const { Types, ConnectionBase } = require('../../../lib');
8
+
9
+ describe('BigIntType', () => {
10
+ let connection;
11
+
12
+ beforeAll(async () => {
13
+ connection = new ConnectionBase({
14
+ bindModels: false,
15
+ models: require('../../support/models'),
16
+ });
17
+ });
18
+
19
+ describe('toConnectionType', () => {
20
+ it('can convert to connection is defined', () => {
21
+ let type = new Types.BigIntType();
22
+ expect(type.toConnectionType(connection)).toEqual('BIGINT');
23
+ });
24
+
25
+ it('can convert to connection type when connection is undefined', () => {
26
+ let type = new Types.BigIntType(6);
27
+ expect(type.toConnectionType()).toEqual('BIGINT(6)');
28
+ });
29
+ });
30
+
31
+ describe('toString', () => {
32
+ it('can convert to connection is defined', () => {
33
+ let type = new Types.BigIntType();
34
+ expect(type.toString(connection)).toEqual('BIGINT');
35
+ });
36
+
37
+ it('can convert to connection type when connection undefined', () => {
38
+ let type = new Types.BigIntType(6);
39
+ expect(type.toString()).toEqual('BIGINT(6)');
40
+ });
41
+ });
42
+
43
+ it('can construct from class', () => {
44
+ let type = new Types.BigIntType();
45
+ expect(type.toString()).toEqual('BIGINT');
46
+ expect(type.length).toBe(null);
47
+ });
48
+
49
+ it('can construct from class with length', () => {
50
+ let type = new Types.BigIntType(11);
51
+ expect(type.toString()).toEqual('BIGINT(11)');
52
+ expect(type.length).toEqual(11);
53
+ });
54
+
55
+ it('can construct from type helper', () => {
56
+ let type = Types.BIGINT();
57
+ expect(type.toString()).toEqual('BIGINT');
58
+ expect(type.length).toBe(null);
59
+ });
60
+
61
+ it('can construct from type helper with length', () => {
62
+ let type = Types.BIGINT(11);
63
+ expect(type.toString()).toEqual('BIGINT(11)');
64
+ expect(type.length).toEqual(11);
65
+ });
66
+
67
+ it('can cast to type', () => {
68
+ let type = Types.BIGINT();
69
+ let value = type.castToType({ value: '1234' });
70
+ expect(typeof value).toEqual('number');
71
+ expect(value).toEqual(1234);
72
+
73
+ expect(() => type.castToType({ value: 'derp' })).toThrow(new SyntaxError('Cannot convert derp to a BigInt'));
74
+ });
75
+
76
+ it('can cast to type (strict)', () => {
77
+ let type = Types.BIGINT(null, { strict: true });
78
+ let value = type.castToType({ value: '1234' });
79
+ expect(typeof value).toEqual('bigint');
80
+ expect(value).toEqual(BigInt(1234));
81
+
82
+ expect(() => type.castToType({ value: 'derp' })).toThrow(new SyntaxError('Cannot convert derp to a BigInt'));
83
+ });
84
+ });