@snowtop/ent 0.1.0-alpha160-test5 → 0.1.0-alpha160-test7

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 (317) hide show
  1. package/dist/package.json +64 -0
  2. package/package.json +52 -7
  3. package/src/action/action.ts +330 -0
  4. package/src/action/executor.ts +453 -0
  5. package/src/action/experimental_action.ts +277 -0
  6. package/src/action/index.ts +31 -0
  7. package/src/action/operations.ts +967 -0
  8. package/src/action/orchestrator.ts +1527 -0
  9. package/src/action/privacy.ts +37 -0
  10. package/src/action/relative_value.ts +242 -0
  11. package/src/action/transaction.ts +38 -0
  12. package/src/auth/auth.ts +77 -0
  13. package/src/auth/index.ts +8 -0
  14. package/src/core/base.ts +367 -0
  15. package/src/core/clause.ts +1065 -0
  16. package/src/core/config.ts +219 -0
  17. package/src/core/const.ts +5 -0
  18. package/src/core/context.ts +135 -0
  19. package/src/core/convert.ts +106 -0
  20. package/src/core/date.ts +23 -0
  21. package/src/core/db.ts +498 -0
  22. package/src/core/ent.ts +1740 -0
  23. package/src/core/global_schema.ts +49 -0
  24. package/src/core/loaders/assoc_count_loader.ts +99 -0
  25. package/src/core/loaders/assoc_edge_loader.ts +250 -0
  26. package/src/core/loaders/index.ts +12 -0
  27. package/src/core/loaders/loader.ts +66 -0
  28. package/src/core/loaders/object_loader.ts +489 -0
  29. package/src/core/loaders/query_loader.ts +314 -0
  30. package/src/core/loaders/raw_count_loader.ts +175 -0
  31. package/src/core/logger.ts +49 -0
  32. package/src/core/privacy.ts +660 -0
  33. package/src/core/query/assoc_query.ts +240 -0
  34. package/src/core/query/custom_clause_query.ts +174 -0
  35. package/src/core/query/custom_query.ts +302 -0
  36. package/src/core/query/index.ts +9 -0
  37. package/src/core/query/query.ts +674 -0
  38. package/src/core/query_impl.ts +32 -0
  39. package/src/core/viewer.ts +52 -0
  40. package/src/ent.code-workspace +73 -0
  41. package/src/graphql/builtins/connection.ts +25 -0
  42. package/src/graphql/builtins/edge.ts +16 -0
  43. package/src/graphql/builtins/node.ts +12 -0
  44. package/src/graphql/graphql.ts +891 -0
  45. package/src/graphql/graphql_field_helpers.ts +221 -0
  46. package/src/graphql/index.ts +42 -0
  47. package/src/graphql/mutations/union.ts +39 -0
  48. package/src/graphql/node_resolver.ts +122 -0
  49. package/src/graphql/query/connection_type.ts +113 -0
  50. package/src/graphql/query/edge_connection.ts +171 -0
  51. package/src/graphql/query/page_info.ts +34 -0
  52. package/src/graphql/query/shared_edge_connection.ts +287 -0
  53. package/src/graphql/scalars/orderby_direction.ts +13 -0
  54. package/src/graphql/scalars/time.ts +38 -0
  55. package/src/imports/dataz/example1/_auth.ts +51 -0
  56. package/src/imports/dataz/example1/_viewer.ts +35 -0
  57. package/src/imports/index.ts +213 -0
  58. package/src/index.ts +145 -0
  59. package/src/parse_schema/parse.ts +585 -0
  60. package/src/schema/base_schema.ts +224 -0
  61. package/src/schema/field.ts +1087 -0
  62. package/src/schema/index.ts +53 -0
  63. package/src/schema/json_field.ts +94 -0
  64. package/src/schema/schema.ts +1028 -0
  65. package/src/schema/struct_field.ts +234 -0
  66. package/src/schema/union_field.ts +105 -0
  67. package/src/scripts/custom_compiler.ts +331 -0
  68. package/src/scripts/custom_graphql.ts +550 -0
  69. package/src/scripts/migrate_v0.1.ts +41 -0
  70. package/src/scripts/move_types.ts +131 -0
  71. package/src/scripts/read_schema.ts +67 -0
  72. package/src/setupPackage.js +42 -0
  73. package/src/testutils/action/complex_schemas.ts +517 -0
  74. package/src/testutils/builder.ts +422 -0
  75. package/src/testutils/context/test_context.ts +25 -0
  76. package/src/testutils/db/fixture.ts +32 -0
  77. package/src/testutils/db/temp_db.ts +941 -0
  78. package/src/testutils/db/value.ts +294 -0
  79. package/src/testutils/db_mock.ts +351 -0
  80. package/src/testutils/db_time_zone.ts +40 -0
  81. package/src/testutils/ent-graphql-tests/index.ts +653 -0
  82. package/src/testutils/fake_comms.ts +50 -0
  83. package/src/testutils/fake_data/const.ts +64 -0
  84. package/src/testutils/fake_data/events_query.ts +145 -0
  85. package/src/testutils/fake_data/fake_contact.ts +150 -0
  86. package/src/testutils/fake_data/fake_event.ts +150 -0
  87. package/src/testutils/fake_data/fake_tag.ts +139 -0
  88. package/src/testutils/fake_data/fake_user.ts +232 -0
  89. package/src/testutils/fake_data/index.ts +1 -0
  90. package/src/testutils/fake_data/internal.ts +8 -0
  91. package/src/testutils/fake_data/tag_query.ts +56 -0
  92. package/src/testutils/fake_data/test_helpers.ts +388 -0
  93. package/src/testutils/fake_data/user_query.ts +524 -0
  94. package/src/testutils/fake_log.ts +52 -0
  95. package/src/testutils/mock_date.ts +10 -0
  96. package/src/testutils/mock_log.ts +39 -0
  97. package/src/testutils/parse_sql.ts +685 -0
  98. package/src/testutils/test_edge_global_schema.ts +49 -0
  99. package/src/testutils/write.ts +70 -0
  100. package/src/tsc/ast.ts +351 -0
  101. package/src/tsc/compilerOptions.ts +85 -0
  102. package/src/tsc/move_generated.ts +191 -0
  103. package/src/tsc/transform.ts +226 -0
  104. package/src/tsc/transform_action.ts +224 -0
  105. package/src/tsc/transform_ent.ts +66 -0
  106. package/src/tsc/transform_schema.ts +546 -0
  107. package/tsconfig.json +20 -0
  108. package/core/query/shared_assoc_test.d.ts +0 -2
  109. package/core/query/shared_assoc_test.js +0 -804
  110. package/core/query/shared_test.d.ts +0 -21
  111. package/core/query/shared_test.js +0 -736
  112. package/graphql/query/shared_assoc_test.d.ts +0 -1
  113. package/graphql/query/shared_assoc_test.js +0 -203
  114. /package/{action → dist/action}/action.d.ts +0 -0
  115. /package/{action → dist/action}/action.js +0 -0
  116. /package/{action → dist/action}/executor.d.ts +0 -0
  117. /package/{action → dist/action}/executor.js +0 -0
  118. /package/{action → dist/action}/experimental_action.d.ts +0 -0
  119. /package/{action → dist/action}/experimental_action.js +0 -0
  120. /package/{action → dist/action}/index.d.ts +0 -0
  121. /package/{action → dist/action}/index.js +0 -0
  122. /package/{action → dist/action}/operations.d.ts +0 -0
  123. /package/{action → dist/action}/operations.js +0 -0
  124. /package/{action → dist/action}/orchestrator.d.ts +0 -0
  125. /package/{action → dist/action}/orchestrator.js +0 -0
  126. /package/{action → dist/action}/privacy.d.ts +0 -0
  127. /package/{action → dist/action}/privacy.js +0 -0
  128. /package/{action → dist/action}/relative_value.d.ts +0 -0
  129. /package/{action → dist/action}/relative_value.js +0 -0
  130. /package/{action → dist/action}/transaction.d.ts +0 -0
  131. /package/{action → dist/action}/transaction.js +0 -0
  132. /package/{auth → dist/auth}/auth.d.ts +0 -0
  133. /package/{auth → dist/auth}/auth.js +0 -0
  134. /package/{auth → dist/auth}/index.d.ts +0 -0
  135. /package/{auth → dist/auth}/index.js +0 -0
  136. /package/{core → dist/core}/base.d.ts +0 -0
  137. /package/{core → dist/core}/base.js +0 -0
  138. /package/{core → dist/core}/clause.d.ts +0 -0
  139. /package/{core → dist/core}/clause.js +0 -0
  140. /package/{core → dist/core}/config.d.ts +0 -0
  141. /package/{core → dist/core}/config.js +0 -0
  142. /package/{core → dist/core}/const.d.ts +0 -0
  143. /package/{core → dist/core}/const.js +0 -0
  144. /package/{core → dist/core}/context.d.ts +0 -0
  145. /package/{core → dist/core}/context.js +0 -0
  146. /package/{core → dist/core}/convert.d.ts +0 -0
  147. /package/{core → dist/core}/convert.js +0 -0
  148. /package/{core → dist/core}/date.d.ts +0 -0
  149. /package/{core → dist/core}/date.js +0 -0
  150. /package/{core → dist/core}/db.d.ts +0 -0
  151. /package/{core → dist/core}/db.js +0 -0
  152. /package/{core → dist/core}/ent.d.ts +0 -0
  153. /package/{core → dist/core}/ent.js +0 -0
  154. /package/{core → dist/core}/global_schema.d.ts +0 -0
  155. /package/{core → dist/core}/global_schema.js +0 -0
  156. /package/{core → dist/core}/loaders/assoc_count_loader.d.ts +0 -0
  157. /package/{core → dist/core}/loaders/assoc_count_loader.js +0 -0
  158. /package/{core → dist/core}/loaders/assoc_edge_loader.d.ts +0 -0
  159. /package/{core → dist/core}/loaders/assoc_edge_loader.js +0 -0
  160. /package/{core → dist/core}/loaders/index.d.ts +0 -0
  161. /package/{core → dist/core}/loaders/index.js +0 -0
  162. /package/{core → dist/core}/loaders/loader.d.ts +0 -0
  163. /package/{core → dist/core}/loaders/loader.js +0 -0
  164. /package/{core → dist/core}/loaders/object_loader.d.ts +0 -0
  165. /package/{core → dist/core}/loaders/object_loader.js +0 -0
  166. /package/{core → dist/core}/loaders/query_loader.d.ts +0 -0
  167. /package/{core → dist/core}/loaders/query_loader.js +0 -0
  168. /package/{core → dist/core}/loaders/raw_count_loader.d.ts +0 -0
  169. /package/{core → dist/core}/loaders/raw_count_loader.js +0 -0
  170. /package/{core → dist/core}/logger.d.ts +0 -0
  171. /package/{core → dist/core}/logger.js +0 -0
  172. /package/{core → dist/core}/privacy.d.ts +0 -0
  173. /package/{core → dist/core}/privacy.js +0 -0
  174. /package/{core → dist/core}/query/assoc_query.d.ts +0 -0
  175. /package/{core → dist/core}/query/assoc_query.js +0 -0
  176. /package/{core → dist/core}/query/custom_clause_query.d.ts +0 -0
  177. /package/{core → dist/core}/query/custom_clause_query.js +0 -0
  178. /package/{core → dist/core}/query/custom_query.d.ts +0 -0
  179. /package/{core → dist/core}/query/custom_query.js +0 -0
  180. /package/{core → dist/core}/query/index.d.ts +0 -0
  181. /package/{core → dist/core}/query/index.js +0 -0
  182. /package/{core → dist/core}/query/query.d.ts +0 -0
  183. /package/{core → dist/core}/query/query.js +0 -0
  184. /package/{core → dist/core}/query_impl.d.ts +0 -0
  185. /package/{core → dist/core}/query_impl.js +0 -0
  186. /package/{core → dist/core}/viewer.d.ts +0 -0
  187. /package/{core → dist/core}/viewer.js +0 -0
  188. /package/{graphql → dist/graphql}/builtins/connection.d.ts +0 -0
  189. /package/{graphql → dist/graphql}/builtins/connection.js +0 -0
  190. /package/{graphql → dist/graphql}/builtins/edge.d.ts +0 -0
  191. /package/{graphql → dist/graphql}/builtins/edge.js +0 -0
  192. /package/{graphql → dist/graphql}/builtins/node.d.ts +0 -0
  193. /package/{graphql → dist/graphql}/builtins/node.js +0 -0
  194. /package/{graphql → dist/graphql}/graphql.d.ts +0 -0
  195. /package/{graphql → dist/graphql}/graphql.js +0 -0
  196. /package/{graphql → dist/graphql}/graphql_field_helpers.d.ts +0 -0
  197. /package/{graphql → dist/graphql}/graphql_field_helpers.js +0 -0
  198. /package/{graphql → dist/graphql}/index.d.ts +0 -0
  199. /package/{graphql → dist/graphql}/index.js +0 -0
  200. /package/{graphql → dist/graphql}/mutations/union.d.ts +0 -0
  201. /package/{graphql → dist/graphql}/mutations/union.js +0 -0
  202. /package/{graphql → dist/graphql}/node_resolver.d.ts +0 -0
  203. /package/{graphql → dist/graphql}/node_resolver.js +0 -0
  204. /package/{graphql → dist/graphql}/query/connection_type.d.ts +0 -0
  205. /package/{graphql → dist/graphql}/query/connection_type.js +0 -0
  206. /package/{graphql → dist/graphql}/query/edge_connection.d.ts +0 -0
  207. /package/{graphql → dist/graphql}/query/edge_connection.js +0 -0
  208. /package/{graphql → dist/graphql}/query/page_info.d.ts +0 -0
  209. /package/{graphql → dist/graphql}/query/page_info.js +0 -0
  210. /package/{graphql → dist/graphql}/query/shared_edge_connection.d.ts +0 -0
  211. /package/{graphql → dist/graphql}/query/shared_edge_connection.js +0 -0
  212. /package/{graphql → dist/graphql}/scalars/orderby_direction.d.ts +0 -0
  213. /package/{graphql → dist/graphql}/scalars/orderby_direction.js +0 -0
  214. /package/{graphql → dist/graphql}/scalars/time.d.ts +0 -0
  215. /package/{graphql → dist/graphql}/scalars/time.js +0 -0
  216. /package/{imports → dist/imports}/dataz/example1/_auth.d.ts +0 -0
  217. /package/{imports → dist/imports}/dataz/example1/_auth.js +0 -0
  218. /package/{imports → dist/imports}/dataz/example1/_viewer.d.ts +0 -0
  219. /package/{imports → dist/imports}/dataz/example1/_viewer.js +0 -0
  220. /package/{imports → dist/imports}/index.d.ts +0 -0
  221. /package/{imports → dist/imports}/index.js +0 -0
  222. /package/{index.d.ts → dist/index.d.ts} +0 -0
  223. /package/{index.js → dist/index.js} +0 -0
  224. /package/{parse_schema → dist/parse_schema}/parse.d.ts +0 -0
  225. /package/{parse_schema → dist/parse_schema}/parse.js +0 -0
  226. /package/{schema → dist/schema}/base_schema.d.ts +0 -0
  227. /package/{schema → dist/schema}/base_schema.js +0 -0
  228. /package/{schema → dist/schema}/field.d.ts +0 -0
  229. /package/{schema → dist/schema}/field.js +0 -0
  230. /package/{schema → dist/schema}/index.d.ts +0 -0
  231. /package/{schema → dist/schema}/index.js +0 -0
  232. /package/{schema → dist/schema}/json_field.d.ts +0 -0
  233. /package/{schema → dist/schema}/json_field.js +0 -0
  234. /package/{schema → dist/schema}/schema.d.ts +0 -0
  235. /package/{schema → dist/schema}/schema.js +0 -0
  236. /package/{schema → dist/schema}/struct_field.d.ts +0 -0
  237. /package/{schema → dist/schema}/struct_field.js +0 -0
  238. /package/{schema → dist/schema}/union_field.d.ts +0 -0
  239. /package/{schema → dist/schema}/union_field.js +0 -0
  240. /package/{scripts → dist/scripts}/custom_compiler.d.ts +0 -0
  241. /package/{scripts → dist/scripts}/custom_compiler.js +0 -0
  242. /package/{scripts → dist/scripts}/custom_graphql.d.ts +0 -0
  243. /package/{scripts → dist/scripts}/custom_graphql.js +0 -0
  244. /package/{scripts → dist/scripts}/migrate_v0.1.d.ts +0 -0
  245. /package/{scripts → dist/scripts}/migrate_v0.1.js +0 -0
  246. /package/{scripts → dist/scripts}/move_types.d.ts +0 -0
  247. /package/{scripts → dist/scripts}/move_types.js +0 -0
  248. /package/{scripts → dist/scripts}/read_schema.d.ts +0 -0
  249. /package/{scripts → dist/scripts}/read_schema.js +0 -0
  250. /package/{testutils → dist/testutils}/action/complex_schemas.d.ts +0 -0
  251. /package/{testutils → dist/testutils}/action/complex_schemas.js +0 -0
  252. /package/{testutils → dist/testutils}/builder.d.ts +0 -0
  253. /package/{testutils → dist/testutils}/builder.js +0 -0
  254. /package/{testutils → dist/testutils}/context/test_context.d.ts +0 -0
  255. /package/{testutils → dist/testutils}/context/test_context.js +0 -0
  256. /package/{testutils → dist/testutils}/db/fixture.d.ts +0 -0
  257. /package/{testutils → dist/testutils}/db/fixture.js +0 -0
  258. /package/{testutils → dist/testutils}/db/temp_db.d.ts +0 -0
  259. /package/{testutils → dist/testutils}/db/temp_db.js +0 -0
  260. /package/{testutils → dist/testutils}/db/value.d.ts +0 -0
  261. /package/{testutils → dist/testutils}/db/value.js +0 -0
  262. /package/{testutils → dist/testutils}/db_mock.d.ts +0 -0
  263. /package/{testutils → dist/testutils}/db_mock.js +0 -0
  264. /package/{testutils → dist/testutils}/db_time_zone.d.ts +0 -0
  265. /package/{testutils → dist/testutils}/db_time_zone.js +0 -0
  266. /package/{testutils → dist/testutils}/ent-graphql-tests/index.d.ts +0 -0
  267. /package/{testutils → dist/testutils}/ent-graphql-tests/index.js +0 -0
  268. /package/{testutils → dist/testutils}/fake_comms.d.ts +0 -0
  269. /package/{testutils → dist/testutils}/fake_comms.js +0 -0
  270. /package/{testutils → dist/testutils}/fake_data/const.d.ts +0 -0
  271. /package/{testutils → dist/testutils}/fake_data/const.js +0 -0
  272. /package/{testutils → dist/testutils}/fake_data/events_query.d.ts +0 -0
  273. /package/{testutils → dist/testutils}/fake_data/events_query.js +0 -0
  274. /package/{testutils → dist/testutils}/fake_data/fake_contact.d.ts +0 -0
  275. /package/{testutils → dist/testutils}/fake_data/fake_contact.js +0 -0
  276. /package/{testutils → dist/testutils}/fake_data/fake_event.d.ts +0 -0
  277. /package/{testutils → dist/testutils}/fake_data/fake_event.js +0 -0
  278. /package/{testutils → dist/testutils}/fake_data/fake_tag.d.ts +0 -0
  279. /package/{testutils → dist/testutils}/fake_data/fake_tag.js +0 -0
  280. /package/{testutils → dist/testutils}/fake_data/fake_user.d.ts +0 -0
  281. /package/{testutils → dist/testutils}/fake_data/fake_user.js +0 -0
  282. /package/{testutils → dist/testutils}/fake_data/index.d.ts +0 -0
  283. /package/{testutils → dist/testutils}/fake_data/index.js +0 -0
  284. /package/{testutils → dist/testutils}/fake_data/internal.d.ts +0 -0
  285. /package/{testutils → dist/testutils}/fake_data/internal.js +0 -0
  286. /package/{testutils → dist/testutils}/fake_data/tag_query.d.ts +0 -0
  287. /package/{testutils → dist/testutils}/fake_data/tag_query.js +0 -0
  288. /package/{testutils → dist/testutils}/fake_data/test_helpers.d.ts +0 -0
  289. /package/{testutils → dist/testutils}/fake_data/test_helpers.js +0 -0
  290. /package/{testutils → dist/testutils}/fake_data/user_query.d.ts +0 -0
  291. /package/{testutils → dist/testutils}/fake_data/user_query.js +0 -0
  292. /package/{testutils → dist/testutils}/fake_log.d.ts +0 -0
  293. /package/{testutils → dist/testutils}/fake_log.js +0 -0
  294. /package/{testutils → dist/testutils}/mock_date.d.ts +0 -0
  295. /package/{testutils → dist/testutils}/mock_date.js +0 -0
  296. /package/{testutils → dist/testutils}/mock_log.d.ts +0 -0
  297. /package/{testutils → dist/testutils}/mock_log.js +0 -0
  298. /package/{testutils → dist/testutils}/parse_sql.d.ts +0 -0
  299. /package/{testutils → dist/testutils}/parse_sql.js +0 -0
  300. /package/{testutils → dist/testutils}/test_edge_global_schema.d.ts +0 -0
  301. /package/{testutils → dist/testutils}/test_edge_global_schema.js +0 -0
  302. /package/{testutils → dist/testutils}/write.d.ts +0 -0
  303. /package/{testutils → dist/testutils}/write.js +0 -0
  304. /package/{tsc → dist/tsc}/ast.d.ts +0 -0
  305. /package/{tsc → dist/tsc}/ast.js +0 -0
  306. /package/{tsc → dist/tsc}/compilerOptions.d.ts +0 -0
  307. /package/{tsc → dist/tsc}/compilerOptions.js +0 -0
  308. /package/{tsc → dist/tsc}/move_generated.d.ts +0 -0
  309. /package/{tsc → dist/tsc}/move_generated.js +0 -0
  310. /package/{tsc → dist/tsc}/transform.d.ts +0 -0
  311. /package/{tsc → dist/tsc}/transform.js +0 -0
  312. /package/{tsc → dist/tsc}/transform_action.d.ts +0 -0
  313. /package/{tsc → dist/tsc}/transform_action.js +0 -0
  314. /package/{tsc → dist/tsc}/transform_ent.d.ts +0 -0
  315. /package/{tsc → dist/tsc}/transform_ent.js +0 -0
  316. /package/{tsc → dist/tsc}/transform_schema.d.ts +0 -0
  317. /package/{tsc → dist/tsc}/transform_schema.js +0 -0
