@stonecrop/graphql-client 0.11.1 → 0.11.3

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.
@@ -1,53 +0,0 @@
1
- import { gql } from 'graphql-request';
2
- /**
3
- * This is the schema for the GraphQL API.
4
- * @public
5
- */
6
- const typeDefs = gql `
7
- type Doctype {
8
- id: ID!
9
- name: String!
10
- workflow: String!
11
- schema: String!
12
- actions: String!
13
- }
14
-
15
- type DoctypeField {
16
- id: ID!
17
- label: String!
18
- fieldtype: String
19
- component: String
20
- required: Boolean
21
- readonly: Boolean
22
- }
23
-
24
- type DoctypeWorkflow {
25
- name: String!
26
- machine: StateMachine!
27
- }
28
-
29
- type StateMachine {
30
- id: ID!
31
- }
32
-
33
- type DoctypeAction {
34
- eventName: String!
35
- callback: String
36
- }
37
-
38
- type Query {
39
- getMeta(doctype: String!): Doctype # ∪ error
40
- getRecords(doctype: String!, filters: [String]): [String] # ∪ error
41
- getRecord(doctype: String!, id: ID!): String # ∪ error
42
- }
43
-
44
- type Mutation {
45
- runAction(doctype: String!, id: [ID!]!, functionName: String!): [String!]! # ∪ error
46
- }
47
-
48
- schema {
49
- query: Query
50
- mutation: Mutation
51
- }
52
- `;
53
- export default typeDefs;
package/dist/queries.js DELETED
@@ -1,19 +0,0 @@
1
- import { gql } from 'graphql-request';
2
- /**
3
- * Queries for the GraphQL API.
4
- * @public
5
- */
6
- const queries = {
7
- getMeta: gql `
8
- query getDoctype($doctype: String!) {
9
- getMeta(doctype: $doctype) {
10
- id
11
- name
12
- workflow
13
- schema
14
- actions
15
- }
16
- }
17
- `,
18
- };
19
- export { queries };
package/dist/query.js DELETED
@@ -1,231 +0,0 @@
1
- import { toPascalCase } from '@stonecrop/schema';
2
- import pluralize from 'pluralize';
3
- /**
4
- * Default sync limit for many-cardinality links
5
- */
6
- const DEFAULT_SYNC_LIMIT = 50;
7
- /**
8
- * Field types that are not scalar queryable fields.
9
- * Link fields are handled separately via sub-selections; relationship fields live in `links`.
10
- */
11
- const RELATION_FIELDTYPES = new Set(['Link']);
12
- /**
13
- * Build a GraphQL connection query to fetch a list of records.
14
- *
15
- * Only declares variables ($limit, $offset, $orderBy) that are actually used,
16
- * avoiding GraphQL spec violations from unused variable declarations.
17
- *
18
- * @param meta - Doctype metadata
19
- * @param connectionFieldName - Function to derive the connection field name from a table name
20
- * @param orderByTypeName - Function to derive the order-by type name from a table name
21
- * @param options - Query options (limit, offset, orderBy)
22
- * @returns GraphQL query string
23
- *
24
- * @public
25
- */
26
- export function buildListQuery(meta, connectionFieldName, orderByTypeName, options) {
27
- const fieldNames = queryableFieldNames(meta);
28
- const connectionName = connectionFieldName(meta.tableName);
29
- const orderByType = orderByTypeName(meta.tableName);
30
- const varDecls = [];
31
- const queryArgs = [];
32
- if (options?.limit) {
33
- varDecls.push('$limit: Int');
34
- queryArgs.push(`first: $limit`);
35
- }
36
- if (options?.offset) {
37
- varDecls.push('$offset: Int');
38
- queryArgs.push(`offset: $offset`);
39
- }
40
- if (options?.orderBy) {
41
- varDecls.push(`$orderBy: [${orderByType}!]`);
42
- queryArgs.push(`orderBy: $orderBy`);
43
- }
44
- const varStr = varDecls.length > 0 ? `(${varDecls.join(', ')})` : '';
45
- const argsStr = queryArgs.length > 0 ? `(${queryArgs.join(', ')})` : '';
46
- return `
47
- query GetRecords${varStr} {
48
- ${connectionName}${argsStr} {
49
- nodes {
50
- ${fieldNames}
51
- }
52
- }
53
- }
54
- `;
55
- }
56
- /**
57
- * Build a GraphQL query string from doctype metadata.
58
- *
59
- * Generates scalar field selections. When `includeNested` is set,
60
- * recursively includes descendant link sub-selections derived from
61
- * the doctype's `links` object.
62
- *
63
- * @param meta - Doctype metadata to build the query from
64
- * @param recordFieldName - Function to derive the query field name from a table name
65
- * @param recordArgName - Function to derive the argument name from a table name
66
- * @param recordArgType - Function to derive the argument type from a table name
67
- * @param registry - Doctype registry for resolving link targets. Required when includeNested is set.
68
- * @param options - Query options (includeNested, maxDepth)
69
- * @returns GraphQL query string
70
- *
71
- * @public
72
- */
73
- export function buildRecordQuery(meta, recordFieldName, recordArgName, recordArgType, registry, options) {
74
- const queryName = recordFieldName(meta.tableName);
75
- const argName = recordArgName(meta.tableName);
76
- const argType = recordArgType(meta.tableName);
77
- const seen = new Set([meta.slug || meta.name]);
78
- let selection = queryableFieldNames(meta);
79
- if (options?.includeNested && meta.links && registry) {
80
- const includeSet = Array.isArray(options.includeNested) ? new Set(options.includeNested) : null;
81
- const nestedSelections = buildNestedSelections(meta.links, meta.tableName, includeSet, registry, seen, 0, options.maxDepth);
82
- if (nestedSelections) {
83
- selection += '\n ' + nestedSelections;
84
- }
85
- }
86
- return `
87
- query GetRecord($${argName}: ${argType}) {
88
- ${queryName}(${argName}: $${argName}) {
89
- ${selection}
90
- }
91
- }
92
- `;
93
- }
94
- /**
95
- * Build nested sub-selections for descendant links
96
- * @internal
97
- */
98
- function buildNestedSelections(links, parentTableName, includeSet, registry, seen, depth, maxDepth) {
99
- if (maxDepth !== undefined && depth >= maxDepth)
100
- return '';
101
- const selections = [];
102
- for (const [fieldname, link] of Object.entries(links)) {
103
- if (maxDepth !== undefined && depth >= maxDepth)
104
- break;
105
- // Check blockWorkflows first - if true, it overrides the includeSet filter
106
- const effectiveBlockWorkflows = getEffectiveBlockWorkflows(link);
107
- const linkBlockWorkflowsExplicitTrue = link.blockWorkflows === true;
108
- // Check includeSet filter - but blockWorkflows: true bypasses this filter
109
- if (includeSet && !includeSet.has(fieldname) && !linkBlockWorkflowsExplicitTrue) {
110
- continue;
111
- }
112
- // Check fetch strategy - skip if not sync (unless blockWorkflows overrides)
113
- const effectiveFetch = getEffectiveFetchStrategy(link);
114
- const shouldSkip = effectiveBlockWorkflows === false || (effectiveFetch.method !== 'sync' && !linkBlockWorkflowsExplicitTrue);
115
- if (shouldSkip) {
116
- continue;
117
- }
118
- // TODO: When blockWorkflows is true with custom fetch, this currently forces the link into
119
- // GraphQL queries, bypassing the custom handler. This is a workaround — custom handlers
120
- // should be able to satisfy blockWorkflows on their own schedule. Future enhancement:
121
- // - Option: Add SchemaValidator error for custom + blockWorkflows (blocking is impossible)
122
- // - Option: Track pending custom fetches and only unblock when all custom handlers complete
123
- // See: relationships.md Phase 6 "Open Question: blockWorkflows + custom fetch"
124
- const targetMeta = registry.get(link.target);
125
- if (!targetMeta)
126
- continue;
127
- const alreadySeen = seen.has(link.target);
128
- if (alreadySeen) {
129
- // Self-referential: include scalar fields only, don't modify seen
130
- }
131
- else {
132
- seen.add(link.target);
133
- }
134
- const scalarFields = queryableFieldNames(targetMeta);
135
- let nestedLinks = '';
136
- if (!alreadySeen && targetMeta.links && targetMeta.tableName && (maxDepth === undefined || depth + 1 < maxDepth)) {
137
- const innerSelections = buildNestedSelections(targetMeta.links, targetMeta.tableName, null, registry, seen, depth + 1, maxDepth);
138
- if (innerSelections) {
139
- nestedLinks = '\n ' + innerSelections;
140
- }
141
- seen.delete(link.target);
142
- }
143
- const fullSelection = scalarFields + nestedLinks;
144
- if (isManyCardinality(link.cardinality)) {
145
- const connectionField = getConnectionFieldName(targetMeta, parentTableName);
146
- const limitArg = effectiveFetch.method === 'sync' && effectiveFetch.limit !== undefined
147
- ? `first: ${effectiveFetch.limit}`
148
- : effectiveFetch.method === 'sync'
149
- ? `first: ${DEFAULT_SYNC_LIMIT}`
150
- : '';
151
- selections.push(`
152
- ${connectionField}${limitArg ? `(${limitArg})` : ''} {
153
- nodes {
154
- ${fullSelection}
155
- }
156
- }`);
157
- }
158
- else {
159
- selections.push(`
160
- ${fieldname} {
161
- ${fullSelection}
162
- }`);
163
- }
164
- }
165
- return selections.join('');
166
- }
167
- /**
168
- * Get the effective fetch strategy for a link, applying cardinality-based defaults.
169
- *
170
- * - `fetch` explicitly set → use it
171
- * - `fetch` absent → apply defaults:
172
- * - `noneOrMany`/`atLeastOne` → `{ method: 'sync', limit: 50 }`
173
- * - `one`/`atMostOne` → `{ method: 'lazy' }`
174
- *
175
- * @internal
176
- */
177
- function getEffectiveFetchStrategy(link) {
178
- if (link.fetch !== undefined) {
179
- return link.fetch;
180
- }
181
- // Apply cardinality-based defaults
182
- if (isManyCardinality(link.cardinality)) {
183
- return { method: 'sync', limit: DEFAULT_SYNC_LIMIT };
184
- }
185
- else {
186
- return { method: 'lazy' };
187
- }
188
- }
189
- /**
190
- * Get the effective blockWorkflows value for a link.
191
- * Returns true if blockWorkflows is explicitly true, or if it's absent and fetch method is 'sync'.
192
- * @internal
193
- */
194
- function getEffectiveBlockWorkflows(link) {
195
- if (link.blockWorkflows !== undefined) {
196
- return link.blockWorkflows;
197
- }
198
- const effectiveFetch = getEffectiveFetchStrategy(link);
199
- return effectiveFetch.method === 'sync';
200
- }
201
- /**
202
- * Get scalar field names for a doctype, excluding Link and Doctype fields
203
- * @internal
204
- */
205
- function queryableFieldNames(meta) {
206
- return meta.fields
207
- .filter(f => !RELATION_FIELDTYPES.has(f.fieldtype))
208
- .map(f => f.fieldname)
209
- .join('\n ');
210
- }
211
- /**
212
- * Check if a cardinality value represents a 1:many relationship
213
- * @internal
214
- */
215
- function isManyCardinality(cardinality) {
216
- return cardinality === 'noneOrMany' || cardinality === 'atLeastOne';
217
- }
218
- /**
219
- * Derive a PostGraphile connection field name from a target doctype and parent table name.
220
- *
221
- * PostGraphile convention: `{targetPlural}By{ParentTablePascal}Id`
222
- * Example: recipe_task with parent recipe → `recipeTasksByRecipeId`
223
- *
224
- * @internal
225
- */
226
- function getConnectionFieldName(targetMeta, parentTableName) {
227
- const targetPlural = pluralize.plural(targetMeta.tableName);
228
- const targetPascal = toPascalCase(targetPlural);
229
- const fkPascal = toPascalCase(parentTableName) + 'Id';
230
- return `${targetPascal}By${fkPascal}`;
231
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * This is the schema for the GraphQL API.
3
- * @public
4
- */
5
- declare const typeDefs: string;
6
- export default typeDefs;
7
- //# sourceMappingURL=schema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/gql/schema.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,QAAA,MAAM,QAAQ,QA8Cb,CAAA;AAED,eAAe,QAAQ,CAAA"}
@@ -1,9 +0,0 @@
1
- /**
2
- * Queries for the GraphQL API.
3
- * @public
4
- */
5
- declare const queries: {
6
- getMeta: string;
7
- };
8
- export { queries };
9
- //# sourceMappingURL=queries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/queries.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,QAAA,MAAM,OAAO;;CAYZ,CAAA;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
@@ -1,35 +0,0 @@
1
- import type { DoctypeMeta, GetRecordOptions, GetRecordsOptions } from '@stonecrop/schema';
2
- /**
3
- * Build a GraphQL connection query to fetch a list of records.
4
- *
5
- * Only declares variables ($limit, $offset, $orderBy) that are actually used,
6
- * avoiding GraphQL spec violations from unused variable declarations.
7
- *
8
- * @param meta - Doctype metadata
9
- * @param connectionFieldName - Function to derive the connection field name from a table name
10
- * @param orderByTypeName - Function to derive the order-by type name from a table name
11
- * @param options - Query options (limit, offset, orderBy)
12
- * @returns GraphQL query string
13
- *
14
- * @public
15
- */
16
- export declare function buildListQuery(meta: DoctypeMeta, connectionFieldName: (t: string) => string, orderByTypeName: (t: string) => string, options?: GetRecordsOptions): string;
17
- /**
18
- * Build a GraphQL query string from doctype metadata.
19
- *
20
- * Generates scalar field selections. When `includeNested` is set,
21
- * recursively includes descendant link sub-selections derived from
22
- * the doctype's `links` object.
23
- *
24
- * @param meta - Doctype metadata to build the query from
25
- * @param recordFieldName - Function to derive the query field name from a table name
26
- * @param recordArgName - Function to derive the argument name from a table name
27
- * @param recordArgType - Function to derive the argument type from a table name
28
- * @param registry - Doctype registry for resolving link targets. Required when includeNested is set.
29
- * @param options - Query options (includeNested, maxDepth)
30
- * @returns GraphQL query string
31
- *
32
- * @public
33
- */
34
- export declare function buildRecordQuery(meta: DoctypeMeta, recordFieldName: (t: string) => string, recordArgName: (t: string) => string, recordArgType: (t: string) => string, registry?: Map<string, DoctypeMeta>, options?: GetRecordOptions): string;
35
- //# sourceMappingURL=query.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EAIjB,MAAM,mBAAmB,CAAA;AAe1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC7B,IAAI,EAAE,WAAW,EACjB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAC1C,eAAe,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACtC,OAAO,CAAC,EAAE,iBAAiB,GACzB,MAAM,CAgCR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,WAAW,EACjB,eAAe,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACtC,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACpC,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EACpC,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,OAAO,CAAC,EAAE,gBAAgB,GACxB,MAAM,CAkCR"}
@@ -1,6 +0,0 @@
1
- declare module '*.gql' {
2
- import { DocumentNode } from 'graphql'
3
- const Schema: DocumentNode
4
-
5
- export = Schema
6
- }
@@ -1,45 +0,0 @@
1
- type Doctype {
2
- id: ID!
3
- name: String!
4
- workflow: DoctypeWorkflow!
5
- schema: [DoctypeField!]!
6
- actions: [DoctypeActions!]!
7
- }
8
-
9
- type DoctypeField {
10
- id: ID!
11
- label: String!
12
- fieldtype: String
13
- component: String
14
- required: Boolean
15
- readonly: Boolean
16
- }
17
-
18
- type DoctypeWorkflow {
19
- name: String!
20
- machine: StateMachine!
21
- }
22
-
23
- type StateMachine {
24
- id: ID!
25
- }
26
-
27
- type DoctypeAction {
28
- eventName: String!
29
- callback: String
30
- }
31
-
32
- type Query {
33
- getMeta(doctype: String!): Doctype # ∪ error
34
- getRecords(doctype: String!, filters: Filters): [Record] # ∪ error
35
- getRecord(doctype: String!, id: ID!): Record # ∪ error
36
- }
37
-
38
- type Mutation {
39
- runAction(doctype: String!, id: [ID!]!, functionName: String!): [Record!]! # ∪ error
40
- }
41
-
42
- schema {
43
- query: Query
44
- mutation: Mutation
45
- }
package/src/gql/schema.ts DELETED
@@ -1,55 +0,0 @@
1
- import { gql } from 'graphql-request'
2
-
3
- /**
4
- * This is the schema for the GraphQL API.
5
- * @public
6
- */
7
- const typeDefs = gql`
8
- type Doctype {
9
- id: ID!
10
- name: String!
11
- workflow: String!
12
- schema: String!
13
- actions: String!
14
- }
15
-
16
- type DoctypeField {
17
- id: ID!
18
- label: String!
19
- fieldtype: String
20
- component: String
21
- required: Boolean
22
- readonly: Boolean
23
- }
24
-
25
- type DoctypeWorkflow {
26
- name: String!
27
- machine: StateMachine!
28
- }
29
-
30
- type StateMachine {
31
- id: ID!
32
- }
33
-
34
- type DoctypeAction {
35
- eventName: String!
36
- callback: String
37
- }
38
-
39
- type Query {
40
- getMeta(doctype: String!): Doctype # ∪ error
41
- getRecords(doctype: String!, filters: [String]): [String] # ∪ error
42
- getRecord(doctype: String!, id: ID!): String # ∪ error
43
- }
44
-
45
- type Mutation {
46
- runAction(doctype: String!, id: [ID!]!, functionName: String!): [String!]! # ∪ error
47
- }
48
-
49
- schema {
50
- query: Query
51
- mutation: Mutation
52
- }
53
- `
54
-
55
- export default typeDefs
package/src/queries.ts DELETED
@@ -1,21 +0,0 @@
1
- import { gql } from 'graphql-request'
2
-
3
- /**
4
- * Queries for the GraphQL API.
5
- * @public
6
- */
7
- const queries = {
8
- getMeta: gql`
9
- query getDoctype($doctype: String!) {
10
- getMeta(doctype: $doctype) {
11
- id
12
- name
13
- workflow
14
- schema
15
- actions
16
- }
17
- }
18
- `,
19
- }
20
-
21
- export { queries }