import { client } from "@logilab/cwclientlibjs"; import { AuthProvider, DataProvider } from "ra-core"; import { Schema, ETypesNames } from "./Schema"; // import authProvider from './authProvider'; // see https://marmelab.com/react-admin/Authentication.html export const authProvider: AuthProvider = { // authentication login: (_params) => Promise.resolve(), checkError: (_error) => Promise.resolve(), checkAuth: (_params) => Promise.resolve(), logout: () => Promise.resolve(), getIdentity: () => Promise.resolve({ id: 0 }), // authorization getPermissions: (_params) => Promise.resolve(), }; export function createDataProvider<S extends Schema>( rqlClient: client.CwRqlClient, schema: S ): DataProvider { const getList: DataProvider["getList"] = async ( resource: ETypesNames<S>, { pagination, sort, filter } ) => { const sortAttribute = sort.field === "id" ? "eid" : sort.field; const attributesNames = ["eid", ...Object.keys(schema.etypes[resource])]; const selection: string[] = []; const restrictions: string[] = []; let sortvariable = null; attributesNames.forEach((key, idx) => { const variable = `X${idx}`; selection.push(variable); restrictions.push(`X ${key} ${variable}`); if (key === sortAttribute) { sortvariable = variable; } }); // Handle filters restrictions.push( ...Object.entries(filter).map(([attrName, attrValue]) => { return `EXISTS(X ${attrName} ~= '%${attrValue}%')`; }) ); const total = await rqlClient .queryRows(`Any Count(${selection[0]}) WHERE ${restrictions.join(",")}`) .then((rows) => rows[0][0]); return rqlClient .queryRows( `Any ${selection.join(", ")} ORDERBY ${sortvariable} ${ sort.order } LIMIT ${pagination.perPage} OFFSET ${ (pagination.page - 1) * pagination.perPage } WHERE ${restrictions.join(", ")}`, {} ) .then((rows) => { return { data: rows.map((row) => row.reduce( (agg, attributeValue, idx) => ({ [attributesNames[idx]]: attributeValue, ...agg, }), { id: row[0] } ) ), total, }; }); }; const getOne: DataProvider["getOne"] = async ( resource: ETypesNames<S>, params ) => { // FIXME Retrieve object relation // Getting attributes const attributesNames = [...Object.keys(schema.etypes[resource])]; const selection: string[] = []; const restrictions: string[] = []; attributesNames.forEach((key, idx) => { const variable = `X${idx}`; selection.push(variable); restrictions.push(`X ${key} ${variable}`); }); const result = await rqlClient.queryRows( `Any ${selection.join(",")} Where ${restrictions.join(",")}, X eid ${ params.id }` ); const row = result[0]; const entity = row.reduce( (agg, attributeValue, idx) => ({ [attributesNames[idx]]: attributeValue, ...agg, }), { eid: params.id, id: params.id } ); // Getting subject relations const subjectRelations = Object.fromEntries( Object.entries( schema.relationships ).filter( ([_relationName, definition]: [string, S["relationships"][string]]) => definition.subject.includes(resource) ) ); for (const relationName in subjectRelations) { const result = await rqlClient.queryRows( `Any TARGET Where X ${relationName} TARGET, X eid ${params.id}` ); if (result.length !== 0) { entity[relationName] = result.map((row) => row[0]); } } // Getting object relations const objectRelations = Object.fromEntries( Object.entries( schema.relationships ).filter( ([_relationName, definition]: [string, S["relationships"][string]]) => definition.object.includes(resource) ) ); for (const relationName in objectRelations) { const result = await rqlClient.queryRows( `Any TARGET Where TARGET ${relationName} X, X eid ${params.id}` ); if (result.length !== 0) { entity[`reverse_${relationName}`] = result.map((row) => row[0]); } } return { data: entity }; }; const getMany: DataProvider["getMany"] = async (resource, params) => { // FIXME handle several params id and refactor code to use GetOne // Getting attributes const attributesNames = [...Object.keys(schema.etypes[resource])]; const selection: string[] = []; const restrictions: string[] = []; attributesNames.forEach((key, idx) => { const variable = `X${idx}`; selection.push(variable); restrictions.push(`X ${key} ${variable}`); }); const result = await rqlClient.queryRows( `Any ${selection.join(",")} Where ${restrictions.join( "," )}, X eid IN (${params.ids.join(",")})` ); const entities = result.map((row, rowIdx) => row.reduce( (agg, attributeValue, idx) => ({ [attributesNames[idx]]: attributeValue, ...agg, }), { id: params.ids[rowIdx] } ) ); return { data: entities }; }; const getManyReference: DataProvider["getManyReference"] = ( _resource, _params ) => Promise.reject("Not implemented"); const update: DataProvider["update"] = async (resource, { data, id }) => { // FIXME update relations const attributesUpdates: string[] = []; Object.entries(data).forEach(([key, value]) => { if (key in schema.etypes[resource]) { attributesUpdates.push(`X ${key} ${JSON.stringify(value)}`); } }); await rqlClient.queryRows(` SET ${attributesUpdates.join(", ")} WHERE X is ${resource}, X eid ${id} `); return Promise.resolve({ data: { ...data, id } }); }; const updateMany: DataProvider["updateMany"] = (_resource, _params) => Promise.reject("Not implemented"); const create: DataProvider["create"] = async (resource, { data }) => { // FIXME create relations const attributesUpdates: string[] = []; Object.entries(data).forEach(([key, value]) => { if (key in schema.etypes[resource]) { attributesUpdates.push(`X ${key} ${JSON.stringify(value)}`); } }); const result = await rqlClient.queryRows(` INSERT ${resource} X: ${attributesUpdates.join(", ")} `); const eid = result[0][0]; return Promise.resolve({ data: { ...data, id: eid } }); }; const _delete: DataProvider["delete"] = (_resource, _params) => Promise.reject("Not implemented"); const deleteMany: DataProvider["deleteMany"] = (_resource, _params) => Promise.reject("Not implemented"); return { getList, getOne, getMany, getManyReference, update, updateMany, create, delete: _delete, deleteMany, }; }