Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@ describe('postgres entity integration', () => {
.createAsync(),
);

const results = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualityConjunctionAsync([
const results = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByFieldEqualityConjunctionAsync([
{
fieldName: 'hasACat',
fieldValue: false,
Expand All @@ -403,9 +405,11 @@ describe('postgres entity integration', () => {

expect(results).toHaveLength(2);

const results2 = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualityConjunctionAsync(
[{ fieldName: 'hasADog', fieldValues: [true, false] }],
);
const results2 = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByFieldEqualityConjunctionAsync([
{ fieldName: 'hasADog', fieldValues: [true, false] },
]);
expect(results2).toHaveLength(3);
});

Expand All @@ -424,19 +428,18 @@ describe('postgres entity integration', () => {
PostgresTestEntity.creatorWithAuthorizationResults(vc1).setField('name', 'c').createAsync(),
);

const results = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualityConjunctionAsync(
[],
{
limit: 2,
offset: 1,
orderBy: [
{
fieldName: 'name',
order: OrderByOrdering.DESCENDING,
},
],
},
);
const results = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByFieldEqualityConjunctionAsync([], {
limit: 2,
offset: 1,
orderBy: [
{
fieldName: 'name',
order: OrderByOrdering.DESCENDING,
},
],
});
expect(results).toHaveLength(2);
expect(results.map((e) => e.getField('name'))).toEqual(['b', 'a']);
});
Expand Down Expand Up @@ -468,13 +471,15 @@ describe('postgres entity integration', () => {
.createAsync(),
);

const results = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualityConjunctionAsync([
{ fieldName: 'name', fieldValue: null },
]);
const results = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByFieldEqualityConjunctionAsync([{ fieldName: 'name', fieldValue: null }]);
expect(results).toHaveLength(2);
expect(results[0]!.getField('name')).toBeNull();

const results2 = await PostgresTestEntity.loader(vc1).loadManyByFieldEqualityConjunctionAsync(
const results2 = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByFieldEqualityConjunctionAsync(
[
{ fieldName: 'name', fieldValues: ['a', null] },
{ fieldName: 'hasADog', fieldValue: true },
Expand Down Expand Up @@ -504,7 +509,7 @@ describe('postgres entity integration', () => {
.createAsync(),
);

const results = await PostgresTestEntity.loader(vc1).loadManyByRawWhereClauseAsync(
const results = await PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync(
'name = ?',
['hello'],
);
Expand All @@ -523,7 +528,7 @@ describe('postgres entity integration', () => {
);

await expect(
PostgresTestEntity.loader(vc1).loadManyByRawWhereClauseAsync('invalid_column = ?', [
PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync('invalid_column = ?', [
'hello',
]),
).rejects.toThrow();
Expand Down Expand Up @@ -553,7 +558,7 @@ describe('postgres entity integration', () => {
.createAsync(),
);

const results = await PostgresTestEntity.loader(vc1).loadManyByRawWhereClauseAsync(
const results = await PostgresTestEntity.knexLoader(vc1).loadManyByRawWhereClauseAsync(
'has_a_dog = ?',
[true],
{
Expand All @@ -571,7 +576,7 @@ describe('postgres entity integration', () => {
expect(results).toHaveLength(2);
expect(results.map((e) => e.getField('name'))).toEqual(['b', 'c']);

const resultsMultipleOrderBy = await PostgresTestEntity.loader(
const resultsMultipleOrderBy = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByRawWhereClauseAsync('has_a_dog = ?', [true], {
orderBy: [
Expand All @@ -589,13 +594,11 @@ describe('postgres entity integration', () => {
expect(resultsMultipleOrderBy).toHaveLength(3);
expect(resultsMultipleOrderBy.map((e) => e.getField('name'))).toEqual(['c', 'b', 'a']);

const resultsOrderByRaw = await PostgresTestEntity.loader(vc1).loadManyByRawWhereClauseAsync(
'has_a_dog = ?',
[true],
{
orderByRaw: 'has_a_dog ASC, name DESC',
},
);
const resultsOrderByRaw = await PostgresTestEntity.knexLoader(
vc1,
).loadManyByRawWhereClauseAsync('has_a_dog = ?', [true], {
orderByRaw: 'has_a_dog ASC, name DESC',
});

expect(resultsOrderByRaw).toHaveLength(3);
expect(resultsOrderByRaw.map((e) => e.getField('name'))).toEqual(['c', 'b', 'a']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class TestSecondaryLocalMemoryCacheLoader extends EntitySecondaryCacheLoader<
}
return nullthrows(
(
await this.entityLoader.loadManyByFieldEqualityConjunctionAsync([
await this.knexEntityLoader.loadManyByFieldEqualityConjunctionAsync([
{ fieldName: 'id', fieldValue: loadParams.id },
])
)[0],
Expand All @@ -198,6 +198,7 @@ describe(LocalMemorySecondaryEntityCache, () => {
createTTLCache<LocalMemoryTestEntityFields>(),
),
LocalMemoryTestEntity.loaderWithAuthorizationResults(viewerContext),
LocalMemoryTestEntity.knexLoaderWithAuthorizationResults(viewerContext),
);

const loadParams = { id: createdEntity.getID() };
Expand Down Expand Up @@ -234,6 +235,7 @@ describe(LocalMemorySecondaryEntityCache, () => {
createTTLCache<LocalMemoryTestEntityFields>(),
),
LocalMemoryTestEntity.loaderWithAuthorizationResults(viewerContext),
LocalMemoryTestEntity.knexLoaderWithAuthorizationResults(viewerContext),
);

const loadParams = { id: FAKE_ID };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class TestSecondaryRedisCacheLoader extends EntitySecondaryCacheLoader<
}
return nullthrows(
(
await this.entityLoader.loadManyByFieldEqualityConjunctionAsync([
await this.knexEntityLoader.loadManyByFieldEqualityConjunctionAsync([
{ fieldName: 'id', fieldValue: loadParams.id },
])
)[0],
Expand Down Expand Up @@ -98,6 +98,7 @@ describe(RedisSecondaryEntityCache, () => {
(loadParams) => `test-key-${loadParams.id}`,
),
RedisTestEntity.loaderWithAuthorizationResults(viewerContext),
RedisTestEntity.knexLoaderWithAuthorizationResults(viewerContext),
);

const loadParams = { id: createdEntity.getID() };
Expand Down Expand Up @@ -137,6 +138,7 @@ describe(RedisSecondaryEntityCache, () => {
(loadParams) => `test-key-${loadParams.id}`,
),
RedisTestEntity.loaderWithAuthorizationResults(viewerContext),
RedisTestEntity.knexLoaderWithAuthorizationResults(viewerContext),
);

const loadParams = { id: FAKE_ID };
Expand Down
84 changes: 2 additions & 82 deletions packages/entity/src/AuthorizationResultBasedEntityLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,11 @@ import {
EntityCompositeFieldValue,
EntityConfiguration,
} from './EntityConfiguration';
import {
FieldEqualityCondition,
isSingleValueFieldEqualityCondition,
QuerySelectionModifiers,
QuerySelectionModifiersWithOrderByRaw,
} from './EntityDatabaseAdapter';
import { EntityLoaderUtils } from './EntityLoaderUtils';
import { EntityPrivacyPolicy } from './EntityPrivacyPolicy';
import { EntityQueryContext } from './EntityQueryContext';
import { ReadonlyEntity } from './ReadonlyEntity';
import { ViewerContext } from './ViewerContext';
import { EntityInvalidFieldValueError } from './errors/EntityInvalidFieldValueError';
import { EntityNotFoundError } from './errors/EntityNotFoundError';
import { CompositeFieldHolder, CompositeFieldValueHolder } from './internal/CompositeFieldHolder';
import { CompositeFieldValueMap } from './internal/CompositeFieldValueMap';
Expand Down Expand Up @@ -265,87 +258,14 @@ export class AuthorizationResultBasedEntityLoader<
});
}

/**
* Authorization-result-based version of the EnforcingEntityLoader method by the same name.
* @returns the first entity results that matches the query, where result error can be
* UnauthorizedError
*/
async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>,
): Promise<Result<TEntity> | null> {
const results = await this.loadManyByFieldEqualityConjunctionAsync(fieldEqualityOperands, {
...querySelectionModifiers,
limit: 1,
});
return results[0] ?? null;
}

/**
* Authorization-result-based version of the EnforcingEntityLoader method by the same name.
* @returns array of entity results that match the query, where result error can be UnauthorizedError
*/
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
querySelectionModifiers: QuerySelectionModifiers<TFields> = {},
): Promise<readonly Result<TEntity>[]> {
for (const fieldEqualityOperand of fieldEqualityOperands) {
const fieldValues = isSingleValueFieldEqualityCondition(fieldEqualityOperand)
? [fieldEqualityOperand.fieldValue]
: fieldEqualityOperand.fieldValues;
this.validateFieldAndValues(fieldEqualityOperand.fieldName, fieldValues);
}

const fieldObjects = await this.dataManager.loadManyByFieldEqualityConjunctionAsync(
this.queryContext,
fieldEqualityOperands,
querySelectionModifiers,
);
return await this.utils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
}

/**
* Authorization-result-based version of the EnforcingEntityLoader method by the same name.
* @returns array of entity results that match the query, where result error can be UnauthorizedError
* @throws Error when rawWhereClause or bindings are invalid
*/
async loadManyByRawWhereClauseAsync(
rawWhereClause: string,
bindings: any[] | object,
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
): Promise<readonly Result<TEntity>[]> {
const fieldObjects = await this.dataManager.loadManyByRawWhereClauseAsync(
this.queryContext,
rawWhereClause,
bindings,
querySelectionModifiers,
);
return await this.utils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
}

private validateFieldAndValues<N extends keyof Pick<TFields, TSelectedFields>>(
fieldName: N,
fieldValues: readonly TFields[N][],
): void {
const fieldDefinition = this.entityConfiguration.schema.get(fieldName);
invariant(fieldDefinition, `must have field definition for field = ${String(fieldName)}`);
for (const fieldValue of fieldValues) {
const isInputValid = fieldDefinition.validateInputValue(fieldValue);
if (!isInputValid) {
throw new EntityInvalidFieldValueError(this.entityClass, fieldName, fieldValue);
}
}
}

private validateFieldAndValuesAndConvertToHolders<N extends keyof Pick<TFields, TSelectedFields>>(
fieldName: N,
fieldValues: readonly NonNullable<TFields[N]>[],
): {
loadKey: SingleFieldHolder<TFields, TIDField, N>;
loadValues: readonly SingleFieldValueHolder<TFields, N>[];
} {
this.validateFieldAndValues(fieldName, fieldValues);
this.utils.validateFieldAndValues(fieldName, fieldValues);

return {
loadKey: new SingleFieldHolder<TFields, TIDField, N>(fieldName),
Expand Down Expand Up @@ -388,7 +308,7 @@ export class AuthorizationResultBasedEntityLoader<
);
for (const field of compositeField) {
const fieldValue = compositeFieldValueHolder.compositeFieldValue[field];
this.validateFieldAndValues(field, [fieldValue]);
this.utils.validateFieldAndValues(field, [fieldValue]);
}
}

Expand Down
Loading