amplifyquery 1.0.15 β 1.0.17
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/service.js +113 -4
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
package/dist/service.js
CHANGED
|
@@ -559,7 +559,10 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
559
559
|
// Check cache first (if forceRefresh is false)
|
|
560
560
|
if (!options.forceRefresh) {
|
|
561
561
|
const cachedItems = query_1.queryClient.getQueryData(queryKey);
|
|
562
|
-
|
|
562
|
+
const queryState = query_1.queryClient.getQueryState(queryKey);
|
|
563
|
+
if (cachedItems &&
|
|
564
|
+
cachedItems.length > 0 &&
|
|
565
|
+
!(queryState === null || queryState === void 0 ? void 0 : queryState.isInvalidated)) {
|
|
563
566
|
console.log(`π¬ ${modelName} list using cache`, queryKey);
|
|
564
567
|
return cachedItems.filter((item) => item !== null);
|
|
565
568
|
}
|
|
@@ -1119,7 +1122,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1119
1122
|
},
|
|
1120
1123
|
// React Hook returning method - Reimplemented based on TanStack Query
|
|
1121
1124
|
useHook: (options) => {
|
|
1122
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1125
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
1123
1126
|
const hookQueryClient = (0, react_query_1.useQueryClient)();
|
|
1124
1127
|
// Determine query key
|
|
1125
1128
|
const queryKey = (0, react_1.useMemo)(() => {
|
|
@@ -1167,16 +1170,82 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1167
1170
|
(_g = options === null || options === void 0 ? void 0 : options.customList) === null || _g === void 0 ? void 0 : _g.forceRefresh,
|
|
1168
1171
|
service,
|
|
1169
1172
|
]);
|
|
1173
|
+
const realtimeEnabled = ((_h = options === null || options === void 0 ? void 0 : options.realtime) === null || _h === void 0 ? void 0 : _h.enabled) === true;
|
|
1170
1174
|
const queryOptions = {
|
|
1171
1175
|
queryKey,
|
|
1172
1176
|
queryFn,
|
|
1173
|
-
enabled: ((
|
|
1177
|
+
enabled: ((_j = options === null || options === void 0 ? void 0 : options.initialFetchOptions) === null || _j === void 0 ? void 0 : _j.fetch) !== false && !realtimeEnabled,
|
|
1174
1178
|
staleTime: 1000 * 30, // Keep fresh for 30 seconds (refresh more frequently)
|
|
1175
1179
|
refetchOnMount: true, // Refetch on component mount
|
|
1176
1180
|
refetchOnWindowFocus: false, // Don't auto-refetch on window focus
|
|
1177
1181
|
refetchOnReconnect: true, // Refetch on network reconnect
|
|
1178
1182
|
};
|
|
1183
|
+
const [isSynced, setIsSynced] = (0, react_1.useState)(undefined);
|
|
1179
1184
|
const { data: items = [], isLoading, error, refetch, } = (0, react_query_1.useQuery)(queryOptions);
|
|
1185
|
+
(0, react_1.useEffect)(() => {
|
|
1186
|
+
var _a, _b, _c;
|
|
1187
|
+
if (!realtimeEnabled)
|
|
1188
|
+
return;
|
|
1189
|
+
if (options === null || options === void 0 ? void 0 : options.customList) {
|
|
1190
|
+
console.warn(`π¬ ${modelName} useHook realtime: customList is not supported.`);
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const client = (0, client_1.getClient)();
|
|
1194
|
+
const model = (_a = client.models) === null || _a === void 0 ? void 0 : _a[modelName];
|
|
1195
|
+
if (!(model === null || model === void 0 ? void 0 : model.observeQuery)) {
|
|
1196
|
+
console.warn(`π¬ ${modelName} useHook realtime: observeQuery not available.`);
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
const observeOptions = Object.assign({}, (((_b = options === null || options === void 0 ? void 0 : options.realtime) === null || _b === void 0 ? void 0 : _b.observeOptions) || {}));
|
|
1200
|
+
if (observeOptions.filter === undefined &&
|
|
1201
|
+
((_c = options === null || options === void 0 ? void 0 : options.initialFetchOptions) === null || _c === void 0 ? void 0 : _c.filter)) {
|
|
1202
|
+
observeOptions.filter = options.initialFetchOptions.filter;
|
|
1203
|
+
}
|
|
1204
|
+
let isMounted = true;
|
|
1205
|
+
const subscription = model.observeQuery(observeOptions).subscribe({
|
|
1206
|
+
next: ({ items: nextItems, isSynced: synced }) => {
|
|
1207
|
+
if (!isMounted)
|
|
1208
|
+
return;
|
|
1209
|
+
const safeItems = Array.isArray(nextItems)
|
|
1210
|
+
? nextItems.filter(Boolean)
|
|
1211
|
+
: [];
|
|
1212
|
+
const previousItems = hookQueryClient.getQueryData(queryKey) || [];
|
|
1213
|
+
const previousIds = new Set(previousItems.map((item) => item === null || item === void 0 ? void 0 : item.id).filter(Boolean));
|
|
1214
|
+
const nextIds = new Set(safeItems.map((item) => item === null || item === void 0 ? void 0 : item.id).filter(Boolean));
|
|
1215
|
+
previousIds.forEach((id) => {
|
|
1216
|
+
if (!nextIds.has(id)) {
|
|
1217
|
+
hookQueryClient.removeQueries({
|
|
1218
|
+
queryKey: itemKey(modelName, id),
|
|
1219
|
+
exact: true,
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
hookQueryClient.setQueryData(queryKey, safeItems);
|
|
1224
|
+
safeItems.forEach((item) => {
|
|
1225
|
+
if (item === null || item === void 0 ? void 0 : item.id) {
|
|
1226
|
+
hookQueryClient.setQueryData(itemKey(modelName, item.id), item);
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
setIsSynced(Boolean(synced));
|
|
1230
|
+
},
|
|
1231
|
+
error: (err) => {
|
|
1232
|
+
console.error(`π¬ ${modelName} useHook realtime subscribe error:`, err);
|
|
1233
|
+
},
|
|
1234
|
+
});
|
|
1235
|
+
return () => {
|
|
1236
|
+
var _a;
|
|
1237
|
+
isMounted = false;
|
|
1238
|
+
(_a = subscription === null || subscription === void 0 ? void 0 : subscription.unsubscribe) === null || _a === void 0 ? void 0 : _a.call(subscription);
|
|
1239
|
+
};
|
|
1240
|
+
}, [
|
|
1241
|
+
realtimeEnabled,
|
|
1242
|
+
modelName,
|
|
1243
|
+
queryKey,
|
|
1244
|
+
hookQueryClient,
|
|
1245
|
+
options === null || options === void 0 ? void 0 : options.customList,
|
|
1246
|
+
(_k = options === null || options === void 0 ? void 0 : options.initialFetchOptions) === null || _k === void 0 ? void 0 : _k.filter,
|
|
1247
|
+
(_l = options === null || options === void 0 ? void 0 : options.realtime) === null || _l === void 0 ? void 0 : _l.observeOptions,
|
|
1248
|
+
]);
|
|
1180
1249
|
// Interface functions implementation
|
|
1181
1250
|
const getItem = (0, react_1.useCallback)((id) => {
|
|
1182
1251
|
// Use useQueryData to get latest single item from current cache
|
|
@@ -1197,6 +1266,17 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1197
1266
|
const createItem = (0, react_1.useCallback)((data) => __awaiter(this, void 0, void 0, function* () {
|
|
1198
1267
|
try {
|
|
1199
1268
|
const result = yield service.create(data);
|
|
1269
|
+
if (result) {
|
|
1270
|
+
// Keep hook cache in sync immediately
|
|
1271
|
+
hookQueryClient.setQueryData(queryKey, (oldData) => {
|
|
1272
|
+
const oldItems = Array.isArray(oldData) ? oldData : [];
|
|
1273
|
+
if (oldItems.some((item) => (item === null || item === void 0 ? void 0 : item.id) === result.id)) {
|
|
1274
|
+
return oldItems;
|
|
1275
|
+
}
|
|
1276
|
+
return [...oldItems, result];
|
|
1277
|
+
});
|
|
1278
|
+
hookQueryClient.setQueryData(itemKey(modelName, result.id), result);
|
|
1279
|
+
}
|
|
1200
1280
|
// Automatically refresh list after successful create
|
|
1201
1281
|
yield refetch();
|
|
1202
1282
|
return result;
|
|
@@ -1210,6 +1290,14 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1210
1290
|
const updateItem = (0, react_1.useCallback)((data) => __awaiter(this, void 0, void 0, function* () {
|
|
1211
1291
|
try {
|
|
1212
1292
|
const result = yield service.update(data);
|
|
1293
|
+
if (result) {
|
|
1294
|
+
// Keep hook cache in sync immediately
|
|
1295
|
+
hookQueryClient.setQueryData(queryKey, (oldData) => {
|
|
1296
|
+
const oldItems = Array.isArray(oldData) ? oldData : [];
|
|
1297
|
+
return oldItems.map((item) => item && item.id === result.id ? result : item);
|
|
1298
|
+
});
|
|
1299
|
+
hookQueryClient.setQueryData(itemKey(modelName, result.id), result);
|
|
1300
|
+
}
|
|
1213
1301
|
// Automatically refresh list after successful update
|
|
1214
1302
|
yield refetch();
|
|
1215
1303
|
return result;
|
|
@@ -1223,6 +1311,14 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1223
1311
|
const deleteItem = (0, react_1.useCallback)((id) => __awaiter(this, void 0, void 0, function* () {
|
|
1224
1312
|
try {
|
|
1225
1313
|
const result = yield service.delete(id);
|
|
1314
|
+
if (result) {
|
|
1315
|
+
// Keep hook cache in sync immediately
|
|
1316
|
+
hookQueryClient.setQueryData(queryKey, (oldData) => {
|
|
1317
|
+
const oldItems = Array.isArray(oldData) ? oldData : [];
|
|
1318
|
+
return oldItems.filter((item) => (item === null || item === void 0 ? void 0 : item.id) !== id);
|
|
1319
|
+
});
|
|
1320
|
+
hookQueryClient.setQueryData(itemKey(modelName, id), null);
|
|
1321
|
+
}
|
|
1226
1322
|
// Automatically refresh list after successful delete
|
|
1227
1323
|
yield refetch();
|
|
1228
1324
|
return result;
|
|
@@ -1252,6 +1348,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1252
1348
|
items,
|
|
1253
1349
|
isLoading,
|
|
1254
1350
|
error: error,
|
|
1351
|
+
isSynced,
|
|
1255
1352
|
getItem,
|
|
1256
1353
|
refresh,
|
|
1257
1354
|
create: createItem,
|
|
@@ -1330,13 +1427,25 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1330
1427
|
const deleteItem = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () {
|
|
1331
1428
|
try {
|
|
1332
1429
|
const result = yield deleteMutation.mutateAsync();
|
|
1430
|
+
if (result) {
|
|
1431
|
+
// Ensure the hook's query cache reflects deletion immediately
|
|
1432
|
+
hookQueryClient.setQueryData(singleItemQueryKey, null);
|
|
1433
|
+
hookQueryClient.invalidateQueries({
|
|
1434
|
+
queryKey: [modelName],
|
|
1435
|
+
refetchType: "active",
|
|
1436
|
+
});
|
|
1437
|
+
hookQueryClient.invalidateQueries({
|
|
1438
|
+
queryKey: singleItemQueryKey,
|
|
1439
|
+
refetchType: "active",
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1333
1442
|
return result;
|
|
1334
1443
|
}
|
|
1335
1444
|
catch (error) {
|
|
1336
1445
|
console.error(`π¬ ${modelName} useItemHook delete error:`, error);
|
|
1337
1446
|
throw error;
|
|
1338
1447
|
}
|
|
1339
|
-
}), [deleteMutation]);
|
|
1448
|
+
}), [deleteMutation, hookQueryClient, modelName, singleItemQueryKey]);
|
|
1340
1449
|
// Change loading state to false when isLoading is true and cached data exists
|
|
1341
1450
|
const effectiveLoading = isLoading && !cachedData;
|
|
1342
1451
|
// μΊμ μ 리λ₯Ό μν ν¨κ³Ό μ΅μ ν (ν λ²λ§ μ€ν)
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type StoreState<T> = {
|
|
|
20
20
|
export type ModelHook<T> = {
|
|
21
21
|
items: T[];
|
|
22
22
|
isLoading: boolean;
|
|
23
|
+
isSynced?: boolean;
|
|
23
24
|
error: Error | null;
|
|
24
25
|
getItem: (id: string) => T | null | undefined;
|
|
25
26
|
refresh: (options?: {
|
|
@@ -92,6 +93,10 @@ export interface AmplifyDataService<T> {
|
|
|
92
93
|
args: Record<string, any>;
|
|
93
94
|
forceRefresh?: boolean;
|
|
94
95
|
};
|
|
96
|
+
realtime?: {
|
|
97
|
+
enabled?: boolean;
|
|
98
|
+
observeOptions?: Record<string, any>;
|
|
99
|
+
};
|
|
95
100
|
}) => ModelHook<T>;
|
|
96
101
|
useItemHook: (id: string) => ItemHook<T>;
|
|
97
102
|
modelName: string;
|