@nx-ddd/hasura 19.0.0-preview.9 → 19.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apollo/link/index.d.ts +31 -0
- package/browser/index.d.ts +8 -0
- package/fesm2022/nx-ddd-hasura-apollo-link.mjs +77 -0
- package/fesm2022/nx-ddd-hasura-apollo-link.mjs.map +1 -0
- package/fesm2022/nx-ddd-hasura-browser.mjs +19 -0
- package/fesm2022/nx-ddd-hasura-browser.mjs.map +1 -0
- package/fesm2022/nx-ddd-hasura-server.mjs +19 -0
- package/fesm2022/nx-ddd-hasura-server.mjs.map +1 -0
- package/fesm2022/nx-ddd-hasura.mjs +880 -0
- package/fesm2022/nx-ddd-hasura.mjs.map +1 -0
- package/index.d.ts +391 -1
- package/package.json +32 -6
- package/server/index.d.ts +8 -0
- package/README.md +0 -11
- package/index.js +0 -5
- package/index.js.map +0 -1
- package/lib/apollo-multi.service.d.ts +0 -23
- package/lib/apollo-multi.service.js +0 -52
- package/lib/apollo-multi.service.js.map +0 -1
- package/lib/decorators.d.ts +0 -35
- package/lib/decorators.js +0 -50
- package/lib/decorators.js.map +0 -1
- package/lib/hasura.config.d.ts +0 -8
- package/lib/hasura.config.js +0 -15
- package/lib/hasura.config.js.map +0 -1
- package/lib/hasura.converter.d.ts +0 -24
- package/lib/hasura.converter.js +0 -82
- package/lib/hasura.converter.js.map +0 -1
- package/lib/hasura.di.d.ts +0 -33
- package/lib/hasura.di.js +0 -79
- package/lib/hasura.di.js.map +0 -1
- package/lib/hasura.interceptor.d.ts +0 -6
- package/lib/hasura.interceptor.js +0 -24
- package/lib/hasura.interceptor.js.map +0 -1
- package/lib/hasura.repository.d.ts +0 -40
- package/lib/hasura.repository.js +0 -261
- package/lib/hasura.repository.js.map +0 -1
- package/lib/hasura.service.d.ts +0 -18
- package/lib/hasura.service.js +0 -49
- package/lib/hasura.service.js.map +0 -1
- package/lib/index.d.ts +0 -8
- package/lib/index.js +0 -12
- package/lib/index.js.map +0 -1
- package/lib/links.d.ts +0 -7
- package/lib/links.js +0 -23
- package/lib/links.js.map +0 -1
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, Injectable, InjectionToken } from '@angular/core';
|
|
3
|
+
import { InMemoryCache } from '@apollo/client/cache';
|
|
4
|
+
import { makeDI, makeDecoratorFactories, plainToInstanceWithValid } from '@nx-ddd/core';
|
|
5
|
+
import { ApolloLinkService as ApolloLinkService$1 } from '@nx-ddd/hasura/apollo/link';
|
|
6
|
+
import { Apollo, APOLLO_OPTIONS, provideApollo, gql } from 'apollo-angular';
|
|
7
|
+
import { HttpLink } from 'apollo-angular/http';
|
|
8
|
+
import { setContext } from '@apollo/client/link/context';
|
|
9
|
+
import { ApolloLink, split, InMemoryCache as InMemoryCache$1, gql as gql$1 } from '@apollo/client/core';
|
|
10
|
+
import { getMainDefinition } from '@apollo/client/utilities';
|
|
11
|
+
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
|
|
12
|
+
import { createClient } from 'graphql-ws';
|
|
13
|
+
import { isObservable, from, of, lastValueFrom, filter, take, distinctUntilChanged, switchMap, map } from 'rxjs';
|
|
14
|
+
import { WEBSOCKET } from '@nx-ddd/common/infrastructure/externals/websocket/token';
|
|
15
|
+
import { CRYPTO } from '@nx-ddd/common/infrastructure/externals/crypto/token';
|
|
16
|
+
import { camelCase as camelCase$1, snakeCase, get, pick, omitBy } from 'lodash-es';
|
|
17
|
+
import dayjs from 'dayjs';
|
|
18
|
+
import { format, parse } from 'date-fns';
|
|
19
|
+
import { formatInTimeZone } from 'date-fns-tz';
|
|
20
|
+
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
21
|
+
import { Repository } from '@nx-ddd/common/domain';
|
|
22
|
+
export { TransformToDayjs } from '@nx-ddd/common/domain';
|
|
23
|
+
export { IsDayjs } from 'class-validator-extended';
|
|
24
|
+
|
|
25
|
+
/** @deprecated use ApolloClientManagerService instead */
|
|
26
|
+
class ApolloMultiService {
|
|
27
|
+
apollo = inject(Apollo);
|
|
28
|
+
linkService = inject(ApolloLinkService$1);
|
|
29
|
+
createClient(name, baseUrl, getHeaders) {
|
|
30
|
+
this.apollo.removeClient(name);
|
|
31
|
+
this.apollo.createNamed(name, {
|
|
32
|
+
link: this.linkService.createLink(baseUrl, getHeaders),
|
|
33
|
+
cache: new InMemoryCache()
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getClient(endpoint, getHeaders) {
|
|
37
|
+
const name = endpoint;
|
|
38
|
+
let client = this.apollo.use(name);
|
|
39
|
+
console.debug('[ApolloMultiService] getClient:', name);
|
|
40
|
+
if (!client) {
|
|
41
|
+
this.createClient(name, endpoint, getHeaders);
|
|
42
|
+
client = this.apollo.use(name);
|
|
43
|
+
}
|
|
44
|
+
return client;
|
|
45
|
+
}
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloMultiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
47
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloMultiService, providedIn: 'root' });
|
|
48
|
+
}
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloMultiService, decorators: [{
|
|
50
|
+
type: Injectable,
|
|
51
|
+
args: [{ providedIn: 'root' }]
|
|
52
|
+
}] });
|
|
53
|
+
const GET_APOLLO_CLIENT = makeDI('GET_APOLLO_CLIENT');
|
|
54
|
+
|
|
55
|
+
function wrap(obsOrPromiseOrValue) {
|
|
56
|
+
if (isObservable(obsOrPromiseOrValue))
|
|
57
|
+
return obsOrPromiseOrValue;
|
|
58
|
+
if (obsOrPromiseOrValue instanceof Promise)
|
|
59
|
+
return from(obsOrPromiseOrValue);
|
|
60
|
+
return of(obsOrPromiseOrValue);
|
|
61
|
+
}
|
|
62
|
+
function resolve(getHeaders) {
|
|
63
|
+
const headers$ = wrap(getHeaders());
|
|
64
|
+
return lastValueFrom(headers$.pipe(filter((headers) => !!headers), take(1), distinctUntilChanged()));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isSubscription(query) {
|
|
68
|
+
const definition = getMainDefinition(query);
|
|
69
|
+
return (definition.kind === 'OperationDefinition' &&
|
|
70
|
+
definition.operation === 'subscription');
|
|
71
|
+
}
|
|
72
|
+
class ApolloLinkService {
|
|
73
|
+
httpLink = inject(HttpLink);
|
|
74
|
+
WebSocketImpl = WEBSOCKET.inject();
|
|
75
|
+
createGraphQLWsClient(baseUrl, getHeaders) {
|
|
76
|
+
return createClient({
|
|
77
|
+
url: baseUrl.replace('http', 'ws'),
|
|
78
|
+
webSocketImpl: this.WebSocketImpl,
|
|
79
|
+
connectionParams: async () => {
|
|
80
|
+
const headers = await resolve(getHeaders);
|
|
81
|
+
return { headers };
|
|
82
|
+
},
|
|
83
|
+
lazy: true, // 必要時のみ接続を開始
|
|
84
|
+
shouldRetry: () => true, // 再接続を有効化
|
|
85
|
+
retryAttempts: 5, // 再接続試行回数を制限
|
|
86
|
+
keepAlive: 30000, // 30秒ごとにキープアライブ
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
createHttpLink(baseUrl, getHeaders) {
|
|
90
|
+
return ApolloLink.from([
|
|
91
|
+
setContext(async () => {
|
|
92
|
+
const headers = await resolve(getHeaders);
|
|
93
|
+
return { headers };
|
|
94
|
+
}),
|
|
95
|
+
this.httpLink.create({ uri: baseUrl, }),
|
|
96
|
+
]);
|
|
97
|
+
}
|
|
98
|
+
createWebSocketLink(baseUrl, getHeaders) {
|
|
99
|
+
return new GraphQLWsLink(this.createGraphQLWsClient(baseUrl, getHeaders));
|
|
100
|
+
}
|
|
101
|
+
createAutoSplitLink(baseUrl, getHeaders) {
|
|
102
|
+
return split(({ query }) => isSubscription(query), this.createWebSocketLink(baseUrl, getHeaders), this.createHttpLink(baseUrl, getHeaders));
|
|
103
|
+
}
|
|
104
|
+
createLink(baseUrl, getHeaders) {
|
|
105
|
+
return this.createAutoSplitLink(baseUrl, getHeaders);
|
|
106
|
+
}
|
|
107
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
108
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloLinkService, providedIn: 'root' });
|
|
109
|
+
}
|
|
110
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloLinkService, decorators: [{
|
|
111
|
+
type: Injectable,
|
|
112
|
+
args: [{ providedIn: 'root' }]
|
|
113
|
+
}] });
|
|
114
|
+
|
|
115
|
+
class ApolloClientManagerService {
|
|
116
|
+
apollo = inject(Apollo);
|
|
117
|
+
linkService = inject(ApolloLinkService);
|
|
118
|
+
crypto = CRYPTO.inject();
|
|
119
|
+
async buildClientName(endpoint, headers) {
|
|
120
|
+
const data = new TextEncoder().encode(JSON.stringify(headers));
|
|
121
|
+
const arrayBuffer = await this.crypto.subtle.digest('SHA-256', data);
|
|
122
|
+
const hash = Array.from(new Uint8Array(arrayBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
123
|
+
return `${endpoint}?headers=${hash}`;
|
|
124
|
+
}
|
|
125
|
+
getClient(endpoint, getHeaders) {
|
|
126
|
+
return wrap(getHeaders()).pipe(take(1), switchMap(async (headers) => {
|
|
127
|
+
const name = await this.buildClientName(endpoint, headers);
|
|
128
|
+
const client = this.apollo.use(name);
|
|
129
|
+
if (!client) {
|
|
130
|
+
this.apollo.removeClient(name);
|
|
131
|
+
this.apollo.createNamed(name, {
|
|
132
|
+
link: this.linkService.createLink(endpoint, getHeaders),
|
|
133
|
+
cache: new InMemoryCache()
|
|
134
|
+
});
|
|
135
|
+
return this.apollo.use(name);
|
|
136
|
+
}
|
|
137
|
+
return client;
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloClientManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
141
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloClientManagerService, providedIn: 'root' });
|
|
142
|
+
}
|
|
143
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: ApolloClientManagerService, decorators: [{
|
|
144
|
+
type: Injectable,
|
|
145
|
+
args: [{ providedIn: 'root' }]
|
|
146
|
+
}] });
|
|
147
|
+
|
|
148
|
+
const { createDecorator,
|
|
149
|
+
// createClassDecorator,
|
|
150
|
+
addAnnotation, getAnnotations, } = makeDecoratorFactories((type, fieldName, propName, options) => ({ type, fieldName, propName, childType: options.childType }), '[@nx-ddd/hasura] annotations');
|
|
151
|
+
function getFieldAnnotationMap(T, prefix = '') {
|
|
152
|
+
const annotations = Hasura.getAnnotations(T);
|
|
153
|
+
return (annotations ?? []).reduce((acc, annotation) => {
|
|
154
|
+
const currentKey = prefix ? camelCase$1(`${prefix}_${annotation.fieldName}`) : annotation.fieldName;
|
|
155
|
+
return { ...acc, [currentKey]: annotation };
|
|
156
|
+
}, {});
|
|
157
|
+
}
|
|
158
|
+
function getFlattenFieldAnnotations(T, prefix = '') {
|
|
159
|
+
const annotations = Hasura.getAnnotations(T);
|
|
160
|
+
return (annotations ?? []).reduce((acc, annotation) => {
|
|
161
|
+
const currentKey = prefix ? camelCase$1(`${prefix}_${annotation.fieldName}`) : annotation.fieldName;
|
|
162
|
+
if (annotation.childType) {
|
|
163
|
+
return {
|
|
164
|
+
...acc,
|
|
165
|
+
...getFlattenFieldAnnotations(annotation.childType(), currentKey)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
...acc,
|
|
170
|
+
[currentKey]: annotation
|
|
171
|
+
};
|
|
172
|
+
}, {});
|
|
173
|
+
}
|
|
174
|
+
function getFields(T, options = {
|
|
175
|
+
prefix: '',
|
|
176
|
+
case: 'snake'
|
|
177
|
+
}) {
|
|
178
|
+
const annotations = Hasura.getAnnotations(T).filter((annotation) => annotation.type !== 'table');
|
|
179
|
+
const changeCase = options?.case === 'snake' ? snakeCase : camelCase$1;
|
|
180
|
+
const fields = (annotations ?? []).flatMap((annotation) => {
|
|
181
|
+
const currentKey = changeCase(options?.prefix ? `${options?.prefix}_${annotation.fieldName}` : annotation.fieldName);
|
|
182
|
+
if (annotation.childType) {
|
|
183
|
+
return [
|
|
184
|
+
...getFields(annotation.childType(), {
|
|
185
|
+
prefix: currentKey,
|
|
186
|
+
case: options?.case,
|
|
187
|
+
})
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
return [currentKey];
|
|
191
|
+
});
|
|
192
|
+
return fields;
|
|
193
|
+
}
|
|
194
|
+
function createClassDecorator(type) {
|
|
195
|
+
return (nameOrProps) => {
|
|
196
|
+
const props = typeof nameOrProps === 'string' ? { name: nameOrProps } : nameOrProps;
|
|
197
|
+
return (target) => {
|
|
198
|
+
const name = props?.name || target.name;
|
|
199
|
+
const annotation = { type, name };
|
|
200
|
+
addAnnotation(target, annotation);
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function getTableName(target) {
|
|
205
|
+
const annotations = getAnnotations(target);
|
|
206
|
+
const annotation = annotations.find((annotation) => annotation.type === 'table');
|
|
207
|
+
return annotation.name;
|
|
208
|
+
}
|
|
209
|
+
const Hasura = {
|
|
210
|
+
Table: createClassDecorator('table'),
|
|
211
|
+
Text: createDecorator('text'),
|
|
212
|
+
Timestamp: createDecorator('timestamp'),
|
|
213
|
+
Date: createDecorator('date'),
|
|
214
|
+
Integer: createDecorator('integer'),
|
|
215
|
+
Numeric: createDecorator('numeric'),
|
|
216
|
+
Boolean: createDecorator('boolean'),
|
|
217
|
+
Map: (childType) => createDecorator('map', { childType })(),
|
|
218
|
+
JSON: createDecorator('json'),
|
|
219
|
+
Location: createDecorator('location'),
|
|
220
|
+
getAnnotations,
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
function deepCamelToSnakeCase(obj) {
|
|
224
|
+
if (Array.isArray(obj))
|
|
225
|
+
return obj.map(deepCamelToSnakeCase);
|
|
226
|
+
if (obj instanceof Date)
|
|
227
|
+
return obj;
|
|
228
|
+
if (obj && typeof obj === "object") {
|
|
229
|
+
const result = {};
|
|
230
|
+
for (const key in obj) {
|
|
231
|
+
if (Object.prototype.hasOwnProperty.call(obj, key))
|
|
232
|
+
result[snakeCase(key)] = deepCamelToSnakeCase(obj[key]);
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
return obj;
|
|
237
|
+
}
|
|
238
|
+
function camelCase(str) {
|
|
239
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
240
|
+
}
|
|
241
|
+
function deepSnakeToCamelCase(obj) {
|
|
242
|
+
if (Array.isArray(obj))
|
|
243
|
+
return obj.map(deepSnakeToCamelCase);
|
|
244
|
+
if (obj instanceof Date)
|
|
245
|
+
return obj;
|
|
246
|
+
if (obj && typeof obj === "object") {
|
|
247
|
+
const result = {};
|
|
248
|
+
for (const key in obj) {
|
|
249
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
250
|
+
result[camelCase(key)] = deepSnakeToCamelCase(obj[key]);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
return obj;
|
|
256
|
+
}
|
|
257
|
+
function getConverter(type) {
|
|
258
|
+
return {
|
|
259
|
+
toHasura(entity) {
|
|
260
|
+
return HasuraUtils.toHasura(entity, type);
|
|
261
|
+
},
|
|
262
|
+
toHasuraMany(entities) {
|
|
263
|
+
return entities.map((entity) => this.toHasura(entity));
|
|
264
|
+
},
|
|
265
|
+
fromHasura(entity) {
|
|
266
|
+
return HasuraUtils.fromHasura(entity, type);
|
|
267
|
+
},
|
|
268
|
+
fromHasuraMany(entities) {
|
|
269
|
+
return entities.map((entity) => this.fromHasura(entity));
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/** @deprecated use `getConverter` instead */
|
|
274
|
+
const makeConverter = getConverter;
|
|
275
|
+
class HasuraUtils {
|
|
276
|
+
static toTimestamp(date) {
|
|
277
|
+
if (dayjs.isDayjs(date)) {
|
|
278
|
+
return date.toISOString();
|
|
279
|
+
}
|
|
280
|
+
else if (date instanceof Date) {
|
|
281
|
+
return format(date, 'yyyy-MM-dd HH:mm:ss');
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
static toDate(date) {
|
|
288
|
+
if (typeof date === 'undefined') {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
else if (dayjs.isDayjs(date)) {
|
|
292
|
+
// Dayjsオブジェクトの場合、既に適切なタイムゾーンで処理されているとみなす
|
|
293
|
+
return date.format('YYYY-MM-DD');
|
|
294
|
+
}
|
|
295
|
+
else if (date instanceof Date) {
|
|
296
|
+
// formatInTimeZoneを使用してローカルタイムゾーンで処理
|
|
297
|
+
return formatInTimeZone(date, Intl.DateTimeFormat().resolvedOptions().timeZone, 'yyyy-MM-dd');
|
|
298
|
+
}
|
|
299
|
+
else if (typeof date === 'string') {
|
|
300
|
+
return date;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
static fromHasura(_object, type) {
|
|
307
|
+
const fieldMap = getFieldAnnotationMap(type);
|
|
308
|
+
// ネストされたmap型の再帰的復元
|
|
309
|
+
function extractNestedMap(mapKey, childType, object) {
|
|
310
|
+
const childFieldMap = getFieldAnnotationMap(childType);
|
|
311
|
+
const childFields = {};
|
|
312
|
+
Object.entries(childFieldMap).forEach(([childKey, childAnnotation]) => {
|
|
313
|
+
if (childAnnotation.type === 'map') {
|
|
314
|
+
// 再帰的にネストを復元
|
|
315
|
+
const nested = extractNestedMap(`${mapKey}_${childKey}`, childAnnotation.childType(), object);
|
|
316
|
+
if (nested && Object.keys(nested).length > 0) {
|
|
317
|
+
childFields[childAnnotation.fieldName] = nested;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
const flattenedKey = `${mapKey}_${childKey}`;
|
|
322
|
+
const value = get(object, snakeCase(flattenedKey));
|
|
323
|
+
if (typeof value !== 'undefined') {
|
|
324
|
+
childFields[childAnnotation.fieldName] = value;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
return childFields;
|
|
329
|
+
}
|
|
330
|
+
// First extract any flattened map fields (e.g., profile_bio)
|
|
331
|
+
const nestedObjects = {};
|
|
332
|
+
Object.entries(fieldMap).forEach(([key, annotation]) => {
|
|
333
|
+
if (annotation.type === 'map') {
|
|
334
|
+
const childType = annotation.childType();
|
|
335
|
+
const nested = extractNestedMap(key, childType, _object);
|
|
336
|
+
if (nested && Object.keys(nested).length > 0) {
|
|
337
|
+
nestedObjects[annotation.fieldName] = nested;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
// Now process all fields normally
|
|
342
|
+
const obj = Object.entries(fieldMap).reduce((acc, [key, annotation]) => {
|
|
343
|
+
// For map types, use our previously extracted nested objects
|
|
344
|
+
if (annotation.type === 'map') {
|
|
345
|
+
const nestedObj = nestedObjects[annotation.fieldName];
|
|
346
|
+
if (nestedObj) {
|
|
347
|
+
return { ...acc, [annotation.fieldName]: nestedObj };
|
|
348
|
+
}
|
|
349
|
+
return acc;
|
|
350
|
+
}
|
|
351
|
+
const value = get(_object, snakeCase(key));
|
|
352
|
+
if (typeof value === 'undefined')
|
|
353
|
+
return acc;
|
|
354
|
+
switch (annotation.type) {
|
|
355
|
+
case 'text': return { ...acc, [annotation.fieldName]: value };
|
|
356
|
+
case 'timestamp': return { ...acc, [annotation.fieldName]: value === null ? null : parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()) };
|
|
357
|
+
case 'date': {
|
|
358
|
+
const parsedDate = value === null ? null : parse(value, 'yyyy-MM-dd', new Date());
|
|
359
|
+
return { ...acc, [annotation.fieldName]: parsedDate };
|
|
360
|
+
}
|
|
361
|
+
case 'numeric': return { ...acc, [annotation.fieldName]: value };
|
|
362
|
+
case 'integer': return { ...acc, [annotation.fieldName]: value };
|
|
363
|
+
case 'json': return { ...acc, [annotation.fieldName]: value };
|
|
364
|
+
case 'location': return { ...acc, [annotation.fieldName]: this.fromHasuraLocation(value) };
|
|
365
|
+
default: return { ...acc, [annotation.fieldName]: value };
|
|
366
|
+
}
|
|
367
|
+
}, {});
|
|
368
|
+
return plainToInstanceWithValid(type, obj);
|
|
369
|
+
}
|
|
370
|
+
static toNumber(value) {
|
|
371
|
+
if (typeof value === 'undefined')
|
|
372
|
+
return undefined;
|
|
373
|
+
if (value === null)
|
|
374
|
+
return null;
|
|
375
|
+
if (value === '' || (typeof value === 'string' && value.trim() === ''))
|
|
376
|
+
return null;
|
|
377
|
+
return isNaN(Number(value)) ? null : Number(value);
|
|
378
|
+
}
|
|
379
|
+
static toHasuraLocation(position) {
|
|
380
|
+
if (!(position?.lat && position?.lng))
|
|
381
|
+
return null;
|
|
382
|
+
return {
|
|
383
|
+
type: 'Point',
|
|
384
|
+
crs: {
|
|
385
|
+
type: 'name',
|
|
386
|
+
properties: { name: 'urn:ogc:def:crs:EPSG::4326' }
|
|
387
|
+
},
|
|
388
|
+
coordinates: [position.lng, position.lat]
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
static fromHasuraLocation(location) {
|
|
392
|
+
if (!location)
|
|
393
|
+
return null;
|
|
394
|
+
return {
|
|
395
|
+
lat: location.coordinates?.[1],
|
|
396
|
+
lng: location.coordinates?.[0],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
static toHasura(object, type, { extraFunc = deepCamelToSnakeCase } = {}) {
|
|
400
|
+
const fieldMap = getFieldAnnotationMap(type);
|
|
401
|
+
const obj = Object.entries(fieldMap).reduce((acc, [key, annotation]) => {
|
|
402
|
+
const value = get(object, annotation.fieldName);
|
|
403
|
+
if (typeof value === 'undefined')
|
|
404
|
+
return acc;
|
|
405
|
+
switch (annotation.type) {
|
|
406
|
+
case 'text': return { ...acc, [key]: value };
|
|
407
|
+
case 'timestamp': return { ...acc, [key]: this.toTimestamp(value) };
|
|
408
|
+
case 'date': return { ...acc, [key]: this.toDate(value) };
|
|
409
|
+
case 'numeric': return { ...acc, [key]: this.toNumber(value) };
|
|
410
|
+
case 'integer': return { ...acc, [key]: this.toNumber(value) };
|
|
411
|
+
case 'json': return { ...acc, [key]: value };
|
|
412
|
+
case 'map': {
|
|
413
|
+
const childObj = this.toHasura(value, annotation.childType(), { extraFunc });
|
|
414
|
+
const flattenedObj = Object.entries(childObj).reduce((childAcc, [childKey, childValue]) => ({
|
|
415
|
+
...childAcc,
|
|
416
|
+
[`${key}_${childKey}`]: childValue
|
|
417
|
+
}), {});
|
|
418
|
+
return { ...acc, ...flattenedObj };
|
|
419
|
+
}
|
|
420
|
+
case 'location': return { ...acc, [key]: this.toHasuraLocation(value) };
|
|
421
|
+
default: return { ...acc, [key]: value };
|
|
422
|
+
}
|
|
423
|
+
}, {});
|
|
424
|
+
return extraFunc(obj);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
class HasuraInterceptor {
|
|
429
|
+
config = inject(HASURA_CONFIG);
|
|
430
|
+
intercept(req, next) {
|
|
431
|
+
if (req.url.startsWith(this.config.url)) {
|
|
432
|
+
return next.handle(req.clone({
|
|
433
|
+
headers: req.headers.set('x-hasura-admin-secret', this.config.adminSecret),
|
|
434
|
+
}));
|
|
435
|
+
}
|
|
436
|
+
return next.handle(req);
|
|
437
|
+
}
|
|
438
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
439
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraInterceptor });
|
|
440
|
+
}
|
|
441
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraInterceptor, decorators: [{
|
|
442
|
+
type: Injectable
|
|
443
|
+
}] });
|
|
444
|
+
|
|
445
|
+
const HASURA_CONFIG = new InjectionToken('HASURA_CONFIG');
|
|
446
|
+
function provideHasuraConfig(config) {
|
|
447
|
+
return [
|
|
448
|
+
{ provide: HASURA_CONFIG, useValue: config },
|
|
449
|
+
config.adminSecret ? { provide: HTTP_INTERCEPTORS, useClass: HasuraInterceptor, multi: true } : [],
|
|
450
|
+
];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const GRAPHQL_HEADERS = new InjectionToken('GRAPHQL_HEADERS', {
|
|
454
|
+
providedIn: 'root',
|
|
455
|
+
factory: () => () => ({}),
|
|
456
|
+
});
|
|
457
|
+
function provideHasuraGetHeaders(useFactory) {
|
|
458
|
+
return [
|
|
459
|
+
{ provide: GRAPHQL_HEADERS, useFactory },
|
|
460
|
+
];
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* @deprecated use provideHasuraGetHeaders instead
|
|
464
|
+
*/
|
|
465
|
+
const provideGraphqlHeaders = provideHasuraGetHeaders;
|
|
466
|
+
function provideApolloOptions() {
|
|
467
|
+
return {
|
|
468
|
+
provide: APOLLO_OPTIONS,
|
|
469
|
+
useFactory: (link) => ({ cache: new InMemoryCache$1(), link }),
|
|
470
|
+
deps: [ApolloLink],
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function provideHasura(config) {
|
|
474
|
+
return [
|
|
475
|
+
provideApollo(() => ({
|
|
476
|
+
cache: new InMemoryCache$1(),
|
|
477
|
+
link: inject(ApolloLink),
|
|
478
|
+
})),
|
|
479
|
+
provideHasuraConfig(config),
|
|
480
|
+
];
|
|
481
|
+
}
|
|
482
|
+
function provideHasuraWithWebSocket(config) {
|
|
483
|
+
return [
|
|
484
|
+
provideApollo(() => ({
|
|
485
|
+
cache: new InMemoryCache$1(),
|
|
486
|
+
link: inject(ApolloLink),
|
|
487
|
+
})),
|
|
488
|
+
provideHasuraConfig(config),
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
class GetQueryPartBuilder {
|
|
493
|
+
config;
|
|
494
|
+
constructor(config) {
|
|
495
|
+
this.config = config;
|
|
496
|
+
}
|
|
497
|
+
build(params) {
|
|
498
|
+
const queryName = `${this.config.tableName}_by_pk`;
|
|
499
|
+
const variableDefinitions = ['$id: String!'];
|
|
500
|
+
const queryPart = `${queryName}(id: $id) { ${this.config.columns.join(' ')} }`;
|
|
501
|
+
return { queryPart, variableDefinitions, variables: params, operationName: queryName };
|
|
502
|
+
}
|
|
503
|
+
buildMany() {
|
|
504
|
+
const queryName = this.config.tableName;
|
|
505
|
+
const queryPart = `${queryName} { ${this.config.columns.join(' ')} }`;
|
|
506
|
+
return { queryPart, variableDefinitions: [], variables: {}, operationName: queryName };
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function makeSubscription(query) {
|
|
511
|
+
const { kind, definitions } = query;
|
|
512
|
+
const subscriptionDefinitions = definitions.map((definition) => {
|
|
513
|
+
if (definition.kind === 'OperationDefinition' && definition.operation === 'query') {
|
|
514
|
+
return {
|
|
515
|
+
...definition,
|
|
516
|
+
operation: 'subscription',
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
return definition;
|
|
520
|
+
});
|
|
521
|
+
return { kind, definitions: subscriptionDefinitions };
|
|
522
|
+
}
|
|
523
|
+
class QueriesBuilder {
|
|
524
|
+
get;
|
|
525
|
+
constructor(config) {
|
|
526
|
+
this.get = new GetQueryPartBuilder(config);
|
|
527
|
+
}
|
|
528
|
+
makeSubscription(query) {
|
|
529
|
+
return makeSubscription(query);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
class CreateMutationBuilder {
|
|
534
|
+
config;
|
|
535
|
+
constructor(config) {
|
|
536
|
+
this.config = config;
|
|
537
|
+
}
|
|
538
|
+
build(data, alias = 'create') {
|
|
539
|
+
const object = this.convertToObject(data);
|
|
540
|
+
const mutationName = `insert_${this.config.tableName}`;
|
|
541
|
+
const variableDefinitions = [`$${alias}: ${this.config.tableName}_insert_input!`];
|
|
542
|
+
const queryPart = `${alias}: ${mutationName}(objects: [$${alias}]) { affected_rows returning { ${this.config.columns.join(' ')} } }`;
|
|
543
|
+
const variables = { [alias]: object };
|
|
544
|
+
return { queryPart, variableDefinitions, variables, operationName: mutationName, alias };
|
|
545
|
+
}
|
|
546
|
+
buildMany(data, alias = 'createMany') {
|
|
547
|
+
const objects = this.convertToObjects(data);
|
|
548
|
+
const mutationName = `insert_${this.config.tableName}`;
|
|
549
|
+
const variableDefinitions = [`$${alias}: [${this.config.tableName}_insert_input!]!`];
|
|
550
|
+
const queryPart = `${alias}: ${mutationName}(objects: $${alias}) { affected_rows returning { ${this.config.columns.join(' ')} } }`;
|
|
551
|
+
const variables = { [alias]: objects };
|
|
552
|
+
return { queryPart, variableDefinitions, variables, operationName: mutationName, alias };
|
|
553
|
+
}
|
|
554
|
+
convertToObject(item) {
|
|
555
|
+
const fields = Object.keys(item).map(snakeCase).filter((field) => !['created_at', 'updated_at'].includes(field));
|
|
556
|
+
const picked = pick(item, [...fields]);
|
|
557
|
+
return omitBy(picked, (value) => typeof value === 'undefined');
|
|
558
|
+
}
|
|
559
|
+
convertToObjects(items) {
|
|
560
|
+
return items.map((item) => this.convertToObject(item));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
class DeleteMutationBuilder {
|
|
565
|
+
config;
|
|
566
|
+
constructor(config) {
|
|
567
|
+
this.config = config;
|
|
568
|
+
}
|
|
569
|
+
build({ id }) {
|
|
570
|
+
const operationName = `delete_${this.config.tableName}`;
|
|
571
|
+
const queryPart = `${operationName}(where: {id: {_eq: $id}}) { affected_rows }`;
|
|
572
|
+
const variableDefinitions = ['$id: String!'];
|
|
573
|
+
return { queryPart, variableDefinitions, variables: { id }, operationName };
|
|
574
|
+
}
|
|
575
|
+
buildMany(params, alias = 'deleteMany') {
|
|
576
|
+
const operationName = `delete_${this.config.tableName}`;
|
|
577
|
+
const variableDefinitions = [`$${alias}: [String!]!`];
|
|
578
|
+
const queryPart = `${alias}: ${operationName}(where: {id: {_in: $${alias}}}) { affected_rows }`;
|
|
579
|
+
const variables = { [alias]: params.map((p) => p.id) };
|
|
580
|
+
return { queryPart, variableDefinitions, variables, operationName, alias };
|
|
581
|
+
}
|
|
582
|
+
buildAll(alias = 'deleteAll') {
|
|
583
|
+
const operationName = `delete_${this.config.tableName}`;
|
|
584
|
+
const uniqueAlias = `${alias}_${this.config.tableName}`;
|
|
585
|
+
const variableDefinitions = [];
|
|
586
|
+
const queryPart = `${uniqueAlias}: ${operationName}(where: {}) { affected_rows }`;
|
|
587
|
+
const variables = {};
|
|
588
|
+
return { queryPart, variableDefinitions, variables, operationName, alias };
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
class SaveMutationBuilder {
|
|
593
|
+
config;
|
|
594
|
+
constructor(config) {
|
|
595
|
+
this.config = config;
|
|
596
|
+
}
|
|
597
|
+
build(data, { operationName = `insert_${this.config.tableName}`, constraint = this.config.pk, columns = this.config.columns, returningColumns = this.config.columns, alias = operationName, } = {}) {
|
|
598
|
+
const object = this.buildObject(data);
|
|
599
|
+
const onConflict = this.buildOnConflict(data, constraint, columns);
|
|
600
|
+
const variableDefinitions = [
|
|
601
|
+
`$${alias}Object: ${this.config.tableName}_insert_input!`,
|
|
602
|
+
`$${alias}OnConflict: ${this.config.tableName}_on_conflict!`
|
|
603
|
+
];
|
|
604
|
+
const queryPart = `${alias}: ${operationName}( objects: [$${alias}Object] on_conflict: $${alias}OnConflict) { affected_rows returning { ${returningColumns.join(', ')} } }`;
|
|
605
|
+
const variables = { [`${alias}Object`]: object, [`${alias}OnConflict`]: onConflict };
|
|
606
|
+
return { queryPart, variableDefinitions, variables, operationName, alias };
|
|
607
|
+
}
|
|
608
|
+
buildMany(entities, { operationName = `insert_${this.config.tableName}`, constraint = this.config.pk, columns = this.config.columns, returningColumns = this.config.columns, alias = 'save' } = {}) {
|
|
609
|
+
const objects = this.buildObjects(entities);
|
|
610
|
+
const onConflict = this.buildOnConflict(entities[0], constraint, columns);
|
|
611
|
+
const variableDefinitions = [
|
|
612
|
+
`$${alias}Objects: [${this.config.tableName}_insert_input!]!`,
|
|
613
|
+
`$${alias}OnConflict: ${this.config.tableName}_on_conflict!`
|
|
614
|
+
];
|
|
615
|
+
const queryPart = `${alias}: ${operationName}(objects: $${alias}Objects on_conflict: $${alias}OnConflict) {
|
|
616
|
+
affected_rows returning { ${returningColumns.join(', ')} }
|
|
617
|
+
}`;
|
|
618
|
+
const variables = { [`${alias}Objects`]: objects, [`${alias}OnConflict`]: onConflict };
|
|
619
|
+
return { queryPart, variableDefinitions, variables, operationName: operationName, alias };
|
|
620
|
+
}
|
|
621
|
+
buildObject(item) {
|
|
622
|
+
const fields = Object.keys(item).map(snakeCase).filter((field) => !['created_at', 'updated_at'].includes(field));
|
|
623
|
+
const picked = pick(item, [...fields]);
|
|
624
|
+
return omitBy(picked, (value) => typeof value === 'undefined');
|
|
625
|
+
}
|
|
626
|
+
buildObjects(items) {
|
|
627
|
+
return items.map((item) => this.buildObject(item));
|
|
628
|
+
}
|
|
629
|
+
buildOnConflict(data, constraint, columns) {
|
|
630
|
+
const fields = Object.keys(this.buildObject(data));
|
|
631
|
+
const updateColumns = fields.filter(column => columns.includes(column));
|
|
632
|
+
return { constraint, update_columns: updateColumns };
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
class UpdateMutationBuilder {
|
|
637
|
+
config;
|
|
638
|
+
constructor(config) {
|
|
639
|
+
this.config = config;
|
|
640
|
+
}
|
|
641
|
+
build(data, alias = 'update') {
|
|
642
|
+
const mutationName = `update_${this.config.tableName}`;
|
|
643
|
+
const object = this.buildObject(data);
|
|
644
|
+
const variableDefinitions = [`$${alias}Id: String!`, `$${alias}Object: ${this.config.tableName}_set_input!`];
|
|
645
|
+
const queryPart = `${alias}: ${mutationName}(where: {id: {_eq: $${alias}Id}} _set: $${alias}Object) { affected_rows returning { id } }`;
|
|
646
|
+
const variables = { [`${alias}Id`]: data.id, [`${alias}Object`]: object };
|
|
647
|
+
return { queryPart, variableDefinitions, variables, operationName: mutationName, alias };
|
|
648
|
+
}
|
|
649
|
+
buildMany(data, alias = 'updateMany') {
|
|
650
|
+
const mutationName = `update_${this.config.tableName}_many`;
|
|
651
|
+
const objects = this.buildObjects(data);
|
|
652
|
+
const variableDefinitions = [`$${alias}Objects: [${this.config.tableName}_updates!]!`];
|
|
653
|
+
const queryPart = `${alias}: ${mutationName}(updates: $${alias}Objects) { affected_rows returning { id } }`;
|
|
654
|
+
const variables = { [`${alias}Objects`]: objects };
|
|
655
|
+
return { queryPart, variableDefinitions, variables, operationName: mutationName, alias };
|
|
656
|
+
}
|
|
657
|
+
buildObject(item) {
|
|
658
|
+
const fields = Object.keys(item).map(snakeCase).filter((field) => !['created_at', 'updated_at'].includes(field));
|
|
659
|
+
const picked = pick(item, fields);
|
|
660
|
+
return omitBy(picked, (value) => typeof value === 'undefined');
|
|
661
|
+
}
|
|
662
|
+
buildObjects(items) {
|
|
663
|
+
return items.map((item) => ({ where: { id: { _eq: item.id } }, _set: this.buildObject(item) }));
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
class HasuraMutationBuilder {
|
|
668
|
+
create;
|
|
669
|
+
update;
|
|
670
|
+
save;
|
|
671
|
+
delete_;
|
|
672
|
+
constructor(config) {
|
|
673
|
+
this.create = new CreateMutationBuilder(config);
|
|
674
|
+
this.update = new UpdateMutationBuilder(config);
|
|
675
|
+
this.save = new SaveMutationBuilder(config);
|
|
676
|
+
this.delete_ = new DeleteMutationBuilder(config);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
class HasuraQueryPartsBuilder {
|
|
681
|
+
mutations;
|
|
682
|
+
queries;
|
|
683
|
+
constructor(config) {
|
|
684
|
+
this.mutations = new HasuraMutationBuilder(config);
|
|
685
|
+
this.queries = new QueriesBuilder(config);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
class HasuraQueryBuilder {
|
|
690
|
+
parts;
|
|
691
|
+
constructor(config) {
|
|
692
|
+
this.parts = new HasuraQueryPartsBuilder(config);
|
|
693
|
+
}
|
|
694
|
+
buildQuery(part) {
|
|
695
|
+
const operationNameStr = part.operationName ? `${part.operationName} ` : '';
|
|
696
|
+
const variablesStr = part.variableDefinitions?.length ? `(${part.variableDefinitions.join(', ')}) ` : '';
|
|
697
|
+
return `query ${operationNameStr}${variablesStr}{ ${part.queryPart} }`;
|
|
698
|
+
}
|
|
699
|
+
static buildMutation(part) {
|
|
700
|
+
const operationNameStr = part.operationName ? `${part.operationName} ` : '';
|
|
701
|
+
const variablesStr = part.variableDefinitions?.length ? `(${part.variableDefinitions.join(', ')}) ` : '';
|
|
702
|
+
return `mutation ${operationNameStr}${variablesStr} { ${part.queryPart} }`;
|
|
703
|
+
}
|
|
704
|
+
buildMutation(part) {
|
|
705
|
+
return HasuraQueryBuilder.buildMutation(part);
|
|
706
|
+
}
|
|
707
|
+
buildTransactionQuery(parts) {
|
|
708
|
+
const operationName = `Transaction`;
|
|
709
|
+
const variableDefinitions = parts.reduce((acc, m) => [...acc, ...m.variableDefinitions], []);
|
|
710
|
+
const mutationParts = parts.map(m => m.queryPart);
|
|
711
|
+
const query = `mutation ${operationName} (${variableDefinitions.join(', ')}) { ${mutationParts.join('\n')} }`;
|
|
712
|
+
const variables = parts.reduce((acc, m) => ({ ...acc, ...m.variables }), {});
|
|
713
|
+
return { query, variables };
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
class HasuraService {
|
|
718
|
+
getHeaders = inject(GRAPHQL_HEADERS);
|
|
719
|
+
apolloClientManager = inject(ApolloClientManagerService);
|
|
720
|
+
config = inject(HASURA_CONFIG);
|
|
721
|
+
getApolloClient() {
|
|
722
|
+
return this.apolloClientManager.getClient(this.config.url, this.getHeaders);
|
|
723
|
+
}
|
|
724
|
+
subscribe({ query, variables, fetchPolicy = 'network-only', context }) {
|
|
725
|
+
return this.getApolloClient().pipe(switchMap((client) => client.subscribe({
|
|
726
|
+
query: makeSubscription(query),
|
|
727
|
+
variables: variables,
|
|
728
|
+
fetchPolicy: fetchPolicy,
|
|
729
|
+
context
|
|
730
|
+
})));
|
|
731
|
+
}
|
|
732
|
+
async mutate(...args) {
|
|
733
|
+
const client = await lastValueFrom(this.getApolloClient());
|
|
734
|
+
return lastValueFrom(client.mutate(...args)).catch((error) => {
|
|
735
|
+
console.error(error.graphQLErrors);
|
|
736
|
+
throw error;
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
async mutateByQueryPart(part) {
|
|
740
|
+
const mutation = HasuraQueryBuilder.buildMutation(part);
|
|
741
|
+
return this.mutate({
|
|
742
|
+
mutation: gql `${mutation}`,
|
|
743
|
+
variables: part.variables,
|
|
744
|
+
}).then((res) => {
|
|
745
|
+
return res.data[part?.alias ?? part.operationName];
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
async query(...args) {
|
|
749
|
+
const client = await lastValueFrom(this.getApolloClient());
|
|
750
|
+
// fetchPolicyが指定されていない場合はnetwork-onlyをデフォルトに
|
|
751
|
+
const [options] = args;
|
|
752
|
+
const queryOptions = {
|
|
753
|
+
...options,
|
|
754
|
+
fetchPolicy: options?.fetchPolicy || 'network-only'
|
|
755
|
+
};
|
|
756
|
+
return lastValueFrom(client.query(queryOptions)).catch((error) => {
|
|
757
|
+
console.error('[HasuraService] query error:', error);
|
|
758
|
+
throw error;
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
// Observable版のqueryメソッド(キャッシュ可能)
|
|
762
|
+
watchQuery(options) {
|
|
763
|
+
const { query, variables, fetchPolicy = 'cache-first' } = options;
|
|
764
|
+
return this.getApolloClient().pipe(switchMap((client) => client.watchQuery({
|
|
765
|
+
query: makeSubscription(query),
|
|
766
|
+
variables: variables,
|
|
767
|
+
fetchPolicy: fetchPolicy
|
|
768
|
+
}).valueChanges));
|
|
769
|
+
}
|
|
770
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
771
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraService, providedIn: 'root' });
|
|
772
|
+
}
|
|
773
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraService, decorators: [{
|
|
774
|
+
type: Injectable,
|
|
775
|
+
args: [{ providedIn: 'root' }]
|
|
776
|
+
}] });
|
|
777
|
+
|
|
778
|
+
class _HasuraRepository extends Repository {
|
|
779
|
+
get pkey() {
|
|
780
|
+
return `${this.tableName}_pkey`;
|
|
781
|
+
}
|
|
782
|
+
getQueryBuilder() {
|
|
783
|
+
return new HasuraQueryBuilder({ tableName: this.tableName, pk: this.pkey, columns: this.updateColumns });
|
|
784
|
+
}
|
|
785
|
+
async get(params) {
|
|
786
|
+
const part = this.getQueryBuilder().parts.queries.get.build({ id: params.id });
|
|
787
|
+
return this.hasura.query({
|
|
788
|
+
query: gql$1 `${this.getQueryBuilder().buildQuery(part)}`,
|
|
789
|
+
variables: part.variables,
|
|
790
|
+
fetchPolicy: 'network-only',
|
|
791
|
+
})
|
|
792
|
+
.then((res) => this.converter.fromHasura(res.data[part.operationName]));
|
|
793
|
+
}
|
|
794
|
+
async list() {
|
|
795
|
+
const part = this.getQueryBuilder().parts.queries.get.buildMany();
|
|
796
|
+
return this.hasura.query({
|
|
797
|
+
query: gql$1 `${this.getQueryBuilder().buildQuery(part)}`,
|
|
798
|
+
fetchPolicy: 'network-only'
|
|
799
|
+
}).then((res) => this.converter.fromHasuraMany(res.data[part.operationName]));
|
|
800
|
+
}
|
|
801
|
+
listChanges() {
|
|
802
|
+
const part = this.getQueryBuilder().parts.queries.get.buildMany();
|
|
803
|
+
const query = this.getQueryBuilder().buildQuery(part);
|
|
804
|
+
return this.hasura.subscribe({ query: gql$1 `${query}`, variables: {} }).pipe(map((res) => this.converter.fromHasuraMany(res.data[part.operationName])));
|
|
805
|
+
}
|
|
806
|
+
async create(data) {
|
|
807
|
+
const converted = this.converter.toHasura(data);
|
|
808
|
+
const part = this.getQueryBuilder().parts.mutations.create.build(converted);
|
|
809
|
+
return this.hasura.mutateByQueryPart(part).then(result => {
|
|
810
|
+
return this.converter.fromHasura(result.returning[0]);
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async createMany(data) {
|
|
814
|
+
const items = this.converter.toHasuraMany(data);
|
|
815
|
+
const part = this.getQueryBuilder().parts.mutations.create.buildMany(items);
|
|
816
|
+
return this.hasura.mutateByQueryPart(part).then((result) => {
|
|
817
|
+
return this.converter.fromHasuraMany(result.returning);
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async update(data) {
|
|
821
|
+
const item = this.converter.toHasura(data);
|
|
822
|
+
const part = this.getQueryBuilder().parts.mutations.update.build(item);
|
|
823
|
+
return this.hasura.mutateByQueryPart(part).then(() => { });
|
|
824
|
+
}
|
|
825
|
+
async updateMany(data) {
|
|
826
|
+
const items = this.converter.toHasuraMany(data);
|
|
827
|
+
const part = this.getQueryBuilder().parts.mutations.update.buildMany(items);
|
|
828
|
+
return this.hasura.mutateByQueryPart(part).then((result) => result.affected_rows).then(() => { });
|
|
829
|
+
}
|
|
830
|
+
async delete(params) {
|
|
831
|
+
const part = this.getQueryBuilder().parts.mutations.delete_.build(params);
|
|
832
|
+
return this.hasura.mutateByQueryPart(part).then(() => { });
|
|
833
|
+
}
|
|
834
|
+
async deleteMany(params) {
|
|
835
|
+
const part = this.getQueryBuilder().parts.mutations.delete_.buildMany(params);
|
|
836
|
+
return this.hasura.mutateByQueryPart(part).then((result) => result.affected_rows);
|
|
837
|
+
}
|
|
838
|
+
async deleteAll() {
|
|
839
|
+
const part = this.getQueryBuilder().parts.mutations.delete_.buildAll();
|
|
840
|
+
console.debug('part:', part);
|
|
841
|
+
return this.hasura.mutateByQueryPart(part).then(() => { });
|
|
842
|
+
}
|
|
843
|
+
async save(data) {
|
|
844
|
+
const item = this.converter.toHasura(data);
|
|
845
|
+
const part = this.getQueryBuilder().parts.mutations.save.build(item);
|
|
846
|
+
return this.hasura.mutateByQueryPart(part).then((res) => res.returning[0]);
|
|
847
|
+
}
|
|
848
|
+
async saveMany(entities) {
|
|
849
|
+
const items = this.converter.toHasuraMany(entities);
|
|
850
|
+
const part = this.getQueryBuilder().parts.mutations.save.buildMany(items);
|
|
851
|
+
return this.hasura.mutateByQueryPart(part).then(() => { });
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
class HasuraRepository extends _HasuraRepository {
|
|
855
|
+
hasura = inject(HasuraService);
|
|
856
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraRepository, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
857
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraRepository });
|
|
858
|
+
}
|
|
859
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.5", ngImport: i0, type: HasuraRepository, decorators: [{
|
|
860
|
+
type: Injectable
|
|
861
|
+
}] });
|
|
862
|
+
function getHasuraRepository(Entity, deps) {
|
|
863
|
+
class Repository extends _HasuraRepository {
|
|
864
|
+
hasura = deps.hasura;
|
|
865
|
+
converter = getConverter(Entity);
|
|
866
|
+
tableName = getTableName(Entity);
|
|
867
|
+
updateColumns = getFields(Entity, { case: 'snake' });
|
|
868
|
+
}
|
|
869
|
+
return new Repository();
|
|
870
|
+
}
|
|
871
|
+
function injectHasuraRepository(Entity) {
|
|
872
|
+
return getHasuraRepository(Entity, { hasura: inject(HasuraService) });
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Generated bundle index. Do not edit.
|
|
877
|
+
*/
|
|
878
|
+
|
|
879
|
+
export { ApolloClientManagerService, ApolloMultiService, GET_APOLLO_CLIENT, GRAPHQL_HEADERS, HASURA_CONFIG, Hasura, HasuraInterceptor, HasuraQueryBuilder, HasuraRepository, HasuraService, HasuraUtils, _HasuraRepository, deepCamelToSnakeCase, deepSnakeToCamelCase, getConverter, getFieldAnnotationMap, getFields, getFlattenFieldAnnotations, getHasuraRepository, getTableName, injectHasuraRepository, makeConverter, provideApolloOptions, provideGraphqlHeaders, provideHasura, provideHasuraConfig, provideHasuraGetHeaders, provideHasuraWithWebSocket, resolve, wrap };
|
|
880
|
+
//# sourceMappingURL=nx-ddd-hasura.mjs.map
|