@commitspark/graphql-api 1.0.0 → 2.0.0-beta.2
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/CHANGELOG.md +15 -0
- package/README.md +87 -4
- package/dist/cjs/client.d.ts +4 -2
- package/dist/cjs/client.js +4 -2
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/graphql/errors.d.ts +3 -2
- package/dist/cjs/graphql/errors.js.map +1 -1
- package/dist/cjs/graphql/input-type-generator.js +2 -1
- package/dist/cjs/graphql/input-type-generator.js.map +1 -1
- package/dist/cjs/graphql/queries-mutations-generator.d.ts +8 -1
- package/dist/cjs/graphql/queries-mutations-generator.js +19 -0
- package/dist/cjs/graphql/queries-mutations-generator.js.map +1 -1
- package/dist/cjs/graphql/resolvers/field-resolvers/field-default-value-resolver.js +2 -1
- package/dist/cjs/graphql/resolvers/field-resolvers/field-default-value-resolver.js.map +1 -1
- package/dist/cjs/graphql/resolvers/query-mutation-resolvers/query-search-resolver.d.ts +2 -0
- package/dist/cjs/graphql/resolvers/query-mutation-resolvers/query-search-resolver.js +74 -0
- package/dist/cjs/graphql/resolvers/query-mutation-resolvers/query-search-resolver.js.map +1 -0
- package/dist/cjs/graphql/resolvers/types.d.ts +6 -0
- package/dist/cjs/graphql/schema-analyzer.js +2 -1
- package/dist/cjs/graphql/schema-analyzer.js.map +1 -1
- package/dist/cjs/graphql/schema-generator.js +7 -1
- package/dist/cjs/graphql/schema-generator.js.map +1 -1
- package/dist/cjs/graphql/schema-root-type-generator.d.ts +2 -2
- package/dist/cjs/graphql/schema-root-type-generator.js +2 -1
- package/dist/cjs/graphql/schema-root-type-generator.js.map +1 -1
- package/dist/cjs/graphql/schema-utils/directive-util.d.ts +4 -0
- package/dist/cjs/graphql/schema-utils/directive-util.js +10 -0
- package/dist/cjs/graphql/schema-utils/directive-util.js.map +1 -0
- package/dist/cjs/graphql/schema-utils/entry-reference-util.js +3 -1
- package/dist/cjs/graphql/schema-utils/entry-reference-util.js.map +1 -1
- package/dist/cjs/graphql/schema-utils/entry-type-util.d.ts +1 -2
- package/dist/cjs/graphql/schema-utils/entry-type-util.js +2 -6
- package/dist/cjs/graphql/schema-utils/entry-type-util.js.map +1 -1
- package/dist/cjs/graphql/schema-utils/searchable-field-util.d.ts +4 -0
- package/dist/cjs/graphql/schema-utils/searchable-field-util.js +79 -0
- package/dist/cjs/graphql/schema-utils/searchable-field-util.js.map +1 -0
- package/dist/cjs/graphql/schema-validator.js +21 -3
- package/dist/cjs/graphql/schema-validator.js.map +1 -1
- package/dist/cjs/index.d.ts +9 -2
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/persistence/cache.js +76 -27
- package/dist/cjs/persistence/cache.js.map +1 -1
- package/dist/esm/client.js +4 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/graphql/errors.js.map +1 -1
- package/dist/esm/graphql/input-type-generator.js +3 -2
- package/dist/esm/graphql/input-type-generator.js.map +1 -1
- package/dist/esm/graphql/queries-mutations-generator.js +18 -0
- package/dist/esm/graphql/queries-mutations-generator.js.map +1 -1
- package/dist/esm/graphql/resolvers/field-resolvers/field-default-value-resolver.js +3 -2
- package/dist/esm/graphql/resolvers/field-resolvers/field-default-value-resolver.js.map +1 -1
- package/dist/esm/graphql/resolvers/query-mutation-resolvers/query-search-resolver.js +70 -0
- package/dist/esm/graphql/resolvers/query-mutation-resolvers/query-search-resolver.js.map +1 -0
- package/dist/esm/graphql/schema-analyzer.js +2 -1
- package/dist/esm/graphql/schema-analyzer.js.map +1 -1
- package/dist/esm/graphql/schema-generator.js +8 -2
- package/dist/esm/graphql/schema-generator.js.map +1 -1
- package/dist/esm/graphql/schema-root-type-generator.js +2 -1
- package/dist/esm/graphql/schema-root-type-generator.js.map +1 -1
- package/dist/esm/graphql/schema-utils/directive-util.js +6 -0
- package/dist/esm/graphql/schema-utils/directive-util.js.map +1 -0
- package/dist/esm/graphql/schema-utils/entry-reference-util.js +4 -2
- package/dist/esm/graphql/schema-utils/entry-reference-util.js.map +1 -1
- package/dist/esm/graphql/schema-utils/entry-type-util.js +2 -5
- package/dist/esm/graphql/schema-utils/entry-type-util.js.map +1 -1
- package/dist/esm/graphql/schema-utils/searchable-field-util.js +76 -0
- package/dist/esm/graphql/schema-utils/searchable-field-util.js.map +1 -0
- package/dist/esm/graphql/schema-validator.js +22 -4
- package/dist/esm/graphql/schema-validator.js.map +1 -1
- package/dist/esm/index.js +4 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/persistence/cache.js +76 -27
- package/dist/esm/persistence/cache.js.map +1 -1
- package/dist/types/client.d.ts +4 -2
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/graphql/errors.d.ts +3 -2
- package/dist/types/graphql/errors.d.ts.map +1 -1
- package/dist/types/graphql/input-type-generator.d.ts.map +1 -1
- package/dist/types/graphql/queries-mutations-generator.d.ts +8 -1
- package/dist/types/graphql/queries-mutations-generator.d.ts.map +1 -1
- package/dist/types/graphql/resolvers/field-resolvers/field-default-value-resolver.d.ts.map +1 -1
- package/dist/types/graphql/resolvers/query-mutation-resolvers/query-search-resolver.d.ts +3 -0
- package/dist/types/graphql/resolvers/query-mutation-resolvers/query-search-resolver.d.ts.map +1 -0
- package/dist/types/graphql/resolvers/types.d.ts +6 -0
- package/dist/types/graphql/resolvers/types.d.ts.map +1 -1
- package/dist/types/graphql/schema-analyzer.d.ts.map +1 -1
- package/dist/types/graphql/schema-generator.d.ts.map +1 -1
- package/dist/types/graphql/schema-root-type-generator.d.ts +2 -2
- package/dist/types/graphql/schema-root-type-generator.d.ts.map +1 -1
- package/dist/types/graphql/schema-utils/directive-util.d.ts +5 -0
- package/dist/types/graphql/schema-utils/directive-util.d.ts.map +1 -0
- package/dist/types/graphql/schema-utils/entry-reference-util.d.ts.map +1 -1
- package/dist/types/graphql/schema-utils/entry-type-util.d.ts +1 -2
- package/dist/types/graphql/schema-utils/entry-type-util.d.ts.map +1 -1
- package/dist/types/graphql/schema-utils/searchable-field-util.d.ts +5 -0
- package/dist/types/graphql/schema-utils/searchable-field-util.d.ts.map +1 -0
- package/dist/types/graphql/schema-validator.d.ts.map +1 -1
- package/dist/types/index.d.ts +9 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence/cache.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/client.ts +6 -0
- package/src/graphql/errors.ts +3 -2
- package/src/graphql/input-type-generator.ts +5 -4
- package/src/graphql/queries-mutations-generator.ts +31 -1
- package/src/graphql/resolvers/field-resolvers/field-default-value-resolver.ts +5 -4
- package/src/graphql/resolvers/query-mutation-resolvers/query-search-resolver.ts +110 -0
- package/src/graphql/resolvers/types.ts +8 -0
- package/src/graphql/schema-analyzer.ts +6 -1
- package/src/graphql/schema-generator.ts +13 -1
- package/src/graphql/schema-root-type-generator.ts +3 -0
- package/src/graphql/schema-utils/directive-util.ts +15 -0
- package/src/graphql/schema-utils/entry-reference-util.ts +6 -2
- package/src/graphql/schema-utils/entry-type-util.ts +2 -11
- package/src/graphql/schema-utils/searchable-field-util.ts +130 -0
- package/src/graphql/schema-validator.ts +37 -7
- package/src/index.ts +25 -4
- package/src/persistence/cache.ts +115 -28
package/src/persistence/cache.ts
CHANGED
|
@@ -3,7 +3,11 @@ import { ApolloContext } from '../client.ts'
|
|
|
3
3
|
import { createError, ErrorCode } from '../graphql/errors.ts'
|
|
4
4
|
|
|
5
5
|
type Ref = string
|
|
6
|
-
type
|
|
6
|
+
type ContentHash = string
|
|
7
|
+
type EntryContent = Omit<Entry, 'id'>
|
|
8
|
+
type EntriesCache = Map<Ref, CommitCacheRecord>
|
|
9
|
+
// entry content shared across all cached commits, so that unchanged entries are neither fetched nor stored twice
|
|
10
|
+
type ContentCache = Map<ContentHash, EntryContent>
|
|
7
11
|
type SchemaCache = Map<Ref, string>
|
|
8
12
|
type InflightEntries = Map<Ref, Promise<EntriesRecord>>
|
|
9
13
|
|
|
@@ -12,6 +16,11 @@ interface EntriesRecord {
|
|
|
12
16
|
byType: Map<string, Entry[]>
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
interface CommitCacheRecord {
|
|
20
|
+
entriesRecord: EntriesRecord
|
|
21
|
+
contentHashes: ContentHash[]
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
export interface RepositoryCacheHandler {
|
|
16
25
|
getEntriesRecord: (
|
|
17
26
|
context: ApolloContext,
|
|
@@ -25,6 +34,7 @@ const MAX_CACHE_ENTRIES = 50
|
|
|
25
34
|
// intentionally not async so that the same in-flight promise is returned to all callers
|
|
26
35
|
const getEntriesRecordByRef = (
|
|
27
36
|
entriesCache: EntriesCache,
|
|
37
|
+
contentCache: ContentCache,
|
|
28
38
|
inflightEntries: InflightEntries,
|
|
29
39
|
cacheSize: number,
|
|
30
40
|
context: ApolloContext,
|
|
@@ -36,7 +46,7 @@ const getEntriesRecordByRef = (
|
|
|
36
46
|
entriesCache.delete(ref)
|
|
37
47
|
entriesCache.set(ref, cacheRecord)
|
|
38
48
|
|
|
39
|
-
return Promise.resolve(cacheRecord)
|
|
49
|
+
return Promise.resolve(cacheRecord.entriesRecord)
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
const inflightPromise = inflightEntries.get(ref)
|
|
@@ -46,6 +56,7 @@ const getEntriesRecordByRef = (
|
|
|
46
56
|
|
|
47
57
|
const fetchPromise = fetchAndCacheEntries(
|
|
48
58
|
entriesCache,
|
|
59
|
+
contentCache,
|
|
49
60
|
cacheSize,
|
|
50
61
|
context,
|
|
51
62
|
ref,
|
|
@@ -58,34 +69,72 @@ const getEntriesRecordByRef = (
|
|
|
58
69
|
|
|
59
70
|
const fetchAndCacheEntries = async (
|
|
60
71
|
entriesCache: EntriesCache,
|
|
72
|
+
contentCache: ContentCache,
|
|
61
73
|
cacheSize: number,
|
|
62
74
|
context: ApolloContext,
|
|
63
75
|
ref: string,
|
|
64
76
|
): Promise<EntriesRecord> => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
const entryHashes = await callGitAdapter(() =>
|
|
78
|
+
context.gitAdapter.getEntryHashes(ref),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
// hold on to known content now, as it may be evicted from the content cache while missing content is fetched
|
|
82
|
+
const contentByHash = new Map<ContentHash, EntryContent>()
|
|
83
|
+
const idsToFetchByHash = new Map<ContentHash, string>()
|
|
84
|
+
for (const { id, hash } of entryHashes) {
|
|
85
|
+
const content = contentCache.get(hash)
|
|
86
|
+
if (content !== undefined) {
|
|
87
|
+
contentByHash.set(hash, content)
|
|
88
|
+
} else if (!idsToFetchByHash.has(hash)) {
|
|
89
|
+
// entries with equal hash have equal content, so fetching one of them is sufficient
|
|
90
|
+
idsToFetchByHash.set(hash, id)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (idsToFetchByHash.size > 0) {
|
|
95
|
+
const fetchedEntries = await callGitAdapter(() =>
|
|
96
|
+
context.gitAdapter.getEntriesByIds(ref, [...idsToFetchByHash.values()]),
|
|
97
|
+
)
|
|
98
|
+
const fetchedEntriesById = new Map(
|
|
99
|
+
fetchedEntries.map((entry) => [entry.id, entry]),
|
|
100
|
+
)
|
|
101
|
+
for (const [hash, id] of idsToFetchByHash) {
|
|
102
|
+
const fetchedEntry = fetchedEntriesById.get(id)
|
|
103
|
+
if (fetchedEntry === undefined) {
|
|
104
|
+
throw createError(
|
|
105
|
+
`Git adapter did not return requested entry "${id}".`,
|
|
106
|
+
ErrorCode.INTERNAL_ERROR,
|
|
107
|
+
{},
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
contentByHash.set(hash, createEntryContent(fetchedEntry))
|
|
71
111
|
}
|
|
72
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
73
|
-
throw createError(message, ErrorCode.INTERNAL_ERROR, {})
|
|
74
112
|
}
|
|
75
113
|
|
|
76
|
-
const entriesById = new Map
|
|
114
|
+
const entriesById = new Map<string, Entry>()
|
|
77
115
|
const entriesByType = new Map<string, Entry[]>()
|
|
78
|
-
for (const
|
|
116
|
+
for (const { id, hash } of entryHashes) {
|
|
117
|
+
const entry: Entry = {
|
|
118
|
+
id: id,
|
|
119
|
+
...(contentByHash.get(hash) as EntryContent),
|
|
120
|
+
}
|
|
121
|
+
entriesById.set(id, entry)
|
|
79
122
|
const existingEntriesOfType = entriesByType.get(entry.metadata.type) || []
|
|
80
123
|
existingEntriesOfType.push(entry)
|
|
81
124
|
entriesByType.set(entry.metadata.type, existingEntriesOfType)
|
|
82
125
|
}
|
|
83
126
|
|
|
84
|
-
const newCacheRecord = {
|
|
85
|
-
|
|
86
|
-
|
|
127
|
+
const newCacheRecord: CommitCacheRecord = {
|
|
128
|
+
entriesRecord: {
|
|
129
|
+
byType: entriesByType,
|
|
130
|
+
byId: entriesById,
|
|
131
|
+
},
|
|
132
|
+
contentHashes: [...contentByHash.keys()],
|
|
87
133
|
}
|
|
88
134
|
|
|
135
|
+
for (const [hash, content] of contentByHash) {
|
|
136
|
+
contentCache.set(hash, content)
|
|
137
|
+
}
|
|
89
138
|
entriesCache.set(ref, newCacheRecord)
|
|
90
139
|
|
|
91
140
|
if (entriesCache.size > cacheSize) {
|
|
@@ -93,10 +142,48 @@ const fetchAndCacheEntries = async (
|
|
|
93
142
|
const oldestKey = entriesCache.keys().next().value as Ref | undefined
|
|
94
143
|
if (oldestKey !== undefined) {
|
|
95
144
|
entriesCache.delete(oldestKey)
|
|
145
|
+
removeUnreferencedContent(entriesCache, contentCache)
|
|
96
146
|
}
|
|
97
147
|
}
|
|
98
148
|
|
|
99
|
-
return newCacheRecord
|
|
149
|
+
return newCacheRecord.entriesRecord
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const createEntryContent = (entry: Entry): EntryContent => {
|
|
153
|
+
const content: EntryContent = { metadata: entry.metadata }
|
|
154
|
+
if (entry.data !== undefined) {
|
|
155
|
+
content.data = entry.data
|
|
156
|
+
}
|
|
157
|
+
return content
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const removeUnreferencedContent = (
|
|
161
|
+
entriesCache: EntriesCache,
|
|
162
|
+
contentCache: ContentCache,
|
|
163
|
+
): void => {
|
|
164
|
+
const referencedHashes = new Set<ContentHash>()
|
|
165
|
+
for (const cacheRecord of entriesCache.values()) {
|
|
166
|
+
for (const hash of cacheRecord.contentHashes) {
|
|
167
|
+
referencedHashes.add(hash)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const hash of contentCache.keys()) {
|
|
171
|
+
if (!referencedHashes.has(hash)) {
|
|
172
|
+
contentCache.delete(hash)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const callGitAdapter = async <T>(operation: () => Promise<T>): Promise<T> => {
|
|
178
|
+
try {
|
|
179
|
+
return await operation()
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (err instanceof GitAdapterError) {
|
|
182
|
+
throw createError(err.message, err.code, {})
|
|
183
|
+
}
|
|
184
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
185
|
+
throw createError(message, ErrorCode.INTERNAL_ERROR, {})
|
|
186
|
+
}
|
|
100
187
|
}
|
|
101
188
|
|
|
102
189
|
const getSchemaStringByRef = async (
|
|
@@ -114,16 +201,9 @@ const getSchemaStringByRef = async (
|
|
|
114
201
|
return schemaCacheRecord
|
|
115
202
|
}
|
|
116
203
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
} catch (err) {
|
|
121
|
-
if (err instanceof GitAdapterError) {
|
|
122
|
-
throw createError(err.message, err.code, {})
|
|
123
|
-
}
|
|
124
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
125
|
-
throw createError(message, ErrorCode.INTERNAL_ERROR, {})
|
|
126
|
-
}
|
|
204
|
+
const schemaString = await callGitAdapter(() =>
|
|
205
|
+
context.gitAdapter.getSchema(ref),
|
|
206
|
+
)
|
|
127
207
|
|
|
128
208
|
schemaCache.set(ref, schemaString)
|
|
129
209
|
|
|
@@ -141,7 +221,8 @@ const getSchemaStringByRef = async (
|
|
|
141
221
|
export const createCacheHandler = (
|
|
142
222
|
cacheSize: number = MAX_CACHE_ENTRIES,
|
|
143
223
|
): RepositoryCacheHandler => {
|
|
144
|
-
const entriesCache: EntriesCache = new Map<Ref,
|
|
224
|
+
const entriesCache: EntriesCache = new Map<Ref, CommitCacheRecord>()
|
|
225
|
+
const contentCache: ContentCache = new Map<ContentHash, EntryContent>()
|
|
145
226
|
const schemaCache: SchemaCache = new Map<Ref, string>()
|
|
146
227
|
const inflightEntries: InflightEntries = new Map<
|
|
147
228
|
Ref,
|
|
@@ -149,7 +230,13 @@ export const createCacheHandler = (
|
|
|
149
230
|
>()
|
|
150
231
|
return {
|
|
151
232
|
getEntriesRecord: (...args) =>
|
|
152
|
-
getEntriesRecordByRef(
|
|
233
|
+
getEntriesRecordByRef(
|
|
234
|
+
entriesCache,
|
|
235
|
+
contentCache,
|
|
236
|
+
inflightEntries,
|
|
237
|
+
cacheSize,
|
|
238
|
+
...args,
|
|
239
|
+
),
|
|
153
240
|
getSchema: (...args) =>
|
|
154
241
|
getSchemaStringByRef(schemaCache, cacheSize, ...args),
|
|
155
242
|
}
|