amplifyquery 1.0.12 → 1.0.14
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/query.js +9 -2
- package/dist/service.js +39 -24
- package/dist/singleton.js +66 -2
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/query.js
CHANGED
|
@@ -134,7 +134,11 @@ function configure(options = {}) {
|
|
|
134
134
|
maxAge: ((_a = config.storage) === null || _a === void 0 ? void 0 : _a.maxAge) || 1000 * 60 * 60 * 24 * 7, // Default 7 days
|
|
135
135
|
dehydrateOptions: {
|
|
136
136
|
shouldDehydrateQuery: (query) => {
|
|
137
|
-
|
|
137
|
+
var _a;
|
|
138
|
+
// Only persist successful queries to reduce hydration cancellation noise
|
|
139
|
+
if (((_a = query.state) === null || _a === void 0 ? void 0 : _a.status) !== "success")
|
|
140
|
+
return false;
|
|
141
|
+
// Avoid persisting mutation-like or transient keys if needed later
|
|
138
142
|
return true;
|
|
139
143
|
},
|
|
140
144
|
},
|
|
@@ -169,7 +173,10 @@ function invalidateModel(modelName) {
|
|
|
169
173
|
* @param id Item ID
|
|
170
174
|
*/
|
|
171
175
|
function invalidateModelItem(modelName, id) {
|
|
172
|
-
|
|
176
|
+
// New item key
|
|
177
|
+
exports.queryClient.invalidateQueries({ queryKey: [modelName, "item", id] });
|
|
178
|
+
// Backward cleanup (in case legacy keys exist)
|
|
179
|
+
exports.queryClient.removeQueries({ queryKey: [modelName, id], exact: true });
|
|
173
180
|
}
|
|
174
181
|
/**
|
|
175
182
|
* Invalidate model items with a specific field value
|
package/dist/service.js
CHANGED
|
@@ -18,6 +18,15 @@ const react_query_1 = require("@tanstack/react-query");
|
|
|
18
18
|
const auth_1 = require("aws-amplify/auth");
|
|
19
19
|
const expo_crypto_1 = require("expo-crypto");
|
|
20
20
|
const react_1 = require("react");
|
|
21
|
+
// -------------------------------
|
|
22
|
+
// Query key helpers
|
|
23
|
+
// -------------------------------
|
|
24
|
+
function itemKey(modelName, id) {
|
|
25
|
+
return [modelName, "item", id];
|
|
26
|
+
}
|
|
27
|
+
function isItemKeyForModel(modelName, key) {
|
|
28
|
+
return Array.isArray(key) && key[0] === modelName && key[1] === "item";
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* Utility function to get owner value based on authentication mode
|
|
23
32
|
* Sets owner value only in userPool auth mode, returns empty string for other auth modes
|
|
@@ -58,9 +67,12 @@ function findRelatedQueryKeys(modelName, queryClient) {
|
|
|
58
67
|
.getQueryCache()
|
|
59
68
|
.findAll({
|
|
60
69
|
predicate: ({ queryKey }) => {
|
|
61
|
-
// Find all query keys
|
|
62
|
-
//
|
|
63
|
-
|
|
70
|
+
// Find all query keys for the model, but EXCLUDE single-item keys
|
|
71
|
+
// Examples kept: [model], [model, 'filter', ...], [model, 'query', ...], [model, Relation, id, ...]
|
|
72
|
+
// Excluded: [model, 'item', id]
|
|
73
|
+
return (Array.isArray(queryKey) &&
|
|
74
|
+
queryKey[0] === modelName &&
|
|
75
|
+
!isItemKeyForModel(modelName, queryKey));
|
|
64
76
|
},
|
|
65
77
|
})
|
|
66
78
|
.map((query) => query.queryKey);
|
|
@@ -86,7 +98,7 @@ function performOptimisticUpdate(queryClient, modelName, relatedQueryKeys, itemI
|
|
|
86
98
|
return previousDataMap; // 빈 맵 반환으로 rollback 시 영향 없음
|
|
87
99
|
}
|
|
88
100
|
// 1. Update individual item cache
|
|
89
|
-
const singleItemQueryKey =
|
|
101
|
+
const singleItemQueryKey = itemKey(modelName, itemId);
|
|
90
102
|
const previousItemSingle = queryClient.getQueryData(singleItemQueryKey);
|
|
91
103
|
previousDataMap.set(singleItemQueryKey, previousItemSingle);
|
|
92
104
|
// Merge with existing data if available, otherwise use updateData as optimistic data
|
|
@@ -136,7 +148,7 @@ function handleCacheUpdateOnSuccess(queryClient, modelName, relatedQueryKeys, it
|
|
|
136
148
|
if (actualItemId &&
|
|
137
149
|
typeof actualItemId === "string" &&
|
|
138
150
|
actualItemId === itemId) {
|
|
139
|
-
queryClient.setQueryData(
|
|
151
|
+
queryClient.setQueryData(itemKey(modelName, itemId), updatedItem);
|
|
140
152
|
}
|
|
141
153
|
else {
|
|
142
154
|
console.warn(`🍬 ${modelName} handleCacheUpdateOnSuccess: ID mismatch! Expected: ${itemId}, Actual: ${actualItemId}. Skipping cache update.`);
|
|
@@ -245,7 +257,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
245
257
|
// Backup previous data for optimistic update
|
|
246
258
|
const previousDataMap = new Map();
|
|
247
259
|
// Update individual item cache
|
|
248
|
-
const singleItemQueryKey =
|
|
260
|
+
const singleItemQueryKey = itemKey(modelName, newItem.id);
|
|
249
261
|
const previousItemSingle = query_1.queryClient.getQueryData(singleItemQueryKey);
|
|
250
262
|
previousDataMap.set(singleItemQueryKey, previousItemSingle);
|
|
251
263
|
query_1.queryClient.setQueryData(singleItemQueryKey, newItem);
|
|
@@ -401,7 +413,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
401
413
|
});
|
|
402
414
|
// Update individual item caches
|
|
403
415
|
preparedItems.forEach((item) => {
|
|
404
|
-
const singleItemQueryKey =
|
|
416
|
+
const singleItemQueryKey = itemKey(modelName, item.id);
|
|
405
417
|
const previousItemSingle = query_1.queryClient.getQueryData(singleItemQueryKey);
|
|
406
418
|
previousDataMap.set(singleItemQueryKey, previousItemSingle);
|
|
407
419
|
query_1.queryClient.setQueryData(singleItemQueryKey, item);
|
|
@@ -416,7 +428,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
416
428
|
const itemId = createdItem === null || createdItem === void 0 ? void 0 : createdItem.id;
|
|
417
429
|
// 🔧 버그 수정: ID가 유효한 경우에만 개별 캐시에 저장
|
|
418
430
|
if (itemId && typeof itemId === "string") {
|
|
419
|
-
query_1.queryClient.setQueryData(
|
|
431
|
+
query_1.queryClient.setQueryData(itemKey(modelName, itemId), createdItem);
|
|
420
432
|
}
|
|
421
433
|
else {
|
|
422
434
|
console.warn(`🍬 ${modelName} createList: Invalid createdItem ID found, skipping cache update:`, itemId, createdItem);
|
|
@@ -465,7 +477,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
465
477
|
// Get item
|
|
466
478
|
get: (id_1, ...args_1) => __awaiter(this, [id_1, ...args_1], void 0, function* (id, options = { forceRefresh: false }) {
|
|
467
479
|
try {
|
|
468
|
-
const singleItemQueryKey =
|
|
480
|
+
const singleItemQueryKey = itemKey(modelName, id);
|
|
469
481
|
// Check cache first (if forceRefresh is false)
|
|
470
482
|
if (!options.forceRefresh) {
|
|
471
483
|
const cachedItem = query_1.queryClient.getQueryData(singleItemQueryKey);
|
|
@@ -606,7 +618,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
606
618
|
const itemId = item === null || item === void 0 ? void 0 : item.id;
|
|
607
619
|
// 🔧 버그 수정: ID가 유효한 경우에만 개별 캐시에 저장
|
|
608
620
|
if (itemId && typeof itemId === "string") {
|
|
609
|
-
query_1.queryClient.setQueryData(
|
|
621
|
+
query_1.queryClient.setQueryData(itemKey(modelName, itemId), item);
|
|
610
622
|
}
|
|
611
623
|
else {
|
|
612
624
|
console.warn(`🍬 ${modelName} list: Invalid item ID found, skipping cache update:`, itemId, item);
|
|
@@ -661,7 +673,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
661
673
|
const itemId = item === null || item === void 0 ? void 0 : item.id;
|
|
662
674
|
// 🔧 버그 수정: ID가 유효한 경우에만 개별 캐시에 저장
|
|
663
675
|
if (itemId && typeof itemId === "string") {
|
|
664
|
-
query_1.queryClient.setQueryData(
|
|
676
|
+
query_1.queryClient.setQueryData(itemKey(modelName, itemId), item);
|
|
665
677
|
}
|
|
666
678
|
else {
|
|
667
679
|
console.warn(`🍬 ${modelName} list fallback: Invalid item ID found, skipping cache update:`, itemId, item);
|
|
@@ -727,7 +739,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
727
739
|
else {
|
|
728
740
|
console.warn(`🍬 ${modelName} update API response missing. Maintaining optimistic update data.`);
|
|
729
741
|
// If no API response, return the data saved during optimistic update
|
|
730
|
-
const singleItemQueryKey =
|
|
742
|
+
const singleItemQueryKey = itemKey(modelName, itemId);
|
|
731
743
|
return (previousDataMap.get(singleItemQueryKey) || null);
|
|
732
744
|
}
|
|
733
745
|
}
|
|
@@ -759,7 +771,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
759
771
|
// Backup item data before deletion (for rollback)
|
|
760
772
|
const previousDataMap = new Map();
|
|
761
773
|
// Backup previous data and perform optimistic update for individual item (set to null)
|
|
762
|
-
const singleItemQueryKey =
|
|
774
|
+
const singleItemQueryKey = itemKey(modelName, id);
|
|
763
775
|
const previousItemSingle = query_1.queryClient.getQueryData(singleItemQueryKey);
|
|
764
776
|
previousDataMap.set(singleItemQueryKey, previousItemSingle);
|
|
765
777
|
query_1.queryClient.setQueryData(singleItemQueryKey, null);
|
|
@@ -823,7 +835,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
823
835
|
// Optimistic update - remove items from all caches
|
|
824
836
|
ids.forEach((id) => {
|
|
825
837
|
// Backup previous data and perform optimistic update for individual item (null)
|
|
826
|
-
const singleItemQueryKey =
|
|
838
|
+
const singleItemQueryKey = itemKey(modelName, id);
|
|
827
839
|
const previousItemSingle = query_1.queryClient.getQueryData(singleItemQueryKey);
|
|
828
840
|
previousItemsCache.set(id, previousItemSingle || null);
|
|
829
841
|
previousDataMap.set(singleItemQueryKey, previousItemSingle); // Backup to map
|
|
@@ -867,7 +879,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
867
879
|
const previousItem = previousItemsCache.get(failedId);
|
|
868
880
|
if (previousItem !== undefined) {
|
|
869
881
|
// Restore if not undefined (was in cache)
|
|
870
|
-
const singleItemQueryKey =
|
|
882
|
+
const singleItemQueryKey = itemKey(modelName, failedId);
|
|
871
883
|
query_1.queryClient.setQueryData(singleItemQueryKey, previousItem);
|
|
872
884
|
}
|
|
873
885
|
// Restore failed item to list queries
|
|
@@ -892,7 +904,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
892
904
|
}
|
|
893
905
|
// Invalidate all related queries to force refresh (safety mechanism)
|
|
894
906
|
relatedQueryKeys.forEach((queryKey) => query_1.queryClient.invalidateQueries({ queryKey }));
|
|
895
|
-
ids.forEach((id) => query_1.queryClient.invalidateQueries({ queryKey:
|
|
907
|
+
ids.forEach((id) => query_1.queryClient.invalidateQueries({ queryKey: itemKey(modelName, id) }));
|
|
896
908
|
console.log(`🍬 ${modelName} batch delete: ${results.success.length} items deleted, ${results.failed.length} items failed`);
|
|
897
909
|
return results;
|
|
898
910
|
}
|
|
@@ -949,7 +961,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
949
961
|
}
|
|
950
962
|
else {
|
|
951
963
|
console.warn(`🍬 ${modelName} upsert(update) no API response. Keeping optimistic update data.`);
|
|
952
|
-
const singleItemQueryKey =
|
|
964
|
+
const singleItemQueryKey = itemKey(modelName, data.id);
|
|
953
965
|
return (previousDataMap.get(singleItemQueryKey) ||
|
|
954
966
|
null);
|
|
955
967
|
}
|
|
@@ -965,7 +977,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
965
977
|
}
|
|
966
978
|
else {
|
|
967
979
|
console.warn(`🍬 ${modelName} upsert(create) no API response. Keeping optimistic update data.`);
|
|
968
|
-
const singleItemQueryKey =
|
|
980
|
+
const singleItemQueryKey = itemKey(modelName, data.id);
|
|
969
981
|
return (previousDataMap.get(singleItemQueryKey) ||
|
|
970
982
|
null);
|
|
971
983
|
}
|
|
@@ -1047,7 +1059,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1047
1059
|
const itemId = item === null || item === void 0 ? void 0 : item.id;
|
|
1048
1060
|
// 🔧 버그 수정: ID가 유효한 경우에만 개별 캐시에 저장
|
|
1049
1061
|
if (itemId && typeof itemId === "string") {
|
|
1050
|
-
query_1.queryClient.setQueryData(
|
|
1062
|
+
query_1.queryClient.setQueryData(itemKey(modelName, itemId), item);
|
|
1051
1063
|
}
|
|
1052
1064
|
else {
|
|
1053
1065
|
console.warn(`🍬 ${modelName} customList: Invalid item ID found, skipping cache update:`, itemId, item);
|
|
@@ -1164,7 +1176,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1164
1176
|
// Interface functions implementation
|
|
1165
1177
|
const getItem = (0, react_1.useCallback)((id) => {
|
|
1166
1178
|
// Use useQueryData to get latest single item from current cache
|
|
1167
|
-
const cachedItem = hookQueryClient.getQueryData(
|
|
1179
|
+
const cachedItem = hookQueryClient.getQueryData(itemKey(modelName, id));
|
|
1168
1180
|
// 🔧 버그 수정: 캐시된 아이템의 ID가 요청한 ID와 일치하는지 검증
|
|
1169
1181
|
if (cachedItem) {
|
|
1170
1182
|
const itemId = cachedItem === null || cachedItem === void 0 ? void 0 : cachedItem.id;
|
|
@@ -1189,7 +1201,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1189
1201
|
console.error(`🍬 ${modelName} useHook create error:`, _error);
|
|
1190
1202
|
throw _error; // Re-throw error
|
|
1191
1203
|
}
|
|
1192
|
-
}), [service, refetch]
|
|
1204
|
+
}), [service, refetch] // Add refetch dependency
|
|
1205
|
+
);
|
|
1193
1206
|
const updateItem = (0, react_1.useCallback)((data) => __awaiter(this, void 0, void 0, function* () {
|
|
1194
1207
|
try {
|
|
1195
1208
|
const result = yield service.update(data);
|
|
@@ -1201,7 +1214,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1201
1214
|
console.error(`🍬 ${modelName} useHook update error:`, _error);
|
|
1202
1215
|
throw _error;
|
|
1203
1216
|
}
|
|
1204
|
-
}), [service, refetch]
|
|
1217
|
+
}), [service, refetch] // Add refetch dependency
|
|
1218
|
+
);
|
|
1205
1219
|
const deleteItem = (0, react_1.useCallback)((id) => __awaiter(this, void 0, void 0, function* () {
|
|
1206
1220
|
try {
|
|
1207
1221
|
const result = yield service.delete(id);
|
|
@@ -1213,7 +1227,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1213
1227
|
console.error(`🍬 ${modelName} useHook delete error:`, error);
|
|
1214
1228
|
throw error;
|
|
1215
1229
|
}
|
|
1216
|
-
}), [service, refetch]
|
|
1230
|
+
}), [service, refetch] // refetch dependency added
|
|
1231
|
+
);
|
|
1217
1232
|
const refresh = (0, react_1.useCallback)((refreshOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
1218
1233
|
console.log(`🍬 ${modelName} useHook refresh called`, queryKey);
|
|
1219
1234
|
const { data } = yield refetch({ throwOnError: true }); // Throw on error
|
|
@@ -1244,7 +1259,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
|
|
|
1244
1259
|
// Hook for managing single item - Reimplemented based on TanStack Query
|
|
1245
1260
|
useItemHook: (id) => {
|
|
1246
1261
|
const hookQueryClient = (0, react_query_1.useQueryClient)();
|
|
1247
|
-
const singleItemQueryKey =
|
|
1262
|
+
const singleItemQueryKey = itemKey(modelName, id);
|
|
1248
1263
|
// First check data from cache
|
|
1249
1264
|
const rawCachedData = hookQueryClient.getQueryData(singleItemQueryKey);
|
|
1250
1265
|
// 🔧 버그 수정: 배열이 캐시되어 있는 경우 처리
|
package/dist/singleton.js
CHANGED
|
@@ -13,6 +13,7 @@ exports.getModelIds = void 0;
|
|
|
13
13
|
exports.createSingletonService = createSingletonService;
|
|
14
14
|
const client_1 = require("./client");
|
|
15
15
|
const auth_1 = require("aws-amplify/auth");
|
|
16
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
16
17
|
/**
|
|
17
18
|
* Function to create an extension service for singleton models
|
|
18
19
|
* @param baseService Base service
|
|
@@ -32,7 +33,7 @@ function createSingletonService(baseService, getModelId) {
|
|
|
32
33
|
return baseService.get(modelId, options);
|
|
33
34
|
}
|
|
34
35
|
catch (error) {
|
|
35
|
-
console.error(`${modelName} singleton instance lookup error:`, error);
|
|
36
|
+
// console.error(`${modelName} singleton instance lookup error:`, error);
|
|
36
37
|
// Safely call getStore
|
|
37
38
|
try {
|
|
38
39
|
(_c = (_b = (_a = baseService
|
|
@@ -122,7 +123,70 @@ function createSingletonService(baseService, getModelId) {
|
|
|
122
123
|
console.error(`${modelName} singleton instance final Upsert error:`, error);
|
|
123
124
|
return null;
|
|
124
125
|
}
|
|
125
|
-
})
|
|
126
|
+
}),
|
|
127
|
+
// React hook to manage the current singleton item
|
|
128
|
+
useCurrentHook: () => {
|
|
129
|
+
const { data: currentId, isLoading: isIdLoading, error: idError, refetch: refetchId, } = (0, react_query_1.useQuery)({
|
|
130
|
+
queryKey: [modelName, "currentId"],
|
|
131
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
var _a, _b, _c;
|
|
133
|
+
try {
|
|
134
|
+
const id = yield getModelId();
|
|
135
|
+
return id || null;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
try {
|
|
139
|
+
(_c = (_b = (_a = baseService
|
|
140
|
+
.getStore) === null || _a === void 0 ? void 0 : _a.call(baseService)) === null || _b === void 0 ? void 0 : _b.setError) === null || _c === void 0 ? void 0 : _c.call(_b, error instanceof Error ? error : new Error(String(error)));
|
|
141
|
+
}
|
|
142
|
+
catch (_storeError) { }
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}),
|
|
146
|
+
staleTime: 1000 * 60,
|
|
147
|
+
refetchOnWindowFocus: false,
|
|
148
|
+
});
|
|
149
|
+
const idForItemHook = currentId !== null && currentId !== void 0 ? currentId : "";
|
|
150
|
+
const core = baseService.useItemHook(idForItemHook);
|
|
151
|
+
const item = (() => {
|
|
152
|
+
var _a;
|
|
153
|
+
if (!currentId)
|
|
154
|
+
return null;
|
|
155
|
+
const raw = core.item;
|
|
156
|
+
if (Array.isArray(raw)) {
|
|
157
|
+
const match = raw.find((i) => (i === null || i === void 0 ? void 0 : i.id) === currentId);
|
|
158
|
+
return match || null;
|
|
159
|
+
}
|
|
160
|
+
return (_a = raw) !== null && _a !== void 0 ? _a : null;
|
|
161
|
+
})();
|
|
162
|
+
const isLoading = isIdLoading || core.isLoading;
|
|
163
|
+
const error = idError || core.error || null;
|
|
164
|
+
const refresh = () => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
if (!currentId) {
|
|
166
|
+
const { data } = yield refetchId({ throwOnError: false });
|
|
167
|
+
if (!data)
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return core.refresh();
|
|
171
|
+
});
|
|
172
|
+
const update = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
if (!currentId) {
|
|
174
|
+
const { data } = yield refetchId({ throwOnError: false });
|
|
175
|
+
if (!data)
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return core.update(data);
|
|
179
|
+
});
|
|
180
|
+
const remove = () => __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
if (!currentId) {
|
|
182
|
+
const { data } = yield refetchId({ throwOnError: false });
|
|
183
|
+
if (!data)
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
return core.delete();
|
|
187
|
+
});
|
|
188
|
+
return { item, isLoading, error, refresh, update, delete: remove };
|
|
189
|
+
} });
|
|
126
190
|
return singletonService;
|
|
127
191
|
}
|
|
128
192
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -106,6 +106,7 @@ export interface SingletonAmplifyService<T> extends AmplifyDataService<T> {
|
|
|
106
106
|
}) => Promise<T | null>;
|
|
107
107
|
updateCurrent: (data: Partial<T>) => Promise<T | null>;
|
|
108
108
|
upsertCurrent: (data: Partial<T>) => Promise<T | null>;
|
|
109
|
+
useCurrentHook: () => ItemHook<T>;
|
|
109
110
|
}
|
|
110
111
|
export interface BaseModel {
|
|
111
112
|
id: string;
|