@greatapps/common 1.1.536 → 1.1.539
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/infra/utils/array.mjs +64 -0
- package/dist/infra/utils/array.mjs.map +1 -1
- package/dist/modules/projects/hooks/create-project.hook.mjs +63 -40
- package/dist/modules/projects/hooks/create-project.hook.mjs.map +1 -1
- package/package.json +1 -1
- package/src/infra/utils/array.ts +113 -0
- package/src/modules/projects/hooks/create-project.hook.ts +84 -52
|
@@ -3,6 +3,69 @@ function insertSorted(data, newItem, compareFn) {
|
|
|
3
3
|
if (index === -1) return [...data, newItem];
|
|
4
4
|
return [...data.slice(0, index), newItem, ...data.slice(index)];
|
|
5
5
|
}
|
|
6
|
+
function insertIntoPaginatedCache({
|
|
7
|
+
pages,
|
|
8
|
+
pageNumbers,
|
|
9
|
+
newItem,
|
|
10
|
+
pageSize,
|
|
11
|
+
compareFn
|
|
12
|
+
}) {
|
|
13
|
+
if (!pages.length) return pages;
|
|
14
|
+
if (!compareFn) {
|
|
15
|
+
const firstIdx = pageNumbers.indexOf(1);
|
|
16
|
+
if (firstIdx === -1) return pages;
|
|
17
|
+
const result2 = pages.slice();
|
|
18
|
+
let carry2 = newItem;
|
|
19
|
+
for (let i = firstIdx; i < result2.length && carry2 !== null; i++) {
|
|
20
|
+
const current = result2[i];
|
|
21
|
+
const nextData = [carry2, ...current.data];
|
|
22
|
+
const overflow = nextData.length > pageSize ? nextData[nextData.length - 1] : null;
|
|
23
|
+
result2[i] = {
|
|
24
|
+
...current,
|
|
25
|
+
data: overflow !== null ? nextData.slice(0, pageSize) : nextData,
|
|
26
|
+
total: current.total + 1
|
|
27
|
+
};
|
|
28
|
+
carry2 = overflow;
|
|
29
|
+
}
|
|
30
|
+
return result2;
|
|
31
|
+
}
|
|
32
|
+
let targetIdx = -1;
|
|
33
|
+
for (let i = 0; i < pages.length; i++) {
|
|
34
|
+
const page = pages[i];
|
|
35
|
+
if (!page.data.length) continue;
|
|
36
|
+
const last = page.data[page.data.length - 1];
|
|
37
|
+
if (compareFn(newItem, last) <= 0) {
|
|
38
|
+
targetIdx = i;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (targetIdx === -1) {
|
|
43
|
+
const lastIdx = pages.length - 1;
|
|
44
|
+
const lastPage = pages[lastIdx];
|
|
45
|
+
if (lastPage.data.length < pageSize) {
|
|
46
|
+
targetIdx = lastIdx;
|
|
47
|
+
} else {
|
|
48
|
+
return pages.map((p) => ({ ...p, total: p.total + 1 }));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const result = pages.slice();
|
|
52
|
+
let carry = newItem;
|
|
53
|
+
for (let i = targetIdx; i < result.length && carry !== null; i++) {
|
|
54
|
+
const current = result[i];
|
|
55
|
+
const withInserted = insertSorted(current.data, carry, compareFn);
|
|
56
|
+
const overflow = withInserted.length > pageSize ? withInserted[withInserted.length - 1] : null;
|
|
57
|
+
result[i] = {
|
|
58
|
+
...current,
|
|
59
|
+
data: overflow !== null ? withInserted.slice(0, pageSize) : withInserted,
|
|
60
|
+
total: current.total + 1
|
|
61
|
+
};
|
|
62
|
+
carry = overflow;
|
|
63
|
+
}
|
|
64
|
+
for (let i = 0; i < targetIdx; i++) {
|
|
65
|
+
result[i] = { ...result[i], total: result[i].total + 1 };
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
6
69
|
function buildCompareFn(sort) {
|
|
7
70
|
const fields = sort.split(",").map((f) => f.trim()).filter(Boolean);
|
|
8
71
|
const parsedFields = fields.map((field) => {
|
|
@@ -29,6 +92,7 @@ function buildCompareFn(sort) {
|
|
|
29
92
|
}
|
|
30
93
|
export {
|
|
31
94
|
buildCompareFn,
|
|
95
|
+
insertIntoPaginatedCache,
|
|
32
96
|
insertSorted
|
|
33
97
|
};
|
|
34
98
|
//# sourceMappingURL=array.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/utils/array.ts"],"sourcesContent":["/**\n * Insere um item em um array já ordenado, mantendo a ordenação\n * com base na função de comparação fornecida.\n */\nexport function insertSorted<T>(\n data: T[],\n newItem: T,\n compareFn: (a: T, b: T) => number\n): T[] {\n const index = data.findIndex((item) => compareFn(newItem, item) < 0);\n if (index === -1) return [...data, newItem];\n return [...data.slice(0, index), newItem, ...data.slice(index)];\n}\n\n/**\n * Cria uma função de comparação a partir de uma string de sort da API.\n * Suporta múltiplos campos separados por vírgula e prefixo `-` para desc.\n *\n * Exemplos:\n * - \"title\" → ascendente por title\n * - \"-title\" → descendente por title\n * - \"title,-datetime_add\" → ascendente por title, depois descendente por datetime_add\n */\nexport function buildCompareFn<T extends Record<string, unknown>>(\n sort: string\n): (a: T, b: T) => number {\n const fields = sort.split(',').map((f) => f.trim()).filter(Boolean);\n\n const parsedFields = fields.map((field) => {\n const desc = field.startsWith('-');\n const key = desc ? field.slice(1) : field;\n return { key, desc };\n });\n\n return (a: T, b: T) => {\n for (const { key, desc } of parsedFields) {\n const aVal = a[key];\n const bVal = b[key];\n\n let result: number;\n\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n result = aVal.localeCompare(bVal);\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n result = aVal - bVal;\n } else {\n result = String(aVal ?? '').localeCompare(String(bVal ?? ''));\n }\n\n if (result !== 0) return desc ? -result : result;\n }\n return 0;\n };\n}\n"],"mappings":"AAIO,SAAS,aACd,MACA,SACA,WACK;AACL,QAAM,QAAQ,KAAK,UAAU,CAAC,SAAS,UAAU,SAAS,IAAI,IAAI,CAAC;AACnE,MAAI,UAAU,GAAI,QAAO,CAAC,GAAG,MAAM,OAAO;AAC1C,SAAO,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,MAAM,KAAK,CAAC;AAChE;AAWO,SAAS,eACd,MACwB;AACxB,QAAM,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAElE,QAAM,eAAe,OAAO,IAAI,CAAC,UAAU;AACzC,UAAM,OAAO,MAAM,WAAW,GAAG;AACjC,UAAM,MAAM,OAAO,MAAM,MAAM,CAAC,IAAI;AACpC,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB,CAAC;AAED,SAAO,CAAC,GAAM,MAAS;AACrB,eAAW,EAAE,KAAK,KAAK,KAAK,cAAc;AACxC,YAAM,OAAO,EAAE,GAAG;AAClB,YAAM,OAAO,EAAE,GAAG;AAElB,UAAI;AAEJ,UAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AACxD,iBAAS,KAAK,cAAc,IAAI;AAAA,MAClC,WAAW,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AAC/D,iBAAS,OAAO;AAAA,MAClB,OAAO;AACL,iBAAS,OAAO,QAAQ,EAAE,EAAE,cAAc,OAAO,QAAQ,EAAE,CAAC;AAAA,MAC9D;AAEA,UAAI,WAAW,EAAG,QAAO,OAAO,CAAC,SAAS;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/utils/array.ts"],"sourcesContent":["/**\n * Insere um item em um array já ordenado, mantendo a ordenação\n * com base na função de comparação fornecida.\n */\nexport function insertSorted<T>(\n data: T[],\n newItem: T,\n compareFn: (a: T, b: T) => number\n): T[] {\n const index = data.findIndex((item) => compareFn(newItem, item) < 0);\n if (index === -1) return [...data, newItem];\n return [...data.slice(0, index), newItem, ...data.slice(index)];\n}\n\nexport interface PaginatedPageCache<T> {\n data: T[];\n total: number;\n}\n\nexport interface InsertIntoPaginatedCacheParams<T> {\n /** Páginas atuais do cache, ordenadas por número de página (1..N). */\n pages: PaginatedPageCache<T>[];\n /** Números das páginas correspondentes (mesmo tamanho de `pages`). */\n pageNumbers: number[];\n /** Novo item a inserir. */\n newItem: T;\n /** Tamanho fixo de cada página. */\n pageSize: number;\n /**\n * Função de comparação que mantém a ordem.\n * Se não fornecida, insere no topo da página 1 (sem reordenar).\n */\n compareFn?: (a: T, b: T) => number;\n}\n\n/**\n * Insere um item em um conjunto de páginas paginadas mantendo ordenação.\n *\n * Quando `compareFn` é fornecida, descobre em qual página o item deveria\n * cair (comparando com o último item de cada página). Insere na posição\n * correta e empurra o último item da página para a próxima, propagando\n * o overflow até a última página disponível.\n *\n * Páginas não-afetadas retornam a mesma referência.\n */\nexport function insertIntoPaginatedCache<T>({\n pages,\n pageNumbers,\n newItem,\n pageSize,\n compareFn,\n}: InsertIntoPaginatedCacheParams<T>): PaginatedPageCache<T>[] {\n if (!pages.length) return pages;\n\n // Sem sort: insere no topo da página 1 e propaga overflow\n if (!compareFn) {\n // Só atualiza se a página 1 estiver no cache\n const firstIdx = pageNumbers.indexOf(1);\n if (firstIdx === -1) return pages;\n\n const result: PaginatedPageCache<T>[] = pages.slice();\n let carry: T | null = newItem;\n for (let i = firstIdx; i < result.length && carry !== null; i++) {\n const current = result[i];\n const nextData: T[] = [carry, ...current.data];\n const overflow: T | null =\n nextData.length > pageSize ? nextData[nextData.length - 1] : null;\n result[i] = {\n ...current,\n data: overflow !== null ? nextData.slice(0, pageSize) : nextData,\n total: current.total + 1,\n };\n carry = overflow;\n }\n return result;\n }\n\n // Descobre em qual página o item cai\n let targetIdx = -1;\n for (let i = 0; i < pages.length; i++) {\n const page = pages[i];\n if (!page.data.length) continue;\n const last = page.data[page.data.length - 1];\n // Se newItem vem antes (ou igual) ao último item desta página, cai aqui\n if (compareFn(newItem, last) <= 0) {\n targetIdx = i;\n break;\n }\n }\n\n // Não coube em nenhuma página com itens — tenta a última página se for incompleta\n if (targetIdx === -1) {\n const lastIdx = pages.length - 1;\n const lastPage = pages[lastIdx];\n if (lastPage.data.length < pageSize) {\n targetIdx = lastIdx;\n } else {\n // Não cai em nenhuma página carregada — apenas incrementa total\n return pages.map((p) => ({ ...p, total: p.total + 1 }));\n }\n }\n\n // Insere no target e propaga overflow para as páginas seguintes\n const result: PaginatedPageCache<T>[] = pages.slice();\n let carry: T | null = newItem;\n\n for (let i = targetIdx; i < result.length && carry !== null; i++) {\n const current = result[i];\n const withInserted: T[] = insertSorted(current.data, carry, compareFn);\n const overflow: T | null =\n withInserted.length > pageSize ? withInserted[withInserted.length - 1] : null;\n result[i] = {\n ...current,\n data: overflow !== null ? withInserted.slice(0, pageSize) : withInserted,\n total: current.total + 1,\n };\n carry = overflow;\n }\n\n // Incrementa o total nas páginas anteriores ao target (não mudaram mas o total global cresceu)\n for (let i = 0; i < targetIdx; i++) {\n result[i] = { ...result[i], total: result[i].total + 1 };\n }\n\n return result;\n}\n\n/**\n * Cria uma função de comparação a partir de uma string de sort da API.\n * Suporta múltiplos campos separados por vírgula e prefixo `-` para desc.\n *\n * Exemplos:\n * - \"title\" → ascendente por title\n * - \"-title\" → descendente por title\n * - \"title,-datetime_add\" → ascendente por title, depois descendente por datetime_add\n */\nexport function buildCompareFn<T extends Record<string, unknown>>(\n sort: string\n): (a: T, b: T) => number {\n const fields = sort.split(',').map((f) => f.trim()).filter(Boolean);\n\n const parsedFields = fields.map((field) => {\n const desc = field.startsWith('-');\n const key = desc ? field.slice(1) : field;\n return { key, desc };\n });\n\n return (a: T, b: T) => {\n for (const { key, desc } of parsedFields) {\n const aVal = a[key];\n const bVal = b[key];\n\n let result: number;\n\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n result = aVal.localeCompare(bVal);\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n result = aVal - bVal;\n } else {\n result = String(aVal ?? '').localeCompare(String(bVal ?? ''));\n }\n\n if (result !== 0) return desc ? -result : result;\n }\n return 0;\n };\n}\n"],"mappings":"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","names":["result","carry"]}
|
|
@@ -4,16 +4,16 @@ import { createProjectAction } from "../actions/create-project.action";
|
|
|
4
4
|
import { withAction } from "../../../utils/withAction";
|
|
5
5
|
import { useAuthQueryKey } from "../../../hooks/useAuthQueryKey";
|
|
6
6
|
import { PROJECTS_BASE_KEY } from "./list-projects.hook";
|
|
7
|
-
import {
|
|
8
|
-
function
|
|
7
|
+
import { buildCompareFn, insertIntoPaginatedCache } from "../../../infra/utils/array";
|
|
8
|
+
function extractQueryParams(query) {
|
|
9
9
|
const key = query.queryKey;
|
|
10
10
|
for (let i = key.length - 1; i >= 0; i--) {
|
|
11
11
|
const segment = key[i];
|
|
12
|
-
if (segment && typeof segment === "object"
|
|
13
|
-
return segment
|
|
12
|
+
if (segment !== null && typeof segment === "object") {
|
|
13
|
+
return segment;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
return
|
|
16
|
+
return {};
|
|
17
17
|
}
|
|
18
18
|
function useCreateProject() {
|
|
19
19
|
const queryClient = useQueryClient();
|
|
@@ -23,42 +23,65 @@ function useCreateProject() {
|
|
|
23
23
|
onSuccess: (newProject) => {
|
|
24
24
|
const cache = queryClient.getQueryCache();
|
|
25
25
|
const queries = cache.findAll({ queryKey: projectsKey });
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
26
|
+
const infiniteQueries = queries.filter((q) => q.queryKey.includes("infinite"));
|
|
27
|
+
for (const query of infiniteQueries) {
|
|
28
|
+
const { sort } = extractQueryParams(query);
|
|
29
|
+
const compareFn = sort ? buildCompareFn(sort) : void 0;
|
|
30
|
+
queryClient.setQueryData(query.queryKey, (old) => {
|
|
31
|
+
if (!old?.pages.length) return old;
|
|
32
|
+
const pageSize = old.pages[0].data.length || 20;
|
|
33
|
+
const newPages = insertIntoPaginatedCache({
|
|
34
|
+
pages: old.pages,
|
|
35
|
+
pageNumbers: old.pages.map((_, i) => i + 1),
|
|
36
|
+
newItem: newProject,
|
|
37
|
+
pageSize,
|
|
38
|
+
compareFn
|
|
39
|
+
});
|
|
40
|
+
return { ...old, pages: newPages.map((p, i) => ({ ...old.pages[i], ...p })) };
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const paginatedQueries = queries.filter((q) => !q.queryKey.includes("infinite"));
|
|
44
|
+
const groups = /* @__PURE__ */ new Map();
|
|
45
|
+
for (const query of paginatedQueries) {
|
|
46
|
+
const params = extractQueryParams(query);
|
|
47
|
+
const { page: _page, ...rest } = params;
|
|
48
|
+
void _page;
|
|
49
|
+
const signature = JSON.stringify(rest);
|
|
50
|
+
const existing = groups.get(signature);
|
|
51
|
+
if (existing) {
|
|
52
|
+
existing.queries.push(query);
|
|
48
53
|
} else {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
groups.set(signature, { queries: [query], sort: params.sort });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const { queries: groupQueries, sort } of groups.values()) {
|
|
58
|
+
const compareFn = sort ? buildCompareFn(sort) : void 0;
|
|
59
|
+
const sortedByPage = groupQueries.map((q) => ({ query: q, page: extractQueryParams(q).page ?? 1 })).sort((a, b) => a.page - b.page);
|
|
60
|
+
const pages = [];
|
|
61
|
+
const pageNumbers = [];
|
|
62
|
+
for (const { query, page } of sortedByPage) {
|
|
63
|
+
const data = queryClient.getQueryData(query.queryKey);
|
|
64
|
+
if (data) {
|
|
65
|
+
pages.push(data);
|
|
66
|
+
pageNumbers.push(page);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!pages.length) continue;
|
|
70
|
+
const pageSize = pages[0].data.length || 20;
|
|
71
|
+
const newPages = insertIntoPaginatedCache({
|
|
72
|
+
pages,
|
|
73
|
+
pageNumbers,
|
|
74
|
+
newItem: newProject,
|
|
75
|
+
pageSize,
|
|
76
|
+
compareFn
|
|
77
|
+
});
|
|
78
|
+
for (let i = 0; i < sortedByPage.length; i++) {
|
|
79
|
+
if (newPages[i] !== pages[i]) {
|
|
80
|
+
queryClient.setQueryData(sortedByPage[i].query.queryKey, {
|
|
81
|
+
...pages[i],
|
|
82
|
+
...newPages[i]
|
|
83
|
+
});
|
|
84
|
+
}
|
|
62
85
|
}
|
|
63
86
|
}
|
|
64
87
|
queryClient.invalidateQueries({ queryKey: projectsKey });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/projects/hooks/create-project.hook.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQueryClient, InfiniteData, Query } from '@tanstack/react-query';\nimport { createProjectAction } from '../actions/create-project.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\nimport { PROJECTS_BASE_KEY } from './list-projects.hook';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/projects/hooks/create-project.hook.ts"],"sourcesContent":["'use client';\n\nimport { useMutation, useQueryClient, InfiniteData, Query } from '@tanstack/react-query';\nimport { createProjectAction } from '../actions/create-project.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\nimport { PROJECTS_BASE_KEY } from './list-projects.hook';\nimport { buildCompareFn, insertIntoPaginatedCache } from '../../../infra/utils/array';\nimport type { CreateProjectRequest, Project, ProjectsPage } from '../types';\n\ntype QueryParams = { sort?: string; page?: number; [key: string]: unknown };\n\nfunction extractQueryParams(query: Query): QueryParams {\n const key = query.queryKey;\n for (let i = key.length - 1; i >= 0; i--) {\n const segment = key[i];\n if (segment !== null && typeof segment === 'object') {\n return segment as QueryParams;\n }\n }\n return {};\n}\n\nexport function useCreateProject() {\n const queryClient = useQueryClient();\n const projectsKey = useAuthQueryKey([...PROJECTS_BASE_KEY]);\n\n return useMutation({\n mutationFn: (data: CreateProjectRequest) =>\n withAction(createProjectAction)(data),\n\n onSuccess: (newProject: Project) => {\n const cache = queryClient.getQueryCache();\n const queries = cache.findAll({ queryKey: projectsKey });\n\n // 1) Caches infinite: todas as páginas vivem no mesmo queryData\n const infiniteQueries = queries.filter((q) => q.queryKey.includes('infinite'));\n\n for (const query of infiniteQueries) {\n const { sort } = extractQueryParams(query);\n const compareFn = sort ? buildCompareFn<Project>(sort) : undefined;\n\n queryClient.setQueryData<InfiniteData<ProjectsPage>>(query.queryKey, (old) => {\n if (!old?.pages.length) return old;\n\n const pageSize = old.pages[0].data.length || 20;\n const newPages = insertIntoPaginatedCache({\n pages: old.pages,\n pageNumbers: old.pages.map((_, i) => i + 1),\n newItem: newProject,\n pageSize,\n compareFn,\n });\n\n return { ...old, pages: newPages.map((p, i) => ({ ...old.pages[i], ...p })) };\n });\n }\n\n // 2) Caches paginados: agrupa queries do mesmo \"sort\" e trata como conjunto\n const paginatedQueries = queries.filter((q) => !q.queryKey.includes('infinite'));\n\n // Agrupa por assinatura dos params (exceto page)\n const groups = new Map<string, { queries: Query[]; sort?: string }>();\n for (const query of paginatedQueries) {\n const params = extractQueryParams(query);\n const { page: _page, ...rest } = params;\n void _page;\n const signature = JSON.stringify(rest);\n const existing = groups.get(signature);\n if (existing) {\n existing.queries.push(query);\n } else {\n groups.set(signature, { queries: [query], sort: params.sort });\n }\n }\n\n for (const { queries: groupQueries, sort } of groups.values()) {\n const compareFn = sort ? buildCompareFn<Project>(sort) : undefined;\n\n // Ordena por número de página\n const sortedByPage = groupQueries\n .map((q) => ({ query: q, page: extractQueryParams(q).page ?? 1 }))\n .sort((a, b) => a.page - b.page);\n\n // Monta as páginas na ordem\n const pages: ProjectsPage[] = [];\n const pageNumbers: number[] = [];\n for (const { query, page } of sortedByPage) {\n const data = queryClient.getQueryData<ProjectsPage>(query.queryKey);\n if (data) {\n pages.push(data);\n pageNumbers.push(page);\n }\n }\n if (!pages.length) continue;\n\n const pageSize = pages[0].data.length || 20;\n const newPages = insertIntoPaginatedCache({\n pages,\n pageNumbers,\n newItem: newProject,\n pageSize,\n compareFn,\n });\n\n // Grava de volta cada página que mudou (referência diferente)\n for (let i = 0; i < sortedByPage.length; i++) {\n if (newPages[i] !== pages[i]) {\n queryClient.setQueryData<ProjectsPage>(sortedByPage[i].query.queryKey, {\n ...pages[i],\n ...newPages[i],\n });\n }\n }\n }\n\n queryClient.invalidateQueries({ queryKey: projectsKey });\n },\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/infra/utils/array.ts
CHANGED
|
@@ -12,6 +12,119 @@ export function insertSorted<T>(
|
|
|
12
12
|
return [...data.slice(0, index), newItem, ...data.slice(index)];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface PaginatedPageCache<T> {
|
|
16
|
+
data: T[];
|
|
17
|
+
total: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface InsertIntoPaginatedCacheParams<T> {
|
|
21
|
+
/** Páginas atuais do cache, ordenadas por número de página (1..N). */
|
|
22
|
+
pages: PaginatedPageCache<T>[];
|
|
23
|
+
/** Números das páginas correspondentes (mesmo tamanho de `pages`). */
|
|
24
|
+
pageNumbers: number[];
|
|
25
|
+
/** Novo item a inserir. */
|
|
26
|
+
newItem: T;
|
|
27
|
+
/** Tamanho fixo de cada página. */
|
|
28
|
+
pageSize: number;
|
|
29
|
+
/**
|
|
30
|
+
* Função de comparação que mantém a ordem.
|
|
31
|
+
* Se não fornecida, insere no topo da página 1 (sem reordenar).
|
|
32
|
+
*/
|
|
33
|
+
compareFn?: (a: T, b: T) => number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Insere um item em um conjunto de páginas paginadas mantendo ordenação.
|
|
38
|
+
*
|
|
39
|
+
* Quando `compareFn` é fornecida, descobre em qual página o item deveria
|
|
40
|
+
* cair (comparando com o último item de cada página). Insere na posição
|
|
41
|
+
* correta e empurra o último item da página para a próxima, propagando
|
|
42
|
+
* o overflow até a última página disponível.
|
|
43
|
+
*
|
|
44
|
+
* Páginas não-afetadas retornam a mesma referência.
|
|
45
|
+
*/
|
|
46
|
+
export function insertIntoPaginatedCache<T>({
|
|
47
|
+
pages,
|
|
48
|
+
pageNumbers,
|
|
49
|
+
newItem,
|
|
50
|
+
pageSize,
|
|
51
|
+
compareFn,
|
|
52
|
+
}: InsertIntoPaginatedCacheParams<T>): PaginatedPageCache<T>[] {
|
|
53
|
+
if (!pages.length) return pages;
|
|
54
|
+
|
|
55
|
+
// Sem sort: insere no topo da página 1 e propaga overflow
|
|
56
|
+
if (!compareFn) {
|
|
57
|
+
// Só atualiza se a página 1 estiver no cache
|
|
58
|
+
const firstIdx = pageNumbers.indexOf(1);
|
|
59
|
+
if (firstIdx === -1) return pages;
|
|
60
|
+
|
|
61
|
+
const result: PaginatedPageCache<T>[] = pages.slice();
|
|
62
|
+
let carry: T | null = newItem;
|
|
63
|
+
for (let i = firstIdx; i < result.length && carry !== null; i++) {
|
|
64
|
+
const current = result[i];
|
|
65
|
+
const nextData: T[] = [carry, ...current.data];
|
|
66
|
+
const overflow: T | null =
|
|
67
|
+
nextData.length > pageSize ? nextData[nextData.length - 1] : null;
|
|
68
|
+
result[i] = {
|
|
69
|
+
...current,
|
|
70
|
+
data: overflow !== null ? nextData.slice(0, pageSize) : nextData,
|
|
71
|
+
total: current.total + 1,
|
|
72
|
+
};
|
|
73
|
+
carry = overflow;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Descobre em qual página o item cai
|
|
79
|
+
let targetIdx = -1;
|
|
80
|
+
for (let i = 0; i < pages.length; i++) {
|
|
81
|
+
const page = pages[i];
|
|
82
|
+
if (!page.data.length) continue;
|
|
83
|
+
const last = page.data[page.data.length - 1];
|
|
84
|
+
// Se newItem vem antes (ou igual) ao último item desta página, cai aqui
|
|
85
|
+
if (compareFn(newItem, last) <= 0) {
|
|
86
|
+
targetIdx = i;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Não coube em nenhuma página com itens — tenta a última página se for incompleta
|
|
92
|
+
if (targetIdx === -1) {
|
|
93
|
+
const lastIdx = pages.length - 1;
|
|
94
|
+
const lastPage = pages[lastIdx];
|
|
95
|
+
if (lastPage.data.length < pageSize) {
|
|
96
|
+
targetIdx = lastIdx;
|
|
97
|
+
} else {
|
|
98
|
+
// Não cai em nenhuma página carregada — apenas incrementa total
|
|
99
|
+
return pages.map((p) => ({ ...p, total: p.total + 1 }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Insere no target e propaga overflow para as páginas seguintes
|
|
104
|
+
const result: PaginatedPageCache<T>[] = pages.slice();
|
|
105
|
+
let carry: T | null = newItem;
|
|
106
|
+
|
|
107
|
+
for (let i = targetIdx; i < result.length && carry !== null; i++) {
|
|
108
|
+
const current = result[i];
|
|
109
|
+
const withInserted: T[] = insertSorted(current.data, carry, compareFn);
|
|
110
|
+
const overflow: T | null =
|
|
111
|
+
withInserted.length > pageSize ? withInserted[withInserted.length - 1] : null;
|
|
112
|
+
result[i] = {
|
|
113
|
+
...current,
|
|
114
|
+
data: overflow !== null ? withInserted.slice(0, pageSize) : withInserted,
|
|
115
|
+
total: current.total + 1,
|
|
116
|
+
};
|
|
117
|
+
carry = overflow;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Incrementa o total nas páginas anteriores ao target (não mudaram mas o total global cresceu)
|
|
121
|
+
for (let i = 0; i < targetIdx; i++) {
|
|
122
|
+
result[i] = { ...result[i], total: result[i].total + 1 };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
15
128
|
/**
|
|
16
129
|
* Cria uma função de comparação a partir de uma string de sort da API.
|
|
17
130
|
* Suporta múltiplos campos separados por vírgula e prefixo `-` para desc.
|
|
@@ -5,18 +5,20 @@ import { createProjectAction } from '../actions/create-project.action';
|
|
|
5
5
|
import { withAction } from '../../../utils/withAction';
|
|
6
6
|
import { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';
|
|
7
7
|
import { PROJECTS_BASE_KEY } from './list-projects.hook';
|
|
8
|
-
import {
|
|
8
|
+
import { buildCompareFn, insertIntoPaginatedCache } from '../../../infra/utils/array';
|
|
9
9
|
import type { CreateProjectRequest, Project, ProjectsPage } from '../types';
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
type QueryParams = { sort?: string; page?: number; [key: string]: unknown };
|
|
12
|
+
|
|
13
|
+
function extractQueryParams(query: Query): QueryParams {
|
|
12
14
|
const key = query.queryKey;
|
|
13
15
|
for (let i = key.length - 1; i >= 0; i--) {
|
|
14
16
|
const segment = key[i];
|
|
15
|
-
if (segment && typeof segment === 'object'
|
|
16
|
-
return
|
|
17
|
+
if (segment !== null && typeof segment === 'object') {
|
|
18
|
+
return segment as QueryParams;
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
|
-
return
|
|
21
|
+
return {};
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export function useCreateProject() {
|
|
@@ -31,54 +33,84 @@ export function useCreateProject() {
|
|
|
31
33
|
const cache = queryClient.getQueryCache();
|
|
32
34
|
const queries = cache.findAll({ queryKey: projectsKey });
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
36
|
+
// 1) Caches infinite: todas as páginas vivem no mesmo queryData
|
|
37
|
+
const infiniteQueries = queries.filter((q) => q.queryKey.includes('infinite'));
|
|
38
|
+
|
|
39
|
+
for (const query of infiniteQueries) {
|
|
40
|
+
const { sort } = extractQueryParams(query);
|
|
41
|
+
const compareFn = sort ? buildCompareFn<Project>(sort) : undefined;
|
|
42
|
+
|
|
43
|
+
queryClient.setQueryData<InfiniteData<ProjectsPage>>(query.queryKey, (old) => {
|
|
44
|
+
if (!old?.pages.length) return old;
|
|
45
|
+
|
|
46
|
+
const pageSize = old.pages[0].data.length || 20;
|
|
47
|
+
const newPages = insertIntoPaginatedCache({
|
|
48
|
+
pages: old.pages,
|
|
49
|
+
pageNumbers: old.pages.map((_, i) => i + 1),
|
|
50
|
+
newItem: newProject,
|
|
51
|
+
pageSize,
|
|
52
|
+
compareFn,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return { ...old, pages: newPages.map((p, i) => ({ ...old.pages[i], ...p })) };
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2) Caches paginados: agrupa queries do mesmo "sort" e trata como conjunto
|
|
60
|
+
const paginatedQueries = queries.filter((q) => !q.queryKey.includes('infinite'));
|
|
61
|
+
|
|
62
|
+
// Agrupa por assinatura dos params (exceto page)
|
|
63
|
+
const groups = new Map<string, { queries: Query[]; sort?: string }>();
|
|
64
|
+
for (const query of paginatedQueries) {
|
|
65
|
+
const params = extractQueryParams(query);
|
|
66
|
+
const { page: _page, ...rest } = params;
|
|
67
|
+
void _page;
|
|
68
|
+
const signature = JSON.stringify(rest);
|
|
69
|
+
const existing = groups.get(signature);
|
|
70
|
+
if (existing) {
|
|
71
|
+
existing.queries.push(query);
|
|
63
72
|
} else {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
73
|
+
groups.set(signature, { queries: [query], sort: params.sort });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const { queries: groupQueries, sort } of groups.values()) {
|
|
78
|
+
const compareFn = sort ? buildCompareFn<Project>(sort) : undefined;
|
|
79
|
+
|
|
80
|
+
// Ordena por número de página
|
|
81
|
+
const sortedByPage = groupQueries
|
|
82
|
+
.map((q) => ({ query: q, page: extractQueryParams(q).page ?? 1 }))
|
|
83
|
+
.sort((a, b) => a.page - b.page);
|
|
84
|
+
|
|
85
|
+
// Monta as páginas na ordem
|
|
86
|
+
const pages: ProjectsPage[] = [];
|
|
87
|
+
const pageNumbers: number[] = [];
|
|
88
|
+
for (const { query, page } of sortedByPage) {
|
|
89
|
+
const data = queryClient.getQueryData<ProjectsPage>(query.queryKey);
|
|
90
|
+
if (data) {
|
|
91
|
+
pages.push(data);
|
|
92
|
+
pageNumbers.push(page);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!pages.length) continue;
|
|
96
|
+
|
|
97
|
+
const pageSize = pages[0].data.length || 20;
|
|
98
|
+
const newPages = insertIntoPaginatedCache({
|
|
99
|
+
pages,
|
|
100
|
+
pageNumbers,
|
|
101
|
+
newItem: newProject,
|
|
102
|
+
pageSize,
|
|
103
|
+
compareFn,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Grava de volta cada página que mudou (referência diferente)
|
|
107
|
+
for (let i = 0; i < sortedByPage.length; i++) {
|
|
108
|
+
if (newPages[i] !== pages[i]) {
|
|
109
|
+
queryClient.setQueryData<ProjectsPage>(sortedByPage[i].query.queryKey, {
|
|
110
|
+
...pages[i],
|
|
111
|
+
...newPages[i],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
82
114
|
}
|
|
83
115
|
}
|
|
84
116
|
|