@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.
- package/dist/package.json +64 -0
- package/package.json +52 -7
- package/src/action/action.ts +330 -0
- package/src/action/executor.ts +453 -0
- package/src/action/experimental_action.ts +277 -0
- package/src/action/index.ts +31 -0
- package/src/action/operations.ts +967 -0
- package/src/action/orchestrator.ts +1527 -0
- package/src/action/privacy.ts +37 -0
- package/src/action/relative_value.ts +242 -0
- package/src/action/transaction.ts +38 -0
- package/src/auth/auth.ts +77 -0
- package/src/auth/index.ts +8 -0
- package/src/core/base.ts +367 -0
- package/src/core/clause.ts +1065 -0
- package/src/core/config.ts +219 -0
- package/src/core/const.ts +5 -0
- package/src/core/context.ts +135 -0
- package/src/core/convert.ts +106 -0
- package/src/core/date.ts +23 -0
- package/src/core/db.ts +498 -0
- package/src/core/ent.ts +1740 -0
- package/src/core/global_schema.ts +49 -0
- package/src/core/loaders/assoc_count_loader.ts +99 -0
- package/src/core/loaders/assoc_edge_loader.ts +250 -0
- package/src/core/loaders/index.ts +12 -0
- package/src/core/loaders/loader.ts +66 -0
- package/src/core/loaders/object_loader.ts +489 -0
- package/src/core/loaders/query_loader.ts +314 -0
- package/src/core/loaders/raw_count_loader.ts +175 -0
- package/src/core/logger.ts +49 -0
- package/src/core/privacy.ts +660 -0
- package/src/core/query/assoc_query.ts +240 -0
- package/src/core/query/custom_clause_query.ts +174 -0
- package/src/core/query/custom_query.ts +302 -0
- package/src/core/query/index.ts +9 -0
- package/src/core/query/query.ts +674 -0
- package/src/core/query_impl.ts +32 -0
- package/src/core/viewer.ts +52 -0
- package/src/ent.code-workspace +73 -0
- package/src/graphql/builtins/connection.ts +25 -0
- package/src/graphql/builtins/edge.ts +16 -0
- package/src/graphql/builtins/node.ts +12 -0
- package/src/graphql/graphql.ts +891 -0
- package/src/graphql/graphql_field_helpers.ts +221 -0
- package/src/graphql/index.ts +42 -0
- package/src/graphql/mutations/union.ts +39 -0
- package/src/graphql/node_resolver.ts +122 -0
- package/src/graphql/query/connection_type.ts +113 -0
- package/src/graphql/query/edge_connection.ts +171 -0
- package/src/graphql/query/page_info.ts +34 -0
- package/src/graphql/query/shared_edge_connection.ts +287 -0
- package/src/graphql/scalars/orderby_direction.ts +13 -0
- package/src/graphql/scalars/time.ts +38 -0
- package/src/imports/dataz/example1/_auth.ts +51 -0
- package/src/imports/dataz/example1/_viewer.ts +35 -0
- package/src/imports/index.ts +213 -0
- package/src/index.ts +145 -0
- package/src/parse_schema/parse.ts +585 -0
- package/src/schema/base_schema.ts +224 -0
- package/src/schema/field.ts +1087 -0
- package/src/schema/index.ts +53 -0
- package/src/schema/json_field.ts +94 -0
- package/src/schema/schema.ts +1028 -0
- package/src/schema/struct_field.ts +234 -0
- package/src/schema/union_field.ts +105 -0
- package/src/scripts/custom_compiler.ts +331 -0
- package/src/scripts/custom_graphql.ts +550 -0
- package/src/scripts/migrate_v0.1.ts +41 -0
- package/src/scripts/move_types.ts +131 -0
- package/src/scripts/read_schema.ts +67 -0
- package/src/setupPackage.js +42 -0
- package/src/testutils/action/complex_schemas.ts +517 -0
- package/src/testutils/builder.ts +422 -0
- package/src/testutils/context/test_context.ts +25 -0
- package/src/testutils/db/fixture.ts +32 -0
- package/src/testutils/db/temp_db.ts +941 -0
- package/src/testutils/db/value.ts +294 -0
- package/src/testutils/db_mock.ts +351 -0
- package/src/testutils/db_time_zone.ts +40 -0
- package/src/testutils/ent-graphql-tests/index.ts +653 -0
- package/src/testutils/fake_comms.ts +50 -0
- package/src/testutils/fake_data/const.ts +64 -0
- package/src/testutils/fake_data/events_query.ts +145 -0
- package/src/testutils/fake_data/fake_contact.ts +150 -0
- package/src/testutils/fake_data/fake_event.ts +150 -0
- package/src/testutils/fake_data/fake_tag.ts +139 -0
- package/src/testutils/fake_data/fake_user.ts +232 -0
- package/src/testutils/fake_data/index.ts +1 -0
- package/src/testutils/fake_data/internal.ts +8 -0
- package/src/testutils/fake_data/tag_query.ts +56 -0
- package/src/testutils/fake_data/test_helpers.ts +388 -0
- package/src/testutils/fake_data/user_query.ts +524 -0
- package/src/testutils/fake_log.ts +52 -0
- package/src/testutils/mock_date.ts +10 -0
- package/src/testutils/mock_log.ts +39 -0
- package/src/testutils/parse_sql.ts +685 -0
- package/src/testutils/test_edge_global_schema.ts +49 -0
- package/src/testutils/write.ts +70 -0
- package/src/tsc/ast.ts +351 -0
- package/src/tsc/compilerOptions.ts +85 -0
- package/src/tsc/move_generated.ts +191 -0
- package/src/tsc/transform.ts +226 -0
- package/src/tsc/transform_action.ts +224 -0
- package/src/tsc/transform_ent.ts +66 -0
- package/src/tsc/transform_schema.ts +546 -0
- package/tsconfig.json +20 -0
- package/core/query/shared_assoc_test.d.ts +0 -2
- package/core/query/shared_assoc_test.js +0 -804
- package/core/query/shared_test.d.ts +0 -21
- package/core/query/shared_test.js +0 -736
- package/graphql/query/shared_assoc_test.d.ts +0 -1
- package/graphql/query/shared_assoc_test.js +0 -203
- /package/{action → dist/action}/action.d.ts +0 -0
- /package/{action → dist/action}/action.js +0 -0
- /package/{action → dist/action}/executor.d.ts +0 -0
- /package/{action → dist/action}/executor.js +0 -0
- /package/{action → dist/action}/experimental_action.d.ts +0 -0
- /package/{action → dist/action}/experimental_action.js +0 -0
- /package/{action → dist/action}/index.d.ts +0 -0
- /package/{action → dist/action}/index.js +0 -0
- /package/{action → dist/action}/operations.d.ts +0 -0
- /package/{action → dist/action}/operations.js +0 -0
- /package/{action → dist/action}/orchestrator.d.ts +0 -0
- /package/{action → dist/action}/orchestrator.js +0 -0
- /package/{action → dist/action}/privacy.d.ts +0 -0
- /package/{action → dist/action}/privacy.js +0 -0
- /package/{action → dist/action}/relative_value.d.ts +0 -0
- /package/{action → dist/action}/relative_value.js +0 -0
- /package/{action → dist/action}/transaction.d.ts +0 -0
- /package/{action → dist/action}/transaction.js +0 -0
- /package/{auth → dist/auth}/auth.d.ts +0 -0
- /package/{auth → dist/auth}/auth.js +0 -0
- /package/{auth → dist/auth}/index.d.ts +0 -0
- /package/{auth → dist/auth}/index.js +0 -0
- /package/{core → dist/core}/base.d.ts +0 -0
- /package/{core → dist/core}/base.js +0 -0
- /package/{core → dist/core}/clause.d.ts +0 -0
- /package/{core → dist/core}/clause.js +0 -0
- /package/{core → dist/core}/config.d.ts +0 -0
- /package/{core → dist/core}/config.js +0 -0
- /package/{core → dist/core}/const.d.ts +0 -0
- /package/{core → dist/core}/const.js +0 -0
- /package/{core → dist/core}/context.d.ts +0 -0
- /package/{core → dist/core}/context.js +0 -0
- /package/{core → dist/core}/convert.d.ts +0 -0
- /package/{core → dist/core}/convert.js +0 -0
- /package/{core → dist/core}/date.d.ts +0 -0
- /package/{core → dist/core}/date.js +0 -0
- /package/{core → dist/core}/db.d.ts +0 -0
- /package/{core → dist/core}/db.js +0 -0
- /package/{core → dist/core}/ent.d.ts +0 -0
- /package/{core → dist/core}/ent.js +0 -0
- /package/{core → dist/core}/global_schema.d.ts +0 -0
- /package/{core → dist/core}/global_schema.js +0 -0
- /package/{core → dist/core}/loaders/assoc_count_loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/assoc_count_loader.js +0 -0
- /package/{core → dist/core}/loaders/assoc_edge_loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/assoc_edge_loader.js +0 -0
- /package/{core → dist/core}/loaders/index.d.ts +0 -0
- /package/{core → dist/core}/loaders/index.js +0 -0
- /package/{core → dist/core}/loaders/loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/loader.js +0 -0
- /package/{core → dist/core}/loaders/object_loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/object_loader.js +0 -0
- /package/{core → dist/core}/loaders/query_loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/query_loader.js +0 -0
- /package/{core → dist/core}/loaders/raw_count_loader.d.ts +0 -0
- /package/{core → dist/core}/loaders/raw_count_loader.js +0 -0
- /package/{core → dist/core}/logger.d.ts +0 -0
- /package/{core → dist/core}/logger.js +0 -0
- /package/{core → dist/core}/privacy.d.ts +0 -0
- /package/{core → dist/core}/privacy.js +0 -0
- /package/{core → dist/core}/query/assoc_query.d.ts +0 -0
- /package/{core → dist/core}/query/assoc_query.js +0 -0
- /package/{core → dist/core}/query/custom_clause_query.d.ts +0 -0
- /package/{core → dist/core}/query/custom_clause_query.js +0 -0
- /package/{core → dist/core}/query/custom_query.d.ts +0 -0
- /package/{core → dist/core}/query/custom_query.js +0 -0
- /package/{core → dist/core}/query/index.d.ts +0 -0
- /package/{core → dist/core}/query/index.js +0 -0
- /package/{core → dist/core}/query/query.d.ts +0 -0
- /package/{core → dist/core}/query/query.js +0 -0
- /package/{core → dist/core}/query_impl.d.ts +0 -0
- /package/{core → dist/core}/query_impl.js +0 -0
- /package/{core → dist/core}/viewer.d.ts +0 -0
- /package/{core → dist/core}/viewer.js +0 -0
- /package/{graphql → dist/graphql}/builtins/connection.d.ts +0 -0
- /package/{graphql → dist/graphql}/builtins/connection.js +0 -0
- /package/{graphql → dist/graphql}/builtins/edge.d.ts +0 -0
- /package/{graphql → dist/graphql}/builtins/edge.js +0 -0
- /package/{graphql → dist/graphql}/builtins/node.d.ts +0 -0
- /package/{graphql → dist/graphql}/builtins/node.js +0 -0
- /package/{graphql → dist/graphql}/graphql.d.ts +0 -0
- /package/{graphql → dist/graphql}/graphql.js +0 -0
- /package/{graphql → dist/graphql}/graphql_field_helpers.d.ts +0 -0
- /package/{graphql → dist/graphql}/graphql_field_helpers.js +0 -0
- /package/{graphql → dist/graphql}/index.d.ts +0 -0
- /package/{graphql → dist/graphql}/index.js +0 -0
- /package/{graphql → dist/graphql}/mutations/union.d.ts +0 -0
- /package/{graphql → dist/graphql}/mutations/union.js +0 -0
- /package/{graphql → dist/graphql}/node_resolver.d.ts +0 -0
- /package/{graphql → dist/graphql}/node_resolver.js +0 -0
- /package/{graphql → dist/graphql}/query/connection_type.d.ts +0 -0
- /package/{graphql → dist/graphql}/query/connection_type.js +0 -0
- /package/{graphql → dist/graphql}/query/edge_connection.d.ts +0 -0
- /package/{graphql → dist/graphql}/query/edge_connection.js +0 -0
- /package/{graphql → dist/graphql}/query/page_info.d.ts +0 -0
- /package/{graphql → dist/graphql}/query/page_info.js +0 -0
- /package/{graphql → dist/graphql}/query/shared_edge_connection.d.ts +0 -0
- /package/{graphql → dist/graphql}/query/shared_edge_connection.js +0 -0
- /package/{graphql → dist/graphql}/scalars/orderby_direction.d.ts +0 -0
- /package/{graphql → dist/graphql}/scalars/orderby_direction.js +0 -0
- /package/{graphql → dist/graphql}/scalars/time.d.ts +0 -0
- /package/{graphql → dist/graphql}/scalars/time.js +0 -0
- /package/{imports → dist/imports}/dataz/example1/_auth.d.ts +0 -0
- /package/{imports → dist/imports}/dataz/example1/_auth.js +0 -0
- /package/{imports → dist/imports}/dataz/example1/_viewer.d.ts +0 -0
- /package/{imports → dist/imports}/dataz/example1/_viewer.js +0 -0
- /package/{imports → dist/imports}/index.d.ts +0 -0
- /package/{imports → dist/imports}/index.js +0 -0
- /package/{index.d.ts → dist/index.d.ts} +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{parse_schema → dist/parse_schema}/parse.d.ts +0 -0
- /package/{parse_schema → dist/parse_schema}/parse.js +0 -0
- /package/{schema → dist/schema}/base_schema.d.ts +0 -0
- /package/{schema → dist/schema}/base_schema.js +0 -0
- /package/{schema → dist/schema}/field.d.ts +0 -0
- /package/{schema → dist/schema}/field.js +0 -0
- /package/{schema → dist/schema}/index.d.ts +0 -0
- /package/{schema → dist/schema}/index.js +0 -0
- /package/{schema → dist/schema}/json_field.d.ts +0 -0
- /package/{schema → dist/schema}/json_field.js +0 -0
- /package/{schema → dist/schema}/schema.d.ts +0 -0
- /package/{schema → dist/schema}/schema.js +0 -0
- /package/{schema → dist/schema}/struct_field.d.ts +0 -0
- /package/{schema → dist/schema}/struct_field.js +0 -0
- /package/{schema → dist/schema}/union_field.d.ts +0 -0
- /package/{schema → dist/schema}/union_field.js +0 -0
- /package/{scripts → dist/scripts}/custom_compiler.d.ts +0 -0
- /package/{scripts → dist/scripts}/custom_compiler.js +0 -0
- /package/{scripts → dist/scripts}/custom_graphql.d.ts +0 -0
- /package/{scripts → dist/scripts}/custom_graphql.js +0 -0
- /package/{scripts → dist/scripts}/migrate_v0.1.d.ts +0 -0
- /package/{scripts → dist/scripts}/migrate_v0.1.js +0 -0
- /package/{scripts → dist/scripts}/move_types.d.ts +0 -0
- /package/{scripts → dist/scripts}/move_types.js +0 -0
- /package/{scripts → dist/scripts}/read_schema.d.ts +0 -0
- /package/{scripts → dist/scripts}/read_schema.js +0 -0
- /package/{testutils → dist/testutils}/action/complex_schemas.d.ts +0 -0
- /package/{testutils → dist/testutils}/action/complex_schemas.js +0 -0
- /package/{testutils → dist/testutils}/builder.d.ts +0 -0
- /package/{testutils → dist/testutils}/builder.js +0 -0
- /package/{testutils → dist/testutils}/context/test_context.d.ts +0 -0
- /package/{testutils → dist/testutils}/context/test_context.js +0 -0
- /package/{testutils → dist/testutils}/db/fixture.d.ts +0 -0
- /package/{testutils → dist/testutils}/db/fixture.js +0 -0
- /package/{testutils → dist/testutils}/db/temp_db.d.ts +0 -0
- /package/{testutils → dist/testutils}/db/temp_db.js +0 -0
- /package/{testutils → dist/testutils}/db/value.d.ts +0 -0
- /package/{testutils → dist/testutils}/db/value.js +0 -0
- /package/{testutils → dist/testutils}/db_mock.d.ts +0 -0
- /package/{testutils → dist/testutils}/db_mock.js +0 -0
- /package/{testutils → dist/testutils}/db_time_zone.d.ts +0 -0
- /package/{testutils → dist/testutils}/db_time_zone.js +0 -0
- /package/{testutils → dist/testutils}/ent-graphql-tests/index.d.ts +0 -0
- /package/{testutils → dist/testutils}/ent-graphql-tests/index.js +0 -0
- /package/{testutils → dist/testutils}/fake_comms.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_comms.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/const.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/const.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/events_query.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/events_query.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_contact.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_contact.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_event.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_event.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_tag.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_tag.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_user.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/fake_user.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/index.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/index.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/internal.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/internal.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/tag_query.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/tag_query.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/test_helpers.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/test_helpers.js +0 -0
- /package/{testutils → dist/testutils}/fake_data/user_query.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_data/user_query.js +0 -0
- /package/{testutils → dist/testutils}/fake_log.d.ts +0 -0
- /package/{testutils → dist/testutils}/fake_log.js +0 -0
- /package/{testutils → dist/testutils}/mock_date.d.ts +0 -0
- /package/{testutils → dist/testutils}/mock_date.js +0 -0
- /package/{testutils → dist/testutils}/mock_log.d.ts +0 -0
- /package/{testutils → dist/testutils}/mock_log.js +0 -0
- /package/{testutils → dist/testutils}/parse_sql.d.ts +0 -0
- /package/{testutils → dist/testutils}/parse_sql.js +0 -0
- /package/{testutils → dist/testutils}/test_edge_global_schema.d.ts +0 -0
- /package/{testutils → dist/testutils}/test_edge_global_schema.js +0 -0
- /package/{testutils → dist/testutils}/write.d.ts +0 -0
- /package/{testutils → dist/testutils}/write.js +0 -0
- /package/{tsc → dist/tsc}/ast.d.ts +0 -0
- /package/{tsc → dist/tsc}/ast.js +0 -0
- /package/{tsc → dist/tsc}/compilerOptions.d.ts +0 -0
- /package/{tsc → dist/tsc}/compilerOptions.js +0 -0
- /package/{tsc → dist/tsc}/move_generated.d.ts +0 -0
- /package/{tsc → dist/tsc}/move_generated.js +0 -0
- /package/{tsc → dist/tsc}/transform.d.ts +0 -0
- /package/{tsc → dist/tsc}/transform.js +0 -0
- /package/{tsc → dist/tsc}/transform_action.d.ts +0 -0
- /package/{tsc → dist/tsc}/transform_action.js +0 -0
- /package/{tsc → dist/tsc}/transform_ent.d.ts +0 -0
- /package/{tsc → dist/tsc}/transform_ent.js +0 -0
- /package/{tsc → dist/tsc}/transform_schema.d.ts +0 -0
- /package/{tsc → dist/tsc}/transform_schema.js +0 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GQLCapture,
|
|
3
|
+
CustomField,
|
|
4
|
+
Field,
|
|
5
|
+
CustomObject,
|
|
6
|
+
CustomMutation,
|
|
7
|
+
CustomQuery,
|
|
8
|
+
CustomType,
|
|
9
|
+
CustomTypeInput,
|
|
10
|
+
} from "./graphql";
|
|
11
|
+
|
|
12
|
+
export function validateOneCustomField(expected: CustomField) {
|
|
13
|
+
let customFields = GQLCapture.getCustomFields();
|
|
14
|
+
// only 1 node
|
|
15
|
+
expect(customFields.size).toBe(1);
|
|
16
|
+
let fields = customFields.get(expected.nodeName);
|
|
17
|
+
expect(fields).toBeDefined();
|
|
18
|
+
validateCustomFieldImpl(expected, fields![0]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function validateCustomFieldsImpl(
|
|
22
|
+
expected: CustomField[],
|
|
23
|
+
actual: CustomField[],
|
|
24
|
+
) {
|
|
25
|
+
expect(actual.length).toBe(expected.length);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < actual.length; i++) {
|
|
28
|
+
let customField = actual[i];
|
|
29
|
+
let expectedCustomField = expected[i];
|
|
30
|
+
validateCustomFieldImpl(expectedCustomField, customField);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function validateCustomFieldImpl(
|
|
35
|
+
expectedCustomField: CustomField,
|
|
36
|
+
customField: CustomField,
|
|
37
|
+
) {
|
|
38
|
+
expect(customField.nodeName).toBe(expectedCustomField.nodeName);
|
|
39
|
+
expect(customField.functionName).toBe(expectedCustomField.functionName);
|
|
40
|
+
expect(customField.gqlName).toBe(expectedCustomField.gqlName);
|
|
41
|
+
expect(customField.fieldType).toBe(expectedCustomField.fieldType);
|
|
42
|
+
|
|
43
|
+
validateFields(customField.results, expectedCustomField.results);
|
|
44
|
+
|
|
45
|
+
validateFields(customField.args, expectedCustomField.args);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// we keep the simple API for the client and map to what the underlying data structure supports...
|
|
49
|
+
export function validateCustomFields(expected: CustomField[]) {
|
|
50
|
+
let map = new Map<string, CustomField[]>();
|
|
51
|
+
expected.forEach((field) => {
|
|
52
|
+
let list = map.get(field.nodeName);
|
|
53
|
+
|
|
54
|
+
if (list === undefined) {
|
|
55
|
+
list = [field];
|
|
56
|
+
map.set(field.nodeName, list);
|
|
57
|
+
} else {
|
|
58
|
+
list.push(field);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let customFields = GQLCapture.getCustomFields();
|
|
63
|
+
|
|
64
|
+
expect(map.size).toEqual(customFields.size);
|
|
65
|
+
|
|
66
|
+
for (const [key, list] of customFields) {
|
|
67
|
+
let expFields = map.get(key);
|
|
68
|
+
expect(expFields).toBeDefined();
|
|
69
|
+
|
|
70
|
+
validateCustomFieldsImpl(expFields!, list);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function validateCustomMutations(expected: CustomMutation[]) {
|
|
75
|
+
validateCustomFieldsImpl(expected, GQLCapture.getCustomMutations());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function validateCustomQueries(expected: CustomQuery[]) {
|
|
79
|
+
validateCustomFieldsImpl(expected, GQLCapture.getCustomQueries());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function validateFields(actual: Field[], expected: Field[]) {
|
|
83
|
+
expect(actual.length).toBe(expected.length);
|
|
84
|
+
|
|
85
|
+
for (let j = 0; j < actual.length; j++) {
|
|
86
|
+
let field = actual[j];
|
|
87
|
+
let expField = expected[j];
|
|
88
|
+
|
|
89
|
+
expect(field.type).toBe(expField.type);
|
|
90
|
+
expect(field.name).toBe(expField.name);
|
|
91
|
+
expect(field.needsResolving, field.name).toBe(expField.needsResolving);
|
|
92
|
+
expect(field.nullable, field.name).toBe(expField.nullable);
|
|
93
|
+
expect(field.isContextArg, field.name).toBe(expField.isContextArg);
|
|
94
|
+
|
|
95
|
+
// TODO set this for everyone and then don't need this...
|
|
96
|
+
if (expField.tsType) {
|
|
97
|
+
expect(field.tsType).toBe(expField.tsType);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function validateNoCustomFields() {
|
|
103
|
+
expect(GQLCapture.getCustomFields().size).toBe(0);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function validateCustom(
|
|
107
|
+
expected: CustomObject[],
|
|
108
|
+
actual: Map<string, CustomObject>,
|
|
109
|
+
) {
|
|
110
|
+
expect(actual.size).toBe(expected.length);
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < expected.length; i++) {
|
|
113
|
+
let expectedObj = expected[i];
|
|
114
|
+
let obj = actual.get(expectedObj.className);
|
|
115
|
+
expect(obj).not.toBe(undefined);
|
|
116
|
+
// let arg = args[i];
|
|
117
|
+
|
|
118
|
+
expect(obj!.className).toBe(expectedObj.className);
|
|
119
|
+
expect(obj!.nodeName).toBe(expectedObj.nodeName);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function validateCustomArgs(expected: CustomObject[]) {
|
|
124
|
+
validateCustom(expected, GQLCapture.getCustomArgs());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function validateCustomInputObjects(expected: CustomObject[]) {
|
|
128
|
+
validateCustom(expected, GQLCapture.getCustomInputObjects());
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function validateCustomObjects(expected: CustomObject[]) {
|
|
132
|
+
validateCustom(expected, GQLCapture.getCustomObjects());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function validateCustomInterfaces(expected: CustomObject[]) {
|
|
136
|
+
validateCustom(expected, GQLCapture.getCustomInterfaces());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function validateCustomUnions(expected: CustomObject[]) {
|
|
140
|
+
validateCustom(expected, GQLCapture.getCustomUnions());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function validateNoCustomArgs() {
|
|
144
|
+
expect(GQLCapture.getCustomArgs().size).toBe(0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function validateNoCustomQueries() {
|
|
148
|
+
expect(GQLCapture.getCustomQueries().length).toBe(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function validateNoCustomMutations() {
|
|
152
|
+
expect(GQLCapture.getCustomMutations().length).toBe(0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function validateNoCustomInputObjects() {
|
|
156
|
+
expect(GQLCapture.getCustomInputObjects().size).toBe(0);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function validateNoCustomObjects() {
|
|
160
|
+
expect(GQLCapture.getCustomObjects().size).toBe(0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function validateNoCustomTypes() {
|
|
164
|
+
expect(GQLCapture.getCustomTypes().size).toBe(0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function validateNoCustomInterfaces() {
|
|
168
|
+
expect(GQLCapture.getCustomInterfaces().size).toBe(0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function validateNoCustomUnions() {
|
|
172
|
+
expect(GQLCapture.getCustomUnions().size).toBe(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export enum CustomObjectTypes {
|
|
176
|
+
Field = 0x1,
|
|
177
|
+
Arg = 0x2,
|
|
178
|
+
Object = 0x4,
|
|
179
|
+
InputObject = 0x8,
|
|
180
|
+
Query = 0x10,
|
|
181
|
+
Mutation = 0x20,
|
|
182
|
+
CustomTypes = 0x40,
|
|
183
|
+
Interface = 0x80,
|
|
184
|
+
Union = 0x100,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// what's a good name for this instead?
|
|
188
|
+
export function validateNoCustom(...exceptions: number[]) {
|
|
189
|
+
let bit = 0;
|
|
190
|
+
exceptions.forEach((exp) => (bit = bit | exp));
|
|
191
|
+
const validate = (typ: CustomObjectTypes, validateFn: () => void) => {
|
|
192
|
+
if (!(bit & typ)) {
|
|
193
|
+
validateFn();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
validate(CustomObjectTypes.Field, validateNoCustomFields);
|
|
197
|
+
validate(CustomObjectTypes.Arg, validateNoCustomArgs);
|
|
198
|
+
validate(CustomObjectTypes.Object, validateNoCustomObjects);
|
|
199
|
+
validate(CustomObjectTypes.Query, validateNoCustomQueries);
|
|
200
|
+
validate(CustomObjectTypes.Mutation, validateNoCustomMutations);
|
|
201
|
+
validate(CustomObjectTypes.InputObject, validateNoCustomInputObjects);
|
|
202
|
+
validate(CustomObjectTypes.CustomTypes, validateNoCustomTypes);
|
|
203
|
+
validate(CustomObjectTypes.Interface, validateNoCustomInterfaces);
|
|
204
|
+
validate(CustomObjectTypes.Union, validateNoCustomUnions);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function validateCustomTypes(expected: CustomTypeInput[]) {
|
|
208
|
+
const actual = GQLCapture.getCustomTypes();
|
|
209
|
+
expect(actual.size).toBe(expected.length);
|
|
210
|
+
|
|
211
|
+
for (let i = 0; i < expected.length; i++) {
|
|
212
|
+
let expectedObj = expected[i];
|
|
213
|
+
let obj = actual.get(expectedObj.type);
|
|
214
|
+
expect(obj).not.toBe(undefined);
|
|
215
|
+
|
|
216
|
+
expect(obj!.type).toBe(expectedObj.type);
|
|
217
|
+
expect(obj!.importPath).toBe(expectedObj.importPath);
|
|
218
|
+
expect(obj!.tsType).toBe(expectedObj.tsType);
|
|
219
|
+
expect(obj!.tsImportPath).toBe(expectedObj.tsImportPath);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export {
|
|
2
|
+
gqlFieldOptions,
|
|
3
|
+
gqlObjectOptions,
|
|
4
|
+
gqlField,
|
|
5
|
+
gqlArgType,
|
|
6
|
+
gqlInputObjectType,
|
|
7
|
+
gqlObjectType,
|
|
8
|
+
gqlQuery,
|
|
9
|
+
gqlMutation,
|
|
10
|
+
gqlContextType,
|
|
11
|
+
gqlConnection,
|
|
12
|
+
GraphQLConnection,
|
|
13
|
+
GQLCapture,
|
|
14
|
+
gqlFileUpload,
|
|
15
|
+
CustomType,
|
|
16
|
+
gqlInterfaceType,
|
|
17
|
+
gqlUnionType,
|
|
18
|
+
} from "./graphql";
|
|
19
|
+
|
|
20
|
+
export { GraphQLTime } from "./scalars/time";
|
|
21
|
+
export { GraphQLOrderByDirection } from "./scalars/orderby_direction";
|
|
22
|
+
export { GraphQLPageInfo } from "./query/page_info";
|
|
23
|
+
export { GraphQLEdge, GraphQLEdgeConnection } from "./query/edge_connection";
|
|
24
|
+
export {
|
|
25
|
+
GraphQLEdgeType,
|
|
26
|
+
GraphQLConnectionType,
|
|
27
|
+
} from "./query/connection_type";
|
|
28
|
+
export { GraphQLNodeInterface } from "./builtins/node";
|
|
29
|
+
export { GraphQLConnectionInterface } from "./builtins/connection";
|
|
30
|
+
export { GraphQLEdgeInterface } from "./builtins/edge";
|
|
31
|
+
export {
|
|
32
|
+
NodeResolver,
|
|
33
|
+
EntNodeResolver,
|
|
34
|
+
registerResolver,
|
|
35
|
+
clearResolvers,
|
|
36
|
+
resolveID,
|
|
37
|
+
nodeIDEncoder,
|
|
38
|
+
mustDecodeIDFromGQLID,
|
|
39
|
+
mustDecodeNullableIDFromGQLID,
|
|
40
|
+
encodeGQLID,
|
|
41
|
+
} from "./node_resolver";
|
|
42
|
+
export { transformUnionTypes } from "./mutations/union";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Data } from "../../core/base";
|
|
2
|
+
|
|
3
|
+
// this transforms an input for union types from graphql format to TS format
|
|
4
|
+
// in graphql, we represent it as UnionType = {foo: FooType, bar: BarType, baz: BazType}
|
|
5
|
+
// in TS, we repseent it as UnionType = FooType | BarType | BazType
|
|
6
|
+
// this takes an input, paths to unions and transforms them as needed
|
|
7
|
+
// only works on fields that are defined. depends on graphql to handle nullable/missing fields
|
|
8
|
+
export function transformUnionTypes<T extends Data>(
|
|
9
|
+
input: T,
|
|
10
|
+
pathsList: string[][],
|
|
11
|
+
) {
|
|
12
|
+
for (const paths of pathsList) {
|
|
13
|
+
const lastPath = paths[paths.length - 1];
|
|
14
|
+
let last: Data = input;
|
|
15
|
+
for (const path of paths) {
|
|
16
|
+
let curr = last[path];
|
|
17
|
+
|
|
18
|
+
if (curr === undefined) {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
if (path === lastPath) {
|
|
22
|
+
let count = 0;
|
|
23
|
+
let lastKey: string | undefined = undefined;
|
|
24
|
+
for (const k in curr) {
|
|
25
|
+
count++;
|
|
26
|
+
lastKey = k;
|
|
27
|
+
}
|
|
28
|
+
if (count != 1) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`can only only pass one key of union. passed ${count}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
last[path] = curr[lastKey!];
|
|
34
|
+
}
|
|
35
|
+
last = curr;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return input;
|
|
39
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ID, Ent, Viewer } from "../core/base";
|
|
2
|
+
import { loadEnt } from "../core/ent";
|
|
3
|
+
import { GraphQLFieldResolver } from "graphql";
|
|
4
|
+
|
|
5
|
+
interface Node {
|
|
6
|
+
id: ID;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface NodeResolver {
|
|
10
|
+
decodeObj(viewer: Viewer, id: string): Promise<Node | null>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// generated loadEntByType signature....
|
|
14
|
+
interface loadEnt {
|
|
15
|
+
(v: Viewer, nodeType: string, id: ID): Promise<Ent | null>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class EntNodeResolver implements NodeResolver {
|
|
19
|
+
constructor(private loader: loadEnt) {}
|
|
20
|
+
|
|
21
|
+
encode(node: Ent): string {
|
|
22
|
+
// let's do 3 parts. we take the "node" prefix
|
|
23
|
+
const str = `node:${node.nodeType}:${node.id}`;
|
|
24
|
+
return Buffer.from(str, "ascii").toString("base64");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static decode(id: string): ID | null {
|
|
28
|
+
const decoded = Buffer.from(id, "base64").toString("ascii");
|
|
29
|
+
let parts = decoded.split(":");
|
|
30
|
+
if (parts.length != 3) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return parts[2];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mustDecode(id: string): [ID, string] {
|
|
37
|
+
const decoded = Buffer.from(id, "base64").toString("ascii");
|
|
38
|
+
let parts = decoded.split(":");
|
|
39
|
+
if (parts.length != 3) {
|
|
40
|
+
throw new Error(`invalid id ${id} passed to EntNodeResolver`);
|
|
41
|
+
}
|
|
42
|
+
return [parts[0], parts[1]];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async decodeObj(viewer: Viewer, id: string): Promise<Node | null> {
|
|
46
|
+
const decoded = Buffer.from(id, "base64").toString("ascii");
|
|
47
|
+
let parts = decoded.split(":");
|
|
48
|
+
if (parts.length != 3 || parts[0] != "node") {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return this.loader(viewer, parts[1], parts[2]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let resolvers: Map<string, NodeResolver> = new Map();
|
|
56
|
+
|
|
57
|
+
// used to register a new NodeResolver
|
|
58
|
+
export async function registerResolver(name: string, resolver: NodeResolver) {
|
|
59
|
+
resolvers.set(name, resolver);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// mainly needed for tests
|
|
63
|
+
export async function clearResolvers() {
|
|
64
|
+
resolvers.clear();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function resolveID(
|
|
68
|
+
viewer: Viewer,
|
|
69
|
+
id: string,
|
|
70
|
+
): Promise<Node | null> {
|
|
71
|
+
for (const [_, resolver] of resolvers) {
|
|
72
|
+
const node = await resolver.decodeObj(viewer, id);
|
|
73
|
+
if (node !== null) {
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// this takes an id and uses the default node resolver which
|
|
81
|
+
// should have been registered as part of entcodegen and decodes
|
|
82
|
+
export const nodeIDEncoder: GraphQLFieldResolver<Ent, {}> = (
|
|
83
|
+
source: Ent,
|
|
84
|
+
_args: {},
|
|
85
|
+
) => {
|
|
86
|
+
const r = resolvers.get("entNode") as EntNodeResolver;
|
|
87
|
+
if (!r) {
|
|
88
|
+
throw new Error(`cannot resolve id when entNode not previously registered`);
|
|
89
|
+
}
|
|
90
|
+
return r.encode(source);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// This takes a GraphQL id and converts it to an ent id
|
|
94
|
+
export function mustDecodeIDFromGQLID(id: string): ID {
|
|
95
|
+
const decoded = EntNodeResolver.decode(id);
|
|
96
|
+
if (!decoded) {
|
|
97
|
+
throw new Error(`wasn't able to decode invalid ${id}`);
|
|
98
|
+
}
|
|
99
|
+
return decoded;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// TODO get the right (non-any) return type here. may need to change codegen to do the right thing here
|
|
103
|
+
export function mustDecodeNullableIDFromGQLID(
|
|
104
|
+
id: string | null | undefined,
|
|
105
|
+
): any {
|
|
106
|
+
// support undefined because fields in action
|
|
107
|
+
if (id === null || id === undefined) {
|
|
108
|
+
return id;
|
|
109
|
+
}
|
|
110
|
+
const decoded = EntNodeResolver.decode(id);
|
|
111
|
+
if (!decoded) {
|
|
112
|
+
throw new Error(`wasn't able to decode invalid ${id}`);
|
|
113
|
+
}
|
|
114
|
+
return decoded;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// This takes an ent and returns the graphql id
|
|
118
|
+
export function encodeGQLID(node: Ent): string {
|
|
119
|
+
// let's do 3 parts. we take the "node" prefix
|
|
120
|
+
const str = `node:${node.nodeType}:${node.id}`;
|
|
121
|
+
return Buffer.from(str, "ascii").toString("base64");
|
|
122
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GraphQLFieldConfigMap,
|
|
3
|
+
GraphQLInt,
|
|
4
|
+
GraphQLList,
|
|
5
|
+
GraphQLNonNull,
|
|
6
|
+
GraphQLObjectType,
|
|
7
|
+
GraphQLInterfaceType,
|
|
8
|
+
GraphQLString,
|
|
9
|
+
} from "graphql";
|
|
10
|
+
import { RequestContext } from "../../core/context";
|
|
11
|
+
import { GraphQLEdge, GraphQLEdgeConnection } from "./edge_connection";
|
|
12
|
+
import { GraphQLPageInfo } from "./page_info";
|
|
13
|
+
import { GraphQLEdgeInterface } from "../builtins/edge";
|
|
14
|
+
import { GraphQLConnectionInterface } from "../builtins/connection";
|
|
15
|
+
import { Data, Ent, Viewer } from "../../core/base";
|
|
16
|
+
|
|
17
|
+
type nodeType = GraphQLObjectType | GraphQLInterfaceType;
|
|
18
|
+
export class GraphQLEdgeType<
|
|
19
|
+
TNode extends nodeType,
|
|
20
|
+
TEdge extends Data,
|
|
21
|
+
TViewer extends Viewer,
|
|
22
|
+
> extends GraphQLObjectType {
|
|
23
|
+
constructor(
|
|
24
|
+
name: string,
|
|
25
|
+
nodeType: TNode,
|
|
26
|
+
optionalFields?: () => GraphQLFieldConfigMap<
|
|
27
|
+
GraphQLEdge<TEdge>,
|
|
28
|
+
RequestContext<TViewer>
|
|
29
|
+
>,
|
|
30
|
+
) {
|
|
31
|
+
let optional:
|
|
32
|
+
| GraphQLFieldConfigMap<GraphQLEdge<TEdge>, RequestContext<TViewer>>
|
|
33
|
+
| undefined;
|
|
34
|
+
if (optionalFields) {
|
|
35
|
+
optional = optionalFields();
|
|
36
|
+
}
|
|
37
|
+
super({
|
|
38
|
+
name: `${name}Edge`,
|
|
39
|
+
fields: (): GraphQLFieldConfigMap<
|
|
40
|
+
GraphQLEdge<TEdge>,
|
|
41
|
+
RequestContext<TViewer>
|
|
42
|
+
> => ({
|
|
43
|
+
node: {
|
|
44
|
+
type: new GraphQLNonNull(nodeType),
|
|
45
|
+
},
|
|
46
|
+
cursor: {
|
|
47
|
+
type: new GraphQLNonNull(GraphQLString),
|
|
48
|
+
},
|
|
49
|
+
...optional,
|
|
50
|
+
}),
|
|
51
|
+
interfaces: [GraphQLEdgeInterface],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface connectionOptions<T extends Data, TViewer extends Viewer> {
|
|
57
|
+
fields?(): GraphQLFieldConfigMap<GraphQLEdge<T>, RequestContext<TViewer>>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class GraphQLConnectionType<
|
|
61
|
+
TNode extends nodeType,
|
|
62
|
+
TEdge extends Data,
|
|
63
|
+
TViewer extends Viewer,
|
|
64
|
+
> extends GraphQLObjectType {
|
|
65
|
+
edgeType: GraphQLEdgeType<TNode, TEdge, TViewer>;
|
|
66
|
+
constructor(
|
|
67
|
+
name: string,
|
|
68
|
+
nodeType: TNode,
|
|
69
|
+
options?: connectionOptions<TEdge, TViewer>,
|
|
70
|
+
) {
|
|
71
|
+
const edgeType = new GraphQLEdgeType(name, nodeType, options?.fields);
|
|
72
|
+
|
|
73
|
+
super({
|
|
74
|
+
name: `${name}Connection`,
|
|
75
|
+
fields: (): GraphQLFieldConfigMap<
|
|
76
|
+
GraphQLEdgeConnection<Ent, TEdge, TViewer>,
|
|
77
|
+
RequestContext<TViewer>
|
|
78
|
+
> => ({
|
|
79
|
+
edges: {
|
|
80
|
+
type: new GraphQLNonNull(
|
|
81
|
+
new GraphQLList(new GraphQLNonNull(edgeType)),
|
|
82
|
+
),
|
|
83
|
+
resolve: (source: GraphQLEdgeConnection<Ent, TEdge, TViewer>) => {
|
|
84
|
+
return source.queryEdges();
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
nodes: {
|
|
88
|
+
type: new GraphQLNonNull(
|
|
89
|
+
new GraphQLList(new GraphQLNonNull(nodeType)),
|
|
90
|
+
),
|
|
91
|
+
resolve: (source: GraphQLEdgeConnection<Ent, TEdge, TViewer>) => {
|
|
92
|
+
return source.queryNodes();
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
pageInfo: {
|
|
96
|
+
type: new GraphQLNonNull(GraphQLPageInfo),
|
|
97
|
+
resolve: (source: GraphQLEdgeConnection<Ent, TEdge, TViewer>) => {
|
|
98
|
+
return source.queryPageInfo();
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
rawCount: {
|
|
102
|
+
type: new GraphQLNonNull(GraphQLInt),
|
|
103
|
+
resolve: (source: GraphQLEdgeConnection<Ent, TEdge, TViewer>) => {
|
|
104
|
+
return source.queryTotalCount();
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
interfaces: [GraphQLConnectionInterface],
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
this.edgeType = edgeType;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { EdgeQuery, PaginationInfo } from "../../core/query/query";
|
|
2
|
+
import { Data, Ent, ID, Viewer } from "../../core/base";
|
|
3
|
+
|
|
4
|
+
// TODO getCursor...
|
|
5
|
+
export interface GraphQLEdge<T extends Data> {
|
|
6
|
+
edge: T;
|
|
7
|
+
node: Ent;
|
|
8
|
+
cursor: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface edgeQueryCtr<
|
|
12
|
+
T extends Ent,
|
|
13
|
+
TEdge extends Data,
|
|
14
|
+
TViewer extends Viewer,
|
|
15
|
+
> {
|
|
16
|
+
(v: TViewer, src: T): EdgeQuery<T, Ent, TEdge>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface edgeQueryCtr2<
|
|
20
|
+
T extends Ent,
|
|
21
|
+
TEdge extends Data,
|
|
22
|
+
TViewer extends Viewer,
|
|
23
|
+
> {
|
|
24
|
+
(v: TViewer): EdgeQuery<T, Ent, TEdge>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// TODO probably need to template Ent. maybe 2 ents?
|
|
28
|
+
export class GraphQLEdgeConnection<
|
|
29
|
+
TSource extends Ent,
|
|
30
|
+
TEdge extends Data,
|
|
31
|
+
TViewer extends Viewer = Viewer,
|
|
32
|
+
> {
|
|
33
|
+
query: EdgeQuery<TSource, Ent, TEdge>;
|
|
34
|
+
private results: GraphQLEdge<TEdge>[] = [];
|
|
35
|
+
private viewer: TViewer;
|
|
36
|
+
private source?: TSource;
|
|
37
|
+
private args?: Data;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
viewer: TViewer,
|
|
41
|
+
source: TSource,
|
|
42
|
+
getQuery: edgeQueryCtr<TSource, TEdge, TViewer>,
|
|
43
|
+
args?: Data,
|
|
44
|
+
);
|
|
45
|
+
constructor(
|
|
46
|
+
viewer: TViewer,
|
|
47
|
+
getQuery: edgeQueryCtr2<TSource, TEdge, TViewer>,
|
|
48
|
+
args?: Data,
|
|
49
|
+
);
|
|
50
|
+
constructor(
|
|
51
|
+
viewer: TViewer,
|
|
52
|
+
arg2: TSource | edgeQueryCtr2<TSource, TEdge, TViewer>,
|
|
53
|
+
arg3: edgeQueryCtr<TSource, TEdge, TViewer> | Data,
|
|
54
|
+
args?: Data,
|
|
55
|
+
) {
|
|
56
|
+
this.viewer = viewer;
|
|
57
|
+
if (typeof arg2 === "function") {
|
|
58
|
+
this.query = arg2(this.viewer);
|
|
59
|
+
} else {
|
|
60
|
+
this.source = arg2;
|
|
61
|
+
}
|
|
62
|
+
if (typeof arg3 === "function") {
|
|
63
|
+
this.query = arg3(this.viewer, this.source!);
|
|
64
|
+
} else {
|
|
65
|
+
this.args = arg3;
|
|
66
|
+
}
|
|
67
|
+
if (args !== undefined) {
|
|
68
|
+
this.args = args;
|
|
69
|
+
}
|
|
70
|
+
if (this.args) {
|
|
71
|
+
if (this.args.after && !this.args.first) {
|
|
72
|
+
throw new Error("cannot process after without first");
|
|
73
|
+
}
|
|
74
|
+
if (this.args.before && !this.args.before) {
|
|
75
|
+
throw new Error("cannot process before without last");
|
|
76
|
+
}
|
|
77
|
+
if (this.args.first) {
|
|
78
|
+
this.query = this.query.first(this.args.first, this.args.after);
|
|
79
|
+
}
|
|
80
|
+
if (this.args.last) {
|
|
81
|
+
this.query = this.query.last(this.args.last, this.args.cursor);
|
|
82
|
+
}
|
|
83
|
+
// TODO custom args
|
|
84
|
+
// how to proceed
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
first(limit: number, cursor?: string) {
|
|
89
|
+
this.query = this.query.first(limit, cursor);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
last(limit: number, cursor?: string) {
|
|
93
|
+
this.query = this.query.last(limit, cursor);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// any custom filters can be applied here...
|
|
97
|
+
modifyQuery(
|
|
98
|
+
fn: (
|
|
99
|
+
query: EdgeQuery<TSource, Ent, TEdge>,
|
|
100
|
+
) => EdgeQuery<TSource, Ent, TEdge>,
|
|
101
|
+
) {
|
|
102
|
+
this.query = fn(this.query);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async queryTotalCount() {
|
|
106
|
+
return await this.query.queryRawCount();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async queryEdges() {
|
|
110
|
+
// because of privacy, we need to query the node regardless of if the node is there
|
|
111
|
+
// otherwise we'd be returning a phantom edge that doesn't actually exist
|
|
112
|
+
await this.queryData();
|
|
113
|
+
return this.results;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// if nodes queried just return ents
|
|
117
|
+
// unlikely to query nodes and pageInfo so we just load this separately for now
|
|
118
|
+
async queryNodes() {
|
|
119
|
+
return await this.query.queryEnts();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private defaultPageInfo() {
|
|
123
|
+
return {
|
|
124
|
+
hasNextPage: false,
|
|
125
|
+
hasPreviousPage: false,
|
|
126
|
+
startCursor: "",
|
|
127
|
+
endCursor: "",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async queryPageInfo(): Promise<PaginationInfo> {
|
|
132
|
+
await this.queryData();
|
|
133
|
+
const paginationInfo = this.query.paginationInfo();
|
|
134
|
+
if (this.source !== undefined) {
|
|
135
|
+
return paginationInfo.get(this.source.id) || this.defaultPageInfo();
|
|
136
|
+
}
|
|
137
|
+
if (paginationInfo.size > 1) {
|
|
138
|
+
throw new Error(`Query mas more than one item yet no source was given`);
|
|
139
|
+
}
|
|
140
|
+
for (const [_, value] of paginationInfo) {
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
return this.defaultPageInfo();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private async queryData() {
|
|
147
|
+
const [edges, ents] = await Promise.all([
|
|
148
|
+
// TODO need a test that this will only fetch edges once
|
|
149
|
+
// and then fetch ents afterward
|
|
150
|
+
this.query.queryEdges(),
|
|
151
|
+
this.query.queryEnts(),
|
|
152
|
+
]);
|
|
153
|
+
|
|
154
|
+
let entsMap = new Map<ID, Ent>();
|
|
155
|
+
ents.forEach((ent) => entsMap.set(ent.id, ent));
|
|
156
|
+
|
|
157
|
+
let results: GraphQLEdge<TEdge>[] = [];
|
|
158
|
+
for (const edge of edges) {
|
|
159
|
+
const node = entsMap.get(this.query.dataToID(edge));
|
|
160
|
+
if (!node) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
results.push({
|
|
164
|
+
edge,
|
|
165
|
+
node,
|
|
166
|
+
cursor: this.query.getCursor(edge),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
this.results = results;
|
|
170
|
+
}
|
|
171
|
+
}
|