Skip to content

Commit

Permalink
Allow passing filters to resource.rgetCollection
Browse files Browse the repository at this point in the history
  • Loading branch information
melton-jason committed Oct 23, 2024
1 parent 075614d commit c6c9d8c
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import type { IR, RA } from '../../utils/types';
import type { BusinessRuleManager } from './businessRules';
import { CollectionFetchFilters } from './collection';
import type {
AnySchema,
CommonFields,
Expand Down Expand Up @@ -113,7 +114,8 @@ export type SpecifyResource<SCHEMA extends AnySchema> = {
VALUE extends (SCHEMA['toManyDependent'] &
SCHEMA['toManyIndependent'])[FIELD_NAME]
>(
fieldName: FIELD_NAME
fieldName: FIELD_NAME,
filters?: CollectionFetchFilters<VALUE[number]>
): Promise<Collection<VALUE[number]>>;
set<
FIELD_NAME extends
Expand Down
27 changes: 17 additions & 10 deletions specifyweb/frontend/js_src/lib/components/DataModel/resourceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { softFail } from '../Errors/Crash';
import { relationshipIsToMany } from '../WbPlanView/mappingHelpers';
import { Backbone } from './backbone';
import { attachBusinessRules } from './businessRules';
import { CollectionFetchFilters } from './collection';
import { isRelationshipCollection } from './collectionApi';
import { backboneFieldSeparator } from './helpers';
import type {
Expand Down Expand Up @@ -606,8 +607,12 @@ export const ResourceBase = Backbone.Model.extend({
);
},
// Duplicate definition for purposes of better typing:
async rgetCollection(fieldName) {
return this.getRelated(fieldName, { prePop: true });
async rgetCollection(fieldName, rawOptions) {
const options = {
...rawOptions,
prePop: true,
};
return this.getRelated(fieldName, options);
},
async getRelated(fieldName, options) {
options ||= {
Expand Down Expand Up @@ -695,8 +700,7 @@ export const ResourceBase = Backbone.Model.extend({
console.warn('expected dependent resource to be in cache');
this.storeDependent(field, toOne);
} else {
const fetchedToOne = toOne.isNew() ? toOne : toOne;
this.storeIndependent(field, fetchedToOne);
this.storeIndependent(field, toOne);
}
}
// If we want a field within the related resource then recur
Expand All @@ -708,8 +712,8 @@ export const ResourceBase = Backbone.Model.extend({
}

return field.isDependent()
? this.getDependentToMany(field)
: this.getIndependentToMany(field);
? this.getDependentToMany(field, options)
: this.getIndependentToMany(field, options);
}
case 'zero-to-one': {
/*
Expand Down Expand Up @@ -752,7 +756,8 @@ export const ResourceBase = Backbone.Model.extend({
}
},
async getDependentToMany(
field: Relationship
field: Relationship,
filters
): Promise<Collection<AnySchema>> {
assert(field.isDependent());

Expand All @@ -776,7 +781,7 @@ export const ResourceBase = Backbone.Model.extend({
? this.isNew()
? new relatedTable.DependentCollection(collectionOptions, [])
: await new relatedTable.ToOneCollection(collectionOptions)
.fetch({ limit: 0 })
.fetch({ ...filters, limit: 0 })
.then(
(collection) =>
new relatedTable.DependentCollection(
Expand All @@ -786,13 +791,14 @@ export const ResourceBase = Backbone.Model.extend({
)
: existingToMany;

return collection.fetch({ limit: 0 }).then((collection) => {
return collection.fetch({ ...filters, limit: 0 }).then((collection) => {
self.storeDependent(field, collection);
return collection;
});
},
async getIndependentToMany(
field: Relationship
field: Relationship,
filters
): Promise<Collection<AnySchema>> {
assert(!field.isDependent());

Expand All @@ -813,6 +819,7 @@ export const ResourceBase = Backbone.Model.extend({
: existingToMany;

return collection.fetch({
...filters,
// Only store the collection if fetch is successful (doesn't return undefined)
success: (collection) => {
this.storeIndependent(field, collection);
Expand Down
10 changes: 4 additions & 6 deletions specifyweb/frontend/js_src/lib/components/Forms/SubView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ export function SubView({
parentResource,
'saved',
(): void => {
if (!relationship.isDependent()) {
handleFetch({
offset: 0,
reset: true,
} as CollectionFetchFilters<AnySchema>);
}
handleFetch({
offset: 0,
reset: true,
} as CollectionFetchFilters<AnySchema>);
},
false
),
Expand Down
106 changes: 48 additions & 58 deletions specifyweb/frontend/js_src/lib/hooks/useCollection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import type { AnySchema } from '../components/DataModel/helperTypes';
import type { SpecifyResource } from '../components/DataModel/legacyTypes';
import type { Relationship } from '../components/DataModel/specifyField';
import type { Collection } from '../components/DataModel/specifyTable';
import { raise } from '../components/Errors/Crash';
import type { SubViewSortField } from '../components/FormParse/cells';
import { relationshipIsToMany } from '../components/WbPlanView/mappingHelpers';
import type { GetOrSet, RA } from '../utils/types';
import type { GetOrSet } from '../utils/types';
import { overwriteReadOnly } from '../utils/types';
import { sortFunction } from '../utils/utils';
import { useAsyncState } from './useAsyncState';
Expand All @@ -17,6 +16,7 @@ type UseCollectionProps<SCHEMA extends AnySchema> = {
readonly parentResource: SpecifyResource<SCHEMA>;
readonly relationship: Relationship;
readonly sortBy?: SubViewSortField;
readonly filters?: CollectionFetchFilters<SCHEMA>;
};

export function useCollection<SCHEMA extends AnySchema>({
Expand Down Expand Up @@ -44,7 +44,6 @@ export function useCollection<SCHEMA extends AnySchema>({
: fetchToOneCollection({
parentResource,
relationship,
sortBy,
}),
[sortBy, parentResource, relationship]
),
Expand All @@ -62,25 +61,28 @@ export function useCollection<SCHEMA extends AnySchema>({
versionRef.current += 1;
const localVersionRef = versionRef.current;

return collection
.fetch({
...filters,
success: (collection) => {
/*
* If the collection is already being fetched, don't update it
* to prevent a race condition.
* REFACTOR: simplify this
*/
if (versionRef.current === localVersionRef)
setCollection(collection);
},
} as CollectionFetchFilters<AnySchema>)
.catch((error: Error, ...args: RA<unknown>) => {
raise(error, args);
return undefined;
});
const fetchCollection =
relationshipIsToMany(relationship) &&
relationship.type !== 'zero-to-one'
? fetchToManyCollection({
parentResource,
relationship,
sortBy,
filters,
})
: fetchToOneCollection({ parentResource, relationship });

return fetchCollection.then((collection) => {
if (
typeof collection === 'object' &&
versionRef.current === localVersionRef
) {
setCollection(collection);
}
return collection === false ? undefined : collection;
});
},
[collection, setCollection]
[collection, parentResource, relationship, setCollection, sortBy]
);
return [collection, setCollection, handleFetch];
}
Expand All @@ -89,37 +91,39 @@ const fetchToManyCollection = async <SCHEMA extends AnySchema>({
parentResource,
relationship,
sortBy,
filters,
}: UseCollectionProps<SCHEMA>): Promise<Collection<SCHEMA> | undefined> =>
parentResource.rgetCollection(relationship.name).then((collection) => {
// TEST: check if this can ever happen
if (collection === null || collection === undefined)
return new relationship.relatedTable.DependentCollection({
related: parentResource,
field: relationship.getReverse(),
}) as Collection<AnySchema>;
if (sortBy === undefined) return collection;
parentResource
.rgetCollection(relationship.name, filters)
.then((collection) => {
// TEST: check if this can ever happen
if (collection === null || collection === undefined)
return new relationship.relatedTable.DependentCollection({
related: parentResource,
field: relationship.getReverse(),
}) as Collection<AnySchema>;
if (sortBy === undefined) return collection;

// BUG: this does not look into related tables
const field = sortBy.fieldNames[0];
// BUG: this does not look into related tables
const field = sortBy.fieldNames[0];

// Overwriting the models on the collection
overwriteReadOnly(
collection,
'models',
Array.from(collection.models).sort(
sortFunction(
(resource) => resource.get(field),
sortBy.direction === 'desc'
// Overwriting the models on the collection
overwriteReadOnly(
collection,
'models',
Array.from(collection.models).sort(
sortFunction(
(resource) => resource.get(field),
sortBy.direction === 'desc'
)
)
)
);
return collection;
});
);
return collection;
});

async function fetchToOneCollection<SCHEMA extends AnySchema>({
parentResource,
relationship,
sortBy,
}: UseCollectionProps<SCHEMA>): Promise<
Collection<SCHEMA> | false | undefined
> {
Expand Down Expand Up @@ -160,19 +164,5 @@ async function fetchToOneCollection<SCHEMA extends AnySchema>({
'field',
collection.field ?? relationship.getReverse()
);
if (sortBy !== undefined) {
// BUG: this does not look into related tables
const field = sortBy.fieldNames[0];
overwriteReadOnly(
collection,
'models',
Array.from(collection.models).sort(
sortFunction(
(resource) => resource.get(field),
sortBy.direction === 'desc'
)
)
);
}
return collection;
}

0 comments on commit c6c9d8c

Please sign in to comment.