@@ -0,0 +1,653 @@
1
+ // NB: this is copied from ent-graphql-tests package until I have time to figure out how to share code here effectively
2
+ // the circular dependencies btw this package and ent-graphql-tests seems to imply something needs to change
3
+ import express, { Express, RequestHandler } from "express";
4
+ import {
5
+ getGraphQLParameters,
6
+ processRequest,
7
+ ExecutionContext,
8
+ sendResult,
9
+ } from "graphql-helix";
10
+ import { Viewer } from "../../core/base";
11
+ import {
12
+ GraphQLSchema,
13
+ GraphQLObjectType,
14
+ GraphQLScalarType,
15
+ isWrappingType,
16
+ GraphQLArgument,
17
+ GraphQLList,
18
+ isScalarType,
19
+ GraphQLType,
20
+ GraphQLFieldMap,
21
+ GraphQLField,
22
+ isEnumType,
23
+ } from "graphql";
24
+ import { buildContext, registerAuthHandler } from "../../auth";
25
+ import supertest from "supertest";
26
+ import * as fs from "fs";
27
+ import { inspect } from "util";
28
+
29
+ function server(config: queryConfig): Express {
30
+ const viewer = config.viewer;
31
+ if (viewer) {
32
+ registerAuthHandler("viewer", {
33
+ authViewer: async (_context) => {
34
+ // TODO we want to use Context here in tests to get caching etc
35
+ return viewer;
36
+ },
37
+ });
38
+ }
39
+ let app = express();
40
+ if (config.init) {
41
+ config.init(app);
42
+ }
43
+ // @ts-ignore something changed. come back
44
+ app.use(express.json());
45
+
46
+ let handlers = config.customHandlers || [];
47
+ handlers.push(async (req, res) => {
48
+ const { operationName, query, variables } = getGraphQLParameters(req);
49
+ const result = await processRequest({
50
+ operationName,
51
+ query,
52
+ variables,
53
+ request: req,
54
+ schema: config.schema,
55
+ contextFactory: async (executionContext: ExecutionContext) => {
56
+ // @ts-ignore something changed. come back
57
+ return buildContext(req, res);
58
+ },
59
+ });
60
+ // @ts-ignore something changed. come back
61
+ await sendResult(result, res);
62
+ });
63
+ app.use(config.graphQLPath || "/graphql", ...handlers);
64
+
65
+ return app;
66
+ }
67
+
68
+ function getInnerType(typ, list) {
69
+ if (isWrappingType(typ)) {
70
+ if (typ instanceof GraphQLList) {
71
+ return getInnerType(typ.ofType, true);
72
+ }
73
+ return getInnerType(typ.ofType, list);
74
+ }
75
+ return [typ, list];
76
+ }
77
+
78
+ function makeGraphQLRequest(
79
+ config: queryConfig,
80
+ query: string,
81
+ fieldArgs: Readonly<GraphQLArgument[]>,
82
+ ): [supertest.SuperTest<supertest.Test>, supertest.Test] {
83
+ let test: supertest.SuperTest<supertest.Test>;
84
+
85
+ if (config.test) {
86
+ if (typeof config.test === "function") {
87
+ test = config.test(config.server ? config.server : server(config));
88
+ } else {
89
+ test = config.test;
90
+ }
91
+ } else {
92
+ test = supertest(config.server ? config.server : server(config));
93
+ }
94
+
95
+ let files = new Map();
96
+
97
+ // handle files
98
+ fieldArgs.forEach((fieldArg) => {
99
+ let [typ, list] = getInnerType(fieldArg.type, false);
100
+
101
+ if (typ instanceof GraphQLScalarType && typ.name == "Upload") {
102
+ let value = config.args[fieldArg.name];
103
+ if (list) {
104
+ expect(Array.isArray(value)).toBe(true);
105
+ // clone if we're going to make changes
106
+ value = [...value];
107
+
108
+ for (let i = 0; i < value.length; i++) {
109
+ files.set(`${fieldArg.name}.${i}`, value[i]);
110
+ value[i] = null;
111
+ }
112
+ config.args[fieldArg.name] = value;
113
+ } else {
114
+ files.set(fieldArg.name, value);
115
+ config.args[fieldArg.name] = null;
116
+ }
117
+ }
118
+ });
119
+
120
+ let variables = {
121
+ ...config.args,
122
+ };
123
+ for (const k in config.extraVariables) {
124
+ variables[k] = config.extraVariables[k].value;
125
+ }
126
+
127
+ if (files.size) {
128
+ let ret = test
129
+ .post(config.graphQLPath || "/graphql")
130
+ .set(config.headers || {});
131
+
132
+ ret.field(
133
+ "operations",
134
+ JSON.stringify({
135
+ query: query,
136
+ variables: variables,
137
+ }),
138
+ );
139
+
140
+ let m = {};
141
+ let idx = 0;
142
+ for (const [key] of files) {
143
+ m[idx] = [`variables.${key}`];
144
+ idx++;
145
+ }
146
+
147
+ ret.field("map", JSON.stringify(m));
148
+
149
+ idx = 0;
150
+ for (let [key, val] of files) {
151
+ if (typeof val === "string") {
152
+ val = fs.createReadStream(val);
153
+ }
154
+ ret.attach(`${idx}`, val, key);
155
+ idx++;
156
+ }
157
+
158
+ return [test, ret];
159
+ } else {
160
+ return [
161
+ test,
162
+ test
163
+ .post(config.graphQLPath || "/graphql")
164
+ .set(config.headers || {})
165
+ .send({
166
+ query: query,
167
+ variables: JSON.stringify(variables),
168
+ }),
169
+ ];
170
+ }
171
+ }
172
+
173
+ function buildTreeFromQueryPaths(
174
+ schema: GraphQLSchema,
175
+ fieldType: GraphQLType,
176
+ ...options: Option[]
177
+ ) {
178
+ let fields: GraphQLFieldMap<any, any>;
179
+ const [typ] = getInnerType(fieldType, false);
180
+ if (typ instanceof GraphQLObjectType) {
181
+ fields = typ.getFields();
182
+ }
183
+ let topLevelTree = {};
184
+ options.forEach((option) => {
185
+ let path = option[0];
186
+ let parts: string[] = [];
187
+ let match = fragmentRegex.exec(path);
188
+ if (match) {
189
+ // fragment, keep the part of the fragment e.g. `...on User`, and then split the rest....
190
+ parts = [match[0], ...match[2].split(".")];
191
+
192
+ const typ = schema.getType(match[1]);
193
+ if (!typ) {
194
+ throw new Error(`can't find type for ${match[1]} in schema`);
195
+ }
196
+ if (typ instanceof GraphQLObjectType) {
197
+ fields = typ.getFields();
198
+ }
199
+ } else {
200
+ parts = splitPath(path);
201
+ }
202
+
203
+ let tree = topLevelTree;
204
+ for (let i = 0; i < parts.length; i++) {
205
+ let part = parts[i];
206
+ // a list, remove the index in the list building part
207
+ let idx = part.indexOf("[");
208
+ if (idx !== -1) {
209
+ part = part.substr(0, idx);
210
+ }
211
+ // if this part of the tree doesn't exist, put an empty node there
212
+ if (tree[part] === undefined) {
213
+ tree[part] = {};
214
+ }
215
+ if (part !== "") {
216
+ tree = tree[part];
217
+ }
218
+ // TODO this needs to be aware of paths etc so this part works for complicated
219
+ // cases but inlineFragmentRoot is a workaround for now.
220
+ function handleSubtree(obj: {}, tree: {}, parts: string[]) {
221
+ let parts2 = [...parts];
222
+ if (Array.isArray(obj)) {
223
+ for (const obj2 of obj) {
224
+ handleSubtree(obj2, tree, parts2);
225
+ }
226
+ return;
227
+ }
228
+ for (const key in obj) {
229
+ if (tree[key] === undefined) {
230
+ tree[key] = {};
231
+ }
232
+ if (typeof obj[key] === "object") {
233
+ let parts2 = [...parts, key];
234
+
235
+ if (!scalarFieldAtLeaf(parts2)) {
236
+ handleSubtree(obj[key], tree[key], parts2);
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ function scalarFieldAtLeaf(pathFromRoot: string[]) {
243
+ let root = fields;
244
+ if (!root) {
245
+ return false;
246
+ }
247
+ let subField: GraphQLField<any, any, any> | undefined;
248
+ for (const p of pathFromRoot) {
249
+ subField = root?.[p];
250
+ if (subField) {
251
+ [subField] = getInnerType(subField.type, false);
252
+ if (subField instanceof GraphQLObjectType) {
253
+ root = subField.getFields();
254
+ }
255
+ }
256
+ }
257
+
258
+ if (!subField) {
259
+ return false;
260
+ }
261
+ return isScalarType(subField) || isEnumType(subField);
262
+ }
263
+
264
+ if (i === parts.length - 1 && typeof option[1] === "object") {
265
+ if (!scalarFieldAtLeaf(parts)) {
266
+ handleSubtree(option[1], tree, parts);
267
+ }
268
+ }
269
+ }
270
+ });
271
+ return topLevelTree;
272
+ }
273
+
274
+ function constructQueryFromTreePath(treePath: {}) {
275
+ let query: string[] = [];
276
+ for (let key in treePath) {
277
+ let value = treePath[key];
278
+ let valueStr = constructQueryFromTreePath(value);
279
+ if (!valueStr) {
280
+ // leaf node
281
+ query.push(key);
282
+ } else {
283
+ query.push(`${key}{${valueStr}}`);
284
+ }
285
+ }
286
+ return query.join(",");
287
+ }
288
+
289
+ function expectQueryResult(
290
+ schema: GraphQLSchema,
291
+ fieldType: GraphQLType,
292
+ ...options: Option[]
293
+ ) {
294
+ let topLevelTree = buildTreeFromQueryPaths(schema, fieldType, ...options);
295
+ // console.log(topLevelTree);
296
+
297
+ let query = constructQueryFromTreePath(topLevelTree);
298
+
299
+ // console.log(query);
300
+ return query;
301
+ }
302
+
303
+ export type Option = [string, any] | [string, any, string];
304
+
305
+ interface queryConfig {
306
+ // if neither viewer nor init is passed, we end with a logged out viewer
307
+ viewer?: Viewer;
308
+ // to init express e.g. session, passport initialize etc
309
+ init?: (app: Express) => void;
310
+ test?:
311
+ | supertest.SuperTest<supertest.Test>
312
+ | ((express: Express) => supertest.SuperTest<supertest.Test>);
313
+ // TODO
314
+ // if none indicated, defaults to logged out viewer
315
+ schema: GraphQLSchema;
316
+ headers?: object;
317
+ debugMode?: boolean;
318
+ args: {};
319
+ // any variables in here get added to the query as `$foo`, in query you should use
320
+ // $foo
321
+ extraVariables?: {
322
+ [key: string]: {
323
+ graphqlType: string;
324
+ value: string;
325
+ };
326
+ };
327
+ expectedStatus?: number; // expected http status code
328
+ expectedError?: string | RegExp; // expected error message
329
+ // todo there can be more than one etc
330
+ callback?: (res: supertest.Response) => void;
331
+ inlineFragmentRoot?: string;
332
+ customHandlers?: RequestHandler[];
333
+ server?: any;
334
+ graphQLPath?: string;
335
+ }
336
+
337
+ export interface queryRootConfig extends queryConfig {
338
+ root: string;
339
+ rootQueryNull?: boolean;
340
+ nullQueryPaths?: string[];
341
+ undefinedQueryPaths?: string[];
342
+ }
343
+
344
+ export async function expectQueryFromRoot(
345
+ config: queryRootConfig,
346
+ ...options: Option[] // TODO queries? expected values
347
+ ): Promise<supertest.SuperTest<supertest.Test>> {
348
+ return await expectFromRoot(
349
+ {
350
+ ...config,
351
+ queryPrefix: "query",
352
+ querySuffix: "Query",
353
+ queryFN: config.schema.getQueryType(),
354
+ },
355
+ ...options,
356
+ );
357
+ }
358
+
359
+ export interface mutationRootConfig extends queryConfig {
360
+ mutation: string;
361
+ disableInputWrapping?: boolean;
362
+ nullQueryPaths?: string[];
363
+ // rootQueryNull?: boolean;
364
+ }
365
+
366
+ export async function expectMutation(
367
+ config: mutationRootConfig,
368
+ ...options: Option[]
369
+ ): Promise<supertest.SuperTest<supertest.Test>> {
370
+ // wrap args in input because we simplify the args for mutations
371
+ // and don't require the input
372
+ let args = config.args;
373
+ if (!config.disableInputWrapping) {
374
+ args = {
375
+ input: args,
376
+ };
377
+ }
378
+
379
+ return await expectFromRoot(
380
+ {
381
+ ...config,
382
+ args: args,
383
+ root: config.mutation,
384
+ queryPrefix: "mutation",
385
+ querySuffix: "Mutation",
386
+ queryFN: config.schema.getMutationType(),
387
+ },
388
+ ...options,
389
+ );
390
+ }
391
+
392
+ interface rootConfig extends queryConfig {
393
+ queryFN: GraphQLObjectType<any, any> | null | undefined;
394
+ queryPrefix: string;
395
+ root: string;
396
+ querySuffix: string;
397
+ rootQueryNull?: boolean;
398
+ nullQueryPaths?: string[];
399
+ undefinedQueryPaths?: string[];
400
+ }
401
+
402
+ const fragmentRegex = /^...on (\w+)(.*)/;
403
+
404
+ function splitPath(path: string) {
405
+ // handle fragment queries. we don't want to compare against this when checking the result
406
+ // but we'll make sure to send to server
407
+ const match = fragmentRegex.exec(path);
408
+ if (!match) {
409
+ return path.split(".");
410
+ }
411
+ return match[2].split(".");
412
+ }
413
+
414
+ async function expectFromRoot(
415
+ config: rootConfig,
416
+ ...options: Option[]
417
+ ): Promise<supertest.SuperTest<supertest.Test>> {
418
+ let query = config.queryFN;
419
+ let fields = query?.getFields();
420
+ if (!fields) {
421
+ // TODO custom error?
422
+ throw new Error("schema doesn't have query or fields");
423
+ }
424
+ let field = fields[config.root];
425
+ if (!field) {
426
+ throw new Error(
427
+ `could not find field ${config.root} in GraphQL query schema`,
428
+ );
429
+ }
430
+ let fieldArgs = field.args;
431
+
432
+ let queryParams: string[] = [];
433
+ fieldArgs.forEach((fieldArg) => {
434
+ const arg = config.args[fieldArg.name];
435
+ // let the graphql runtime handle this (it may be optional for example)
436
+ if (arg === undefined) {
437
+ return;
438
+ }
439
+ queryParams.push(`$${fieldArg.name}: ${fieldArg.type}`);
440
+ });
441
+
442
+ // add extra variables in queryArgs...
443
+ for (const key in config.extraVariables) {
444
+ const v = config.extraVariables[key];
445
+ queryParams.push(`$${key}: ${v.graphqlType}`);
446
+ }
447
+
448
+ let params: string[] = [];
449
+ for (let key in config.args) {
450
+ params.push(`${key}: $${key}`);
451
+ }
452
+ let fieldType: GraphQLType = field.type;
453
+ if (config.inlineFragmentRoot) {
454
+ const rootType = config.schema.getType(config.inlineFragmentRoot);
455
+ if (!rootType) {
456
+ throw new Error(
457
+ `couldn't find inline fragment root ${config.inlineFragmentRoot} in the schema`,
458
+ );
459
+ }
460
+ fieldType = rootType;
461
+ }
462
+ let q = expectQueryResult(config.schema, fieldType, ...options);
463
+ let queryVar = "";
464
+ let callVar = "";
465
+ if (queryParams.length) {
466
+ queryVar = `(${queryParams.join(",")})`;
467
+ }
468
+ if (params.length) {
469
+ callVar = `(${params.join(",")})`;
470
+ }
471
+ let suffix = "";
472
+ if (q) {
473
+ // if no suffix part of query, don't put it there
474
+ suffix = `{${q}}`;
475
+ }
476
+ if (config.inlineFragmentRoot) {
477
+ suffix = `{...on ${config.inlineFragmentRoot}${suffix}}`;
478
+ }
479
+ q = `${config.queryPrefix} ${config.root}${config.querySuffix} ${queryVar} {
480
+ ${config.root}${callVar} ${suffix}
481
+ }`;
482
+
483
+ if (config.debugMode) {
484
+ console.log(q);
485
+ }
486
+ let [st, temp] = makeGraphQLRequest(config, q, fieldArgs);
487
+ const res = await temp.expect("Content-Type", /json/);
488
+ if (config.debugMode) {
489
+ console.log(inspect(res.body, false, 3));
490
+ }
491
+ // if there's a callback, let everything be done there and we're done
492
+ if (config.callback) {
493
+ config.callback(res);
494
+ return st;
495
+ }
496
+ if (config.expectedStatus !== undefined) {
497
+ expect(res.status).toBe(config.expectedStatus);
498
+ } else {
499
+ expect(
500
+ res.ok,
501
+ `expected ok response. instead got ${
502
+ res.status
503
+ } and result ${JSON.stringify(res.body)}`,
504
+ );
505
+ }
506
+
507
+ // res.ok = true in graphql-helix when there's errors...
508
+ // res.ok = false in express-graphql when there's errors...
509
+ if (!res.ok || (res.body.errors && res.body.errors.length > 0)) {
510
+ let errors: any[] = res.body.errors;
511
+ expect(errors.length).toBeGreaterThan(0);
512
+
513
+ if (config.expectedError) {
514
+ // todo multiple errors etc
515
+ expect(errors[0].message).toMatch(config.expectedError);
516
+ } else {
517
+ throw new Error(`unhandled error ${JSON.stringify(errors)}`);
518
+ }
519
+ return st;
520
+ }
521
+ let data = res.body.data;
522
+ let result = data[config.root];
523
+
524
+ if (config.rootQueryNull) {
525
+ expect(result, "root query wasn't null").toBe(null);
526
+ return st;
527
+ }
528
+
529
+ // special case. TODO needs to be handled better
530
+ if (options.length === 1) {
531
+ const parts = splitPath(options[0][0]);
532
+ if (parts.length == 1 && parts[0] === "") {
533
+ expect(options[0][1]).toStrictEqual(result);
534
+ return st;
535
+ }
536
+ }
537
+
538
+ await Promise.all(
539
+ options.map(async (option) => {
540
+ const path = option[0];
541
+ const expected = option[1];
542
+ const alias = option[2];
543
+
544
+ let nullPath: string | undefined;
545
+ let nullParts: string[] = [];
546
+ let undefinedPath: string | undefined;
547
+ let undefinedParts: string[] = [];
548
+ if (config.nullQueryPaths) {
549
+ for (let i = 0; i < config.nullQueryPaths.length; i++) {
550
+ if (path.startsWith(config.nullQueryPaths[i])) {
551
+ nullPath = config.nullQueryPaths[i];
552
+ nullParts = splitPath(nullPath);
553
+ break;
554
+ }
555
+ }
556
+ }
557
+ if (config.undefinedQueryPaths) {
558
+ for (let i = 0; i < config.undefinedQueryPaths.length; i++) {
559
+ if (path.startsWith(config.undefinedQueryPaths[i])) {
560
+ undefinedPath = config.undefinedQueryPaths[i];
561
+ undefinedParts = splitPath(undefinedPath);
562
+ break;
563
+ }
564
+ }
565
+ }
566
+
567
+ let parts = splitPath(alias ?? path);
568
+ let current = result;
569
+
570
+ // possible to make this smarter and better
571
+ // e.g. when building up the tree above
572
+ for (let i = 0; i < parts.length; i++) {
573
+ let part = parts[i];
574
+ let idx = part.indexOf("[");
575
+ let listIdx: number | undefined;
576
+
577
+ // list
578
+ if (idx !== -1) {
579
+ let endIdx = part.indexOf("]");
580
+ if (endIdx === -1) {
581
+ throw new Error(
582
+ "can't have a beginning index without an end index",
583
+ );
584
+ }
585
+ // get the idx we care about
586
+ listIdx = parseInt(part.substr(idx + 1, endIdx - idx), 10);
587
+
588
+ // update part
589
+ part = part.substr(0, idx);
590
+ }
591
+
592
+ idx = part.indexOf("(");
593
+ // function or arg call
594
+ if (idx !== -1) {
595
+ let endIdx = part.indexOf(")");
596
+ if (endIdx === -1) {
597
+ throw new Error(
598
+ "can't have a beginning index without an end index",
599
+ );
600
+ }
601
+ // update part
602
+ part = part.substr(0, idx);
603
+ }
604
+
605
+ // "" as root is ok.
606
+ if (part !== "") {
607
+ current = current[part];
608
+ }
609
+
610
+ if (listIdx !== undefined && nullPath?.indexOf("[") !== -1) {
611
+ current = current[listIdx];
612
+ }
613
+
614
+ // at the part of the path where it's expected to be null, confirm it is before proceeding
615
+ if (nullParts.length === i + 1) {
616
+ expect(current, `path ${nullPath} expected to be null`).toBe(null);
617
+ return st;
618
+ }
619
+
620
+ if (undefinedParts.length === i + 1) {
621
+ expect(
622
+ current,
623
+ `path ${undefinedPath} expected to be undefined`,
624
+ ).toBe(undefined);
625
+ return st;
626
+ }
627
+
628
+ if (listIdx !== undefined && nullPath?.indexOf("[") === -1) {
629
+ current = current[listIdx];
630
+ }
631
+
632
+ if (i === parts.length - 1) {
633
+ // leaf node, check the value
634
+ if (typeof expected === "function") {
635
+ // TODO eventually may need to batch this but fine for now
636
+ await expected(current);
637
+ } else {
638
+ expect(
639
+ current,
640
+ `value of ${part} in path ${path} was not as expected`,
641
+ ).toStrictEqual(expected);
642
+ }
643
+ } else {
644
+ expect(
645
+ part,
646
+ `found undefined node in path ${path} at subtree ${part}`,
647
+ ).not.toBe(undefined);
648
+ }
649
+ }
650
+ }),
651
+ );
652
+ return st;
653
+ }
@@ -0,0 +1,50 @@
1
+ export enum Mode {
2
+ SMS = 1,
3
+ EMAIL = 2,
4
+ }
5
+
6
+ export interface commsInput {
7
+ subject?: string;
8
+ body: string;
9
+ from: string;
10
+ to: string;
11
+ mode: Mode;
12
+ }
13
+
14
+ export class FakeComms {
15
+ private static sent: commsInput[] = [];
16
+
17
+ static send(option: commsInput) {
18
+ this.sent.push(option);
19
+ }
20
+
21
+ static async sendAsync(option: commsInput) {
22
+ await new Promise((resolve) => setTimeout(resolve, 10));
23
+ this.sent.push(option);
24
+ }
25
+
26
+ static verifySent(to: string, mode: Mode, opts?: { subject; body }) {
27
+ let sent = this.sent.filter(
28
+ (option) => option.to === to && option.mode === mode,
29
+ );
30
+ expect(sent.length).toBeGreaterThan(0);
31
+ if (opts) {
32
+ expect(sent[0].body).toBe(opts.body);
33
+ expect(sent[0].subject).toBe(opts.subject);
34
+ }
35
+ }
36
+
37
+ static getSent(to: string, mode: Mode) {
38
+ return this.sent.filter(
39
+ (option) => option.to === to && option.mode === mode,
40
+ );
41
+ }
42
+
43
+ static verifyNoEmailSent() {
44
+ expect(this.sent.length).toBe(0);
45
+ }
46
+
47
+ static clear() {
48
+ this.sent = [];
49
+ }
50
+ }