Skip to content

Commit

Permalink
Display resources in sidebar-list with 'isPresentIn' relation
Browse files Browse the repository at this point in the history
constrain logic for db query includes 'isPresentIn:contain' and is changed from AND to OR if document.category is 'Profile' at MoveInto action
  • Loading branch information
maxhaibt committed Jan 29, 2024
1 parent ffefdae commit e220770
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 83 deletions.
23 changes: 11 additions & 12 deletions core/src/datastore/datastore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ export class Datastore {
* @returns {Promise<IdaiFieldFindResult>} result object
* @throws [GENERIC_ERROR (, cause: any)] - in case of error, optionally including a cause
*/
public find: Datastore.Find = async (query: Query): Promise<Datastore.FindResult> => {

const { ids } = this.findIds(query);
public find: Datastore.Find = async (query: Query, logic?: 'AND' | 'OR'): Promise<Datastore.FindResult> => {
const effectiveLogic = logic || 'AND';
const { ids } = this.findIds(query, effectiveLogic);
const { documents, totalCount } = await this.getDocumentsForIds(ids, query.limit, query.offset);

return {
Expand All @@ -240,17 +240,17 @@ export class Datastore {
* @param query
* @returns
*/
public findIds: Datastore.FindIds = (query: Query): Datastore.FindIdsResult => {

const orderedResults: string[] = this.getIds(query);

public findIds: Datastore.FindIds = (query: Query, logic: 'AND' | 'OR' = 'AND'): Datastore.FindIdsResult => {
const orderedResults: string[] = this.getIds(query, logic); // Pass the logic parameter

return {
ids: orderedResults,
totalCount: orderedResults.length
};
}



/**
* Fetches a specific revision directly from the underlying datastore layer.
* Bypasses the cache and alway returns a new instance.
Expand All @@ -272,10 +272,9 @@ export class Datastore {
* If two or more documents have the same last modified date, their sort order is unspecified.
* The modified date is taken from document.modified[document.modified.length-1].date
*/
private getIds(query: Query): string[] {

private getIds(query: Query, logic: 'AND' | 'OR'): string[] {
try {
return this.indexFacade.find(query);
return this.indexFacade.find(query, logic); // Pass the logic parameter to IndexFacade's find method
} catch (err) {
throw [DatastoreErrors.GENERIC_ERROR, err];
}
Expand Down Expand Up @@ -381,9 +380,9 @@ export namespace Datastore {

export type Get = (id: string, options?: { skipCache?: boolean, conflicts?: boolean }) => Promise<Document>;

export type Find = (query: Query) => Promise<FindResult>;
export type Find = (query: Query, logic?: 'AND'|'OR') => Promise<FindResult>;

export type FindIds = (query: Query) => FindIdsResult;
export type FindIds = (query: Query, logic?: 'AND'|'OR') => FindIdsResult;

export type Update = (document: Document, squashRevisionsIds?: string[]) => Promise<Document>;

Expand Down
12 changes: 9 additions & 3 deletions core/src/index/index-facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,26 @@ export class IndexFacade {

private observers: Array<Observer<Document>> = [];
private indexItems: { [resourceId: string]: IndexItem } = {};
private defaultLogic: 'AND' | 'OR' = 'OR';


constructor(private constraintIndex: ConstraintIndex,
private fulltextIndex: FulltextIndex,
private projectConfiguration: ProjectConfiguration,
private showWarnings: boolean) {}
private showWarnings: boolean,
defaultLogic: 'AND' | 'OR' = 'OR'
) {
this.defaultLogic = defaultLogic;
}


public changesNotifications = (): Observable<Document|undefined> => ObserverUtil.register(this.observers);


public find(query: Query): Array<string /*resourceId*/> {
public find(query: Query, logic: 'AND' | 'OR' = this.defaultLogic): Array<string /*resourceId*/> {

const queryResult: Array<Resource.Id> = performQuery(query, this.constraintIndex, this.fulltextIndex);
console.log('find', query, logic)
const queryResult: Array<Resource.Id> = performQuery(query, this.constraintIndex, this.fulltextIndex, logic);
return this.getSortedResult(query, queryResult);
}

Expand Down
39 changes: 26 additions & 13 deletions core/src/index/perform-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import { ResultSets } from './result-sets';
*/
export function performQuery(query: Query,
constraintIndex: ConstraintIndex,
fulltextIndex: FulltextIndex): Array<Resource.Id> {
fulltextIndex: FulltextIndex,
logic: 'AND' | 'OR' = 'OR'): Array<Resource.Id> {

let resultSets = performConstraints(
constraintIndex,
query.constraints ? query.constraints : {}
query.constraints ? query.constraints : {},
logic
);

resultSets = ResultSets.containsOnlyEmptyAddSets(resultSets)
Expand All @@ -40,21 +42,32 @@ function performFulltext(fulltextIndex: FulltextIndex,
return resultSets;
}

//This seems to be the place where the query is actually performed upon the pouchdb.TOMORROW

function performConstraints(constraintIndex: ConstraintIndex,
constraints: { [name: string]: Constraint|string|string[] }): ResultSets<Resource.Id> {

return Object.keys(constraints)
.reduce((resultSets, name: string) => {
constraints: { [name: string]: Constraint|string|string[] },
logic: 'AND' | 'OR' = 'OR'): ResultSets<Resource.Id> {
let resultSets = ResultSets.make<Resource.Id>();
if (logic === 'OR') {

let orSets: Array<Array<Resource.Id>> = [];
for (let name in constraints) {
const { subtract, value, searchRecursively } = Constraint.convert(constraints[name]);

const get = !searchRecursively
? ConstraintIndex.get
: ConstraintIndex.getWithDescendants;

const get = !searchRecursively ? ConstraintIndex.get : ConstraintIndex.getWithDescendants;
const indexItemIds = get(constraintIndex, name, value);
orSets.push(indexItemIds);
}
resultSets.addSets.push(ResultSets.unionSets(orSets));
} else {
// Existing AND logic
Object.keys(constraints).forEach(name => {
const { subtract, value, searchRecursively } = Constraint.convert(constraints[name]);
const get = !searchRecursively ? ConstraintIndex.get : ConstraintIndex.getWithDescendants;
const indexItemIds = get(constraintIndex, name, value);

ResultSets.combine(resultSets, indexItemIds, subtract);
return resultSets;
}, ResultSets.make<Resource.Id>());
});
}

return resultSets;
}
4 changes: 4 additions & 0 deletions core/src/index/result-sets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ export module ResultSets {

return union(resultSets.addSets);
}

export function unionSets<T>(resultSets: Array<Array<T>>): Array<T> {
return tsfun.union(resultSets);
}
}
104 changes: 63 additions & 41 deletions desktop/src/app/components/resources/view/documents-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,34 +104,40 @@ export class DocumentsManager {
}


public async moveInto(document: FieldDocument|string|undefined, resetFiltersAndSelection: boolean = false,
rebuildNavigationPath: boolean = false) {

try {
if (isString(document)) {
document = (await this.datastore.get(document)) as FieldDocument;
} else if (document) {
await this.datastore.get(document.resource.id);
}
} catch (errWithParams) {
throw errWithParams; // Throw error if the resource has been deleted from remote
public async moveInto(document: FieldDocument|string|undefined, resetFiltersAndSelection: boolean = false,
rebuildNavigationPath: boolean = false) {

let documentCategory: string | undefined;
try {
if (isString(document)) {
document = (await this.datastore.get(document)) as FieldDocument;
documentCategory = document.resource.category;
} else if (document) {
const fetchedDocument = (await this.datastore.get(document.resource.id)) as FieldDocument;
documentCategory = fetchedDocument.resource.category;
}
} catch (errWithParams) {
throw errWithParams; // Throw error if the resource has been deleted from remote
}

if (rebuildNavigationPath && document) {
await this.resourcesStateManager.updateNavigationPathForDocument(document, true);
}
if (rebuildNavigationPath && document) {
await this.resourcesStateManager.updateNavigationPathForDocument(document, true);
}

await this.resourcesStateManager.moveInto(document);
await this.resourcesStateManager.moveInto(document);

if (resetFiltersAndSelection) {
await this.setCategoryFilters([], false);
await this.setQueryString('', false);
await this.deselect();
await this.populateDocumentList();
} else {
await this.populateAndDeselectIfNecessary();
}
const logic = documentCategory === 'Profile' ? 'OR' : 'AND';

if (resetFiltersAndSelection) {
await this.setCategoryFilters([], false);
await this.setQueryString('', false);
await this.deselect();
await this.populateDocumentList(true, logic); // Pass the OR logic flag
} else {
await this.populateAndDeselectIfNecessary(); // Pass the OR logic flag
}
}



public deselect() {
Expand Down Expand Up @@ -197,7 +203,7 @@ export class DocumentsManager {
}


public async populateDocumentList(reset: boolean = true) {
public async populateDocumentList(reset: boolean = true, logic?: 'AND' | 'OR') {

this.populateInProgress = true;
if (this.loading) this.loading.start();
Expand All @@ -211,7 +217,8 @@ export class DocumentsManager {

this.currentQueryId = new Date().toISOString();
const queryId = this.currentQueryId;
const result = await this.createUpdatedDocumentList();
const effectiveLogic = logic || 'AND';
const result = await this.createUpdatedDocumentList(effectiveLogic);

await this.updateChildrenCountMap(result.documents as Array<FieldDocument>);

Expand All @@ -222,31 +229,35 @@ export class DocumentsManager {
}

this.documents = result.documents as Array<FieldDocument>;
console.log('This is',this.documents)
this.totalDocumentCount = result.totalCount;

this.populateInProgress = false;
ObserverUtil.notify(this.populateDocumentsObservers, this.documents);
}


public async createUpdatedDocumentList(): Promise<Datastore.FindResult> {

public async createUpdatedDocumentList(logic?: 'AND' | 'OR'): Promise<Datastore.FindResult> {
const isRecordedInTarget = this.makeIsRecordedInTarget();
if (!isRecordedInTarget && !this.resourcesStateManager.isInSpecialView()) {
return { documents: [], ids: [], totalCount: 0 };
}


const operationId: string|undefined = this.resourcesStateManager.isInSpecialView()
? undefined
: this.resourcesStateManager.get().view;


const query = DocumentsManager.buildQuery(
operationId,
this.resourcesStateManager,
this.getAllowedTypeNames()
);

return (await this.fetchDocuments(query));
console.log(query)
const effectiveLogic = logic || 'AND';
return (await this.fetchDocuments(query, effectiveLogic));
}


Expand Down Expand Up @@ -345,10 +356,10 @@ export class DocumentsManager {
}


private async fetchDocuments(query: Query): Promise<Datastore.FindResult> {
private async fetchDocuments(query: Query, logic: 'AND' | 'OR' = 'AND'): Promise<Datastore.FindResult> {

try {
return await this.datastore.find(query);
return await this.datastore.find(query, logic);
} catch (errWithParams) {
DocumentsManager.handleFindErr(errWithParams, query);
return { documents: [], ids: [], totalCount: 0 };
Expand All @@ -364,14 +375,15 @@ export class DocumentsManager {
const state = resourcesStateManager.get();
const categoryFilters = ResourcesState.getCategoryFilters(state);
const customConstraints = ResourcesState.getCustomConstraints(state);

const currentView = state.view;
return {
q: ResourcesState.getQueryString(state),
constraints: DocumentsManager.buildConstraints(
customConstraints,
operationId,
ResourcesState.getNavigationPath(state).selectedSegmentId,
extendedSearchMode
extendedSearchMode,
currentView
),
categories: (categoryFilters.length > 0)
? categoryFilters
Expand All @@ -384,22 +396,32 @@ export class DocumentsManager {


private static buildConstraints(customConstraints: Constraints,
operationId: string|undefined,
liesWithinId: string|undefined,
isInExtendedSearchMode: boolean): Constraints {
operationId: string|undefined,
liesWithinId: string|undefined,
isInExtendedSearchMode: boolean,
currentView: string): Constraints {

const constraints = clone(customConstraints);

if (!isInExtendedSearchMode) {
if (liesWithinId) constraints[CHILDOF_CONTAIN] = liesWithinId;
else if (operationId) constraints[CHILDOF_CONTAIN] = operationId as any;
else constraints[CHILDOF_EXIST] = UNKNOWN;
if (!isInExtendedSearchMode) {
if (liesWithinId) {
constraints[CHILDOF_CONTAIN] = liesWithinId ;
constraints['isPresentIn:contain'] = liesWithinId;
}
else if (operationId) {
constraints[CHILDOF_CONTAIN] = operationId as any;
} else {
constraints[CHILDOF_EXIST] = UNKNOWN;
}

} else {
if (operationId) constraints[CHILDOF_CONTAIN] = { value: operationId, searchRecursively: true } as any;
}
return constraints;
}
}




private static handleFindErr(errWithParams: Array<string>, query: Query) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ export class ResourcesStateManager {

public resetForE2E = () => this.resourcesState = ResourcesState.makeDefaults();

public isInSpecialView = () => this.isInOverview() || this.isInTypesManagement();
public isInSpecialView = () => this.isInOverview() || this.isInTypesManagement() || this.isInSideView();

public isInOverview = () => this.resourcesState.view === 'project';

public isInTypesManagement = () => this.resourcesState.view === 'types';

public isInSideView = () => this.resourcesState.view === 'sideview';

public getCurrentOperation = (): FieldDocument|undefined =>
ResourcesState.getCurrentOperation(this.resourcesState);

Expand Down Expand Up @@ -181,6 +183,11 @@ export class ResourcesStateManager {


public async moveInto(document: FieldDocument|undefined) {
console.log('MoveInto called with document:',document);

if (document && document.resource.category === 'Profile') {
console.log('MoveInto sideview, this view:',this.resourcesState.view);
}

const invalidSegment = await NavigationPath.findInvalidSegment(
this.resourcesState.view,
Expand Down
Loading

0 comments on commit e220770

Please sign in to comment.