diff --git a/src/readers/queryService.ts b/src/readers/queryService.ts index be55e4c097f4f9ab81f6d2b216d0d0a339da51ac..06c109b2d1f1a35024f4b78120bb768dc0f8e255 100644 --- a/src/readers/queryService.ts +++ b/src/readers/queryService.ts @@ -24,6 +24,7 @@ import { parseCypherQuery } from "../utils/cypher/queryParser"; import { formatTimeDifference } from "ts-common/src/logger/logger"; import { graphQueryBackend2graphQuery } from "../frontend/statistics"; import { Query2BackendQuery } from "../utils/reactflow/query2backend"; +import { hashDictionary, hashIsEqual } from "../utils/hashing"; export const queryService = async (db: DbConnection, query: string): Promise<GraphQueryResultMetaFromBackend> => { // TODO: only neo4j is supported for now @@ -287,16 +288,13 @@ export const queryServiceReaderDiffCheck = async (type: QueryExecutionTypes) => USER_MANAGEMENT_SERVICE_API ); - // const ssInsight = await getUserSaveStateInsight( - // headers.message.sessionData.userID, - // headers.message.sessionData.saveStateID, - // USER_MANAGEMENT_SERVICE_API - // ); - - const previousQueryResult = { - nodes: [], - edges: [], - }; + const ssInsight = await getUserSaveStateInsight( + headers.message.sessionData.userID, + headers.message.sessionData.saveStateID, + USER_MANAGEMENT_SERVICE_API + ); + // const previousQueryResult = ssInsight.previous_result_hash; + const previousQueryResult = "Get hash from db"; log.debug("Received query request:", ss); @@ -331,21 +329,14 @@ export const queryServiceReaderDiffCheck = async (type: QueryExecutionTypes) => log.debug("Query result!"); log.info(`Query executed in ${formatTimeDifference(Date.now() - startTime)}`); - const queryResult = { + const queryResult = hashDictionary({ nodes: result.nodes.map((node) => node._id), edges: result.edges.map((edge) => edge._id), - }; - - // Compare query results - const nodesDifferent = queryResult.nodes.some((node, index) => node !== previousQueryResult.nodes[index]); - const edgesDifferent = queryResult.edges.some((edge, index) => edge !== previousQueryResult.edges[index]); - - if ( - queryResult.nodes.length !== previousQueryResult.nodes.length || - queryResult.edges.length !== previousQueryResult.edges.length || - nodesDifferent || - edgesDifferent - ) { + }); + + log.info("Comparing hash values from current and previous query"); + + if (previousQueryResult && !hashIsEqual(queryResult, previousQueryResult)) { log.info("Different results, use Dennis code..."); } else { log.info("No difference in result sets"); @@ -356,7 +347,7 @@ export const queryServiceReaderDiffCheck = async (type: QueryExecutionTypes) => headers.message.sessionData.userID, headers.message.sessionData.saveStateID, USER_MANAGEMENT_SERVICE_API, - queryResult + { previous_result_hash: queryResult } ); log.info("Updated node and edge ids in SaveState"); diff --git a/src/utils/hashing/index.ts b/src/utils/hashing/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e6c7941069b5c1391b35a9d34af0ee3f7ecf0dd --- /dev/null +++ b/src/utils/hashing/index.ts @@ -0,0 +1,20 @@ +const FNV_OFFSET_BASIS = 2166136261; + +export const hashDictionary = (dictionary: Record<"nodes" | "edges", string[]>): string => { + // Convert the dictionary into a consistent string format + const jsonString = JSON.stringify(dictionary, Object.keys(dictionary).sort()); + + // FNV-1a hash implementation + let hash = FNV_OFFSET_BASIS; // FNV offset basis + for (let i = 0; i < jsonString.length; i++) { + hash ^= jsonString.charCodeAt(i); + hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); // FNV prime + } + + // Convert hash to a hexadecimal string + return (hash >>> 0).toString(16); // Ensure unsigned integer representation +}; + +export const hashIsEqual = (hash1: string, hash2: string): boolean => { + return hash1 === hash2; +};