Skip to content

Commit

Permalink
feat(search): add title matching for search capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
thesophiaxu committed Apr 16, 2022
1 parent 59159b1 commit d5ba291
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const newTitles = (
await unigraph.getQueries([
`(func: uid(u1, u2, u3, u4, u5, u6)) @filter(NOT eq(_hide, true) AND type(Entity)) @normalize {
uid
_updatedAt: _updatedAt
type { type: <unigraph.id> }
<unigraph.indexes> {
name {
name: <_value.%>
_value { _value { name: <_value.%> } }
}
}
}
var(func: eq(<unigraph.id>, "$/schema/note_block")) {
<~type> {
u1 as uid
}
}
var(func: eq(<unigraph.id>, "$/schema/calendar_event")) {
<~type> {
u2 as uid
}
}
var(func: eq(<unigraph.id>, "$/schema/email_message")) {
<~type> {
u3 as uid
}
}
var(func: eq(<unigraph.id>, "$/schema/todo")) {
<~type> {
u4 as uid
}
}
var(func: eq(<unigraph.id>, "$/schema/contact")) {
<~type> {
u5 as uid
}
}
var(func: eq(<unigraph.id>, "$/schema/tag")) {
<~type> {
u6 as uid
}
}`,
])
)[0];

unigraph.updateClientCache('searchTitles', newTitles);
18 changes: 18 additions & 0 deletions packages/default-packages/unigraph.search/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"displayName": "Unigraph search",
"version": "0.2.9",
"description": "Search commons for Unigraph",
"name": "unigraph.search",
"unigraph": {
"executables": [
{
"id": "initialize-search-cache",
"env": "backend-startup/js",
"src": "executables/initializeSearchCache.js",
"periodic": "* * * * *",
"editable": true,
"name": "Initializes search cache for backend"
}
]
}
}
31 changes: 30 additions & 1 deletion packages/unigraph-dev-backend/src/caches.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Abstract definition for caches

import stringify from 'json-stable-stringify';
import { getCircularReplacer } from 'unigraph-dev-common/lib/utils/utils';
import DgraphClient from './dgraphClient';

export type Cache<T> = {
Expand All @@ -9,4 +11,31 @@ export type Cache<T> = {
cacheType: 'subscription' | 'manual';
/* eslint-disable */ // TODO: Temporarily appease the linter, remember to fix it later
subscribe(listener: Function): any
}
}

export function updateClientCache (states: any, key: string, newValue: any) {
states.clientCaches[key] = newValue;
Object.values(states.connections).forEach((conn: any) => {
conn.send(stringify(
{
type: 'cache_updated',
name: key,
result: newValue,
},
{ replacer: getCircularReplacer() },
),)
})
}

export function initCaches (states: any, conn: any) {
Object.entries(states.clientCaches).forEach(([key, value]: any) => {
conn.send(stringify(
{
type: 'cache_updated',
name: key,
result: value,
},
{ replacer: getCircularReplacer() },
));
});
}
5 changes: 5 additions & 0 deletions packages/unigraph-dev-backend/src/executableManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export function initExecutables(
buildExecutable(el, { ...context, definition: el, params }, unigraph, states)(),
);
}
if (key.startsWith('0x') && el.env === 'backend-startup/js' && !states.finishedStartups[key]) {
states.finishedStartups[key] = true;
buildExecutable(el, { ...context, definition: el, params: {} }, unigraph, states)();
}
});
states.hooks = _.mergeWith({}, states.defaultHooks, newHooks, mergeWithConcatArray);
}
Expand Down Expand Up @@ -187,6 +191,7 @@ const returnSrcFromEnvClientJs: ExecRunner = (src, context, unigraph) => src;

