@cubicweb/data-provider
Version:
CubicWeb data provider implementation
194 lines (177 loc) • 5.48 kB
text/typescript
import {
EntityRawSchemaArray,
Client,
RelationDefinitionRawSchemaArray,
Schema,
Transaction,
RQLQuery,
getLooseSchema,
} from "@cubicweb/client";
import {
GetListParams,
GetListResult,
GetManyParams,
GetManyReferenceParams,
GetManyReferenceResult,
GetManyResult,
GetOneParams,
GetOneResult,
Identifier,
RaRecord,
} from "./types.js";
import { executeApiTransaction } from "./utils/requests.js";
import {
EntityData,
generateCountEntitiesRQL,
generateSelectEntitiesRQL,
getEntityRelationNames,
resultSetToEntities,
resultSetToEntity,
} from "@cubicweb/rql-generator";
export const getGet = <
E extends EntityRawSchemaArray,
R extends RelationDefinitionRawSchemaArray<E>
>(
client: Client,
schema: Schema<E, R>
) => {
const getDefaultRelations = (entity: string) => {
const relations = [];
const entitySchema = getLooseSchema(schema).getEntity(entity)!;
relations.push(...getEntityRelationNames(entitySchema, "attributes"));
relations.push(...getEntityRelationNames(entitySchema, "subject"));
return relations;
};
const getList = async (
resource: E[number]["type"],
{ pagination, sort, filter }: GetListParams
): Promise<GetListResult<RaRecord>> => {
if (typeof filter !== "string") {
throw new Error("Only RQL filters are supported for now");
}
const transaction = new Transaction();
const queries = generateSelectEntitiesRQL(schema, resource, {
limit: pagination.perPage,
offset: (pagination.page - 1) * pagination.perPage,
orderBy: [{ relationName: sort.field, ascending: sort.order === "ASC" }],
relations: getDefaultRelations(resource),
where: new RQLQuery(filter, {}),
});
transaction.push(...queries);
const countQueries = generateCountEntitiesRQL(schema, resource, {
where: new RQLQuery(filter, {}),
});
transaction.push(...countQueries);
return executeApiTransaction(client, transaction).then((result) => {
const total = result.getCell(countQueries[0].cellRef(0, 0)) as number;
const entities = resultSetToEntities(
schema,
resource,
undefined,
result.getResultSet(queries[0])
);
return {
data: addIdToEntities(entities),
total,
};
});
};
const getOne = async (
resource: E[number]["type"],
params: GetOneParams
): Promise<GetOneResult<RaRecord>> => {
const transaction = new Transaction();
const queries = generateSelectEntitiesRQL(schema, resource, {
where: { eid: getEid(params.id) },
relations: params.meta,
});
transaction.push(...queries);
return executeApiTransaction(client, transaction).then((result) => {
const entity = resultSetToEntity(
schema,
resource,
params.meta,
result.getResultSet(queries[0])
);
return {
data: addIdToEntity(entity),
};
});
};
const getMany = async (
resource: E[number]["type"],
params: GetManyParams
): Promise<GetManyResult<RaRecord>> => {
const idList = params.ids.map(getEid);
const transaction = new Transaction();
const queries = generateSelectEntitiesRQL(schema, resource, {
limit: idList.length,
orderBy: [{ relationName: "eid", ascending: true }],
relations: getDefaultRelations(resource),
where: new RQLQuery(`X eid IN (${idList.join(", ")},)`, {}),
});
transaction.push(...queries);
return executeApiTransaction(client, transaction).then((result) => {
const entities = resultSetToEntities(
schema,
resource,
params.meta,
result.getResultSet(queries[0])
);
return {
data: addIdToEntities(entities),
};
});
};
const getManyReference = async (
resource: E[number]["type"],
{ target, id, pagination, sort, filter }: GetManyReferenceParams
): Promise<GetManyReferenceResult<RaRecord>> => {
if (typeof filter !== "string") {
throw new Error("Only RQL filters are supported for now");
}
const transaction = new Transaction();
const filterRql = new RQLQuery(
`X ${target} ${id}${filter ? ", " + filter : ""}`,
{}
);
const queries = generateSelectEntitiesRQL(schema, resource, {
limit: pagination.perPage,
offset: (pagination.page - 1) * pagination.perPage,
orderBy: [{ relationName: sort.field, ascending: sort.order === "ASC" }],
relations: getDefaultRelations(resource),
where: filterRql,
});
transaction.push(...queries);
const countQueries = generateCountEntitiesRQL(schema, resource, {
where: filterRql,
});
transaction.push(...countQueries);
return executeApiTransaction(client, transaction).then((result) => {
const total = result.getCell(countQueries[0].cellRef(0, 0)) as number;
const entities = resultSetToEntities(
schema,
resource,
undefined,
result.getResultSet(queries[0])
);
return {
data: addIdToEntities(entities),
total,
};
});
};
return { getList, getOne, getMany, getManyReference };
};
function addIdToEntities(entityList: EntityData[]): RaRecord[] {
return entityList.map(addIdToEntity);
}
function addIdToEntity(entity: EntityData): RaRecord {
return {
...entity,
id: entity.eid,
};
}
function getEid(id: Identifier) {
return typeof id === "string" ? parseInt(id) : id;
}