export const environmentRunners = {
'routine/js': runEnvRoutineJs,
'backend-startup/js': runEnvRoutineJs,
'lambda/js': runEnvLambdaJs,
'component/react-jsx': runEnvReactJSX,
'client/js': returnSrcFromEnvClientJs, // TODO: should we just forbid this in backend?
Expand Down
5 changes: 4 additions & 1 deletion packages/unigraph-dev-backend/src/localUnigraphApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { buildExecutable } from './executableManager';
import { callHooks } from './hooks';
import { addNotification } from './notifications';
import { createSubscriptionLocal, createSubscriptionWS, getFragment, resolveSubscriptionUpdate } from './subscriptions';
import { Cache } from './caches';
import { Cache, updateClientCache } from './caches';
import { getQueryString } from './search';

// eslint-disable-next-line import/prefer-default-export
Expand Down Expand Up @@ -740,6 +740,9 @@ export function getLocalUnigraphAPI(
const deleter = (api.deleteItemFromArray as any)(resKeyUid, uids, resUid, [], false);
return deleter;
},
updateClientCache(key: string, newValue: any) {
return updateClientCache(states, key, newValue);
},
};

return api;
Expand Down
78 changes: 9 additions & 69 deletions packages/unigraph-dev-backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import {
UnigraphUpsert,
} from './custom.d';
import { checkOrCreateDefaultDataModel, createSchemaCache } from './datamodelManager';
import { Cache } from './caches';
import { Cache, initCaches, updateClientCache } from './caches';
import {
createSubscriptionLocal,
MsgCallbackFn,
Expand Down Expand Up @@ -207,18 +207,7 @@ export default async function startServer(client: DgraphClient) {
serverStates.executableSchedule,
serverStates,
);
Object.values(connections).forEach((el) =>
el.send(
stringify(
{
type: 'cache_updated',
name: 'schemaMap',
result: serverStates.caches.schemas.data,
},
{ replacer: getCircularReplacer() },
),
),
);
updateClientCache(serverStates, 'schemaMap', serverStates.caches.schemas.data);
},
],
after_object_changed: [
Expand Down Expand Up @@ -285,9 +274,12 @@ export default async function startServer(client: DgraphClient) {
let debounceId: NodeJS.Timeout;

Object.assign(serverStates, {
connections,
clientCaches: {},
caches,
subscriptions: _subscriptions,
dgraphClient,
finishedStartups: {},
hooks,
defaultHooks: hooks,
namespaceMap,
Expand All @@ -302,36 +294,14 @@ export default async function startServer(client: DgraphClient) {
serverStates.runningExecutables.push(defn);
clearTimeout(debounceId);
debounceId = setTimeout(() => {
Object.values(connections).forEach((el) => {
el.send(
stringify(
{
type: 'cache_updated',
name: 'runningExecutables',
result: serverStates.runningExecutables,
},
{ replacer: getCircularReplacer() },
),
);
});
updateClientCache(serverStates, 'runningExecutables', serverStates.runningExecutables);
}, 250);
},
removeRunningExecutable: (id: any) => {
serverStates.runningExecutables = serverStates.runningExecutables.filter((el: any) => el.id !== id);
clearTimeout(debounceId);
debounceId = setTimeout(() => {
Object.values(connections).forEach((el) => {
el.send(
stringify(
{
type: 'cache_updated',
name: 'runningExecutables',
result: serverStates.runningExecutables,
},
{ replacer: getCircularReplacer() },
),
);
});
updateClientCache(serverStates, 'runningExecutables', serverStates.runningExecutables);
}, 250);
},
entityHeadByType: {},
Expand All @@ -346,18 +316,7 @@ export default async function startServer(client: DgraphClient) {
(data) => {
namespaceMap = data[0];
serverStates.namespaceMap = data[0];
Object.values(connections).forEach((el) => {
el.send(
stringify(
{
type: 'cache_updated',
name: 'namespaceMap',
result: data[0],
},
{ replacer: getCircularReplacer() },
),
);
});
updateClientCache(serverStates, 'namespaceMap', data[0]);
},
{
type: 'query',
Expand Down Expand Up @@ -1046,26 +1005,7 @@ export default async function startServer(client: DgraphClient) {
serverStates.leasedUids.push(...(serverStates.clientLeasedUids[connId] || []));
delete serverStates.clientLeasedUids[connId];
});
ws.send(
stringify(
{
type: 'cache_updated',
name: 'namespaceMap',
result: serverStates.namespaceMap,
},
{ replacer: getCircularReplacer() },
),
);
ws.send(
stringify(
{
type: 'cache_updated',
name: 'schemaMap',
result: serverStates.caches['schemas'].data,
},
{ replacer: getCircularReplacer() },
),
);
initCaches(serverStates, ws);
leaseToClient(connId);
ws.send(
stringify(
Expand Down
2 changes: 2 additions & 0 deletions packages/unigraph-dev-backend/src/templates/defaultDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { pkg as calendar } from 'unigraph-dev-common/lib/data/unigraph.calendar.
import { pkg as notes } from 'unigraph-dev-common/lib/data/unigraph.notes.pkg';
import { pkg as contacts } from 'unigraph-dev-common/lib/data/unigraph.contacts.pkg';
import { pkg as home } from 'unigraph-dev-common/lib/data/unigraph.home.pkg';
import { pkg as search } from 'unigraph-dev-common/lib/data/unigraph.search.pkg';

// Userspace packages
import { pkg as onboarding } from 'unigraph-dev-common/lib/data/unigraph.onboarding.pkg';
Expand Down Expand Up @@ -350,6 +351,7 @@ export const defaultPackages = [
execexample,
coreuser,
home,
search,
calendar,
notes,
contacts,
Expand Down
4 changes: 3 additions & 1 deletion packages/unigraph-dev-common/src/api/unigraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,13 @@ export default function unigraph(url: string, browserId: string): Unigraph<WebSo
};
sendEvent(connection, 'get_status', {}, id);
}),
onCacheUpdated: (cache, callback) => {
onCacheUpdated: (cache, callback, currentCache) => {
if (Array.isArray(cacheCallbacks[cache])) {
cacheCallbacks[cache].push(callback);
} else cacheCallbacks[cache] = [callback];
if (currentCache) callback(caches[cache]);
},
getCache: (cache) => caches[cache],
createSchema: (schema) =>
new Promise((resolve, reject) => {
const id = getRandomInt();
Expand Down
11 changes: 10 additions & 1 deletion packages/unigraph-dev-common/src/types/unigraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ export interface Unigraph<TT = WebSocket | undefined> {
getStatus(): Promise<any>;
/** The specified callback will be invoked once initial Unigraph connecton is established. */
onReady?(callback: () => void): void;
onCacheUpdated?(cache: string, callback: (newEl: any) => void): void;
onCacheUpdated?(cache: string, callback: (newEl: any) => void, currentCache?: boolean): void;
getCache?: (cache: string) => any;
/**
* Create a new schema using the json-ts format and add it to cache.
*
Expand Down Expand Up @@ -554,5 +555,13 @@ export interface Unigraph<TT = WebSocket | undefined> {
* @param uids The list of uids that have been synced successfully.
*/
acknowledgeSync(resource: string, key: string, uids: any[]): any;
/**
* Updates client cache with given key and value.
* Clients will be immediately notified of this cache update through websocket.
*
* @param key A string key to identify the cache
* @param newValue Tne new value to set
*/
updateClientCache?(key: string, newValue: any): any;
}
/** End of unigraph interface */ // Don't remove this line - needed for Monaco to work
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const ResultDisplay = ({ el }: any) => {
};

export function InlineSearch() {
const [isFulltext, setIsFulltext] = React.useState(false);
const [ctxMenuState, setCtxMenuState] = React.useState<AppState<Partial<SearchPopupState>>>(
window.unigraph.getState('global/searchPopup'),
);
Expand All @@ -60,6 +61,15 @@ export function InlineSearch() {

const [currentAction, setCurrentAction] = React.useState(0);

const titleSearch = (key: string) => {
const names = (window.unigraph as any).getCache('searchTitles');
const results = (names || []).filter((el: any) => el?.name?.toLowerCase().includes(key?.toLowerCase().trim()));
setSearchResults(
results
.sort((a: any, b: any) => new Date(b._updatedAt || 0).getTime() - new Date(a._updatedAt || 0).getTime())
.slice(0, 100),
);
};
const search = React.useCallback(
_.debounce((key: string) => {
if (key !== undefined && key.length > 1) {
Expand Down Expand Up @@ -103,8 +113,8 @@ export function InlineSearch() {
setSearchResults([]);
setTopResults([]);
} else setCurrentAction(0);
search(state.search as string);
}, [state]);
(isFulltext ? search : titleSearch)(state.search as string);
}, [state.show, state.search, isFulltext]);

const [actionItems, setActionItems] = React.useState<any[]>([]);
React.useEffect(() => {
Expand Down

0 comments on commit d5ba291

Please sign in to comment.