Skip to content
Snippets Groups Projects
index.ts 6.65 KiB
Newer Older
Frank Bessou's avatar
Frank Bessou committed
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(),
};

Frank Bessou's avatar
Frank Bessou committed
export function createDataProvider<S extends Schema>(
  rqlClient: client.CwRqlClient,
Frank Bessou's avatar
Frank Bessou committed
  schema: S
): DataProvider {
  return {
    getList: async (resource: ETypesNames<S>, { pagination, sort, filter }) => {
      const sortAttribute = sort.field === "id" ? "eid" : sort.field;
Frank Bessou's avatar
Frank Bessou committed
      const attributesNames = ["eid", ...Object.keys(schema.etypes[resource])];
      const selection: string[] = [];
      const restrictions: string[] = [];
      let sortvariable = null;
Frank Bessou's avatar
Frank Bessou committed
      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}%')`;
        })
      );

Frank Bessou's avatar
Frank Bessou committed
      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
Frank Bessou's avatar
Frank Bessou committed
          } WHERE ${restrictions.join(", ")}`,
          {}
        )
        .then((rows) => {
          return {
            data: rows.map((row) =>
              row.reduce(
                (agg, attributeValue, idx) => ({
                  [attributesNames[idx]]: attributeValue,
                  ...agg,
                }),
                { id: row[0] }
              )
            ),
            total,
          };
        });
    },
    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(
Frank Bessou's avatar
Frank Bessou committed
        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(
Frank Bessou's avatar
Frank Bessou committed
        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 };
Frank Bessou's avatar
Frank Bessou committed
    },
    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(
Frank Bessou's avatar
Frank Bessou committed
        `Any ${selection.join(",")} Where ${restrictions.join(
          ","
        )}, X eid IN (${params.ids.join(",")})`
Frank Bessou's avatar
Frank Bessou committed
      const entities = result.map((row, rowIdx) =>
        row.reduce(
          (agg, attributeValue, idx) => ({
            [attributesNames[idx]]: attributeValue,
            ...agg,
          }),
          { id: params.ids[rowIdx] }
        )
      );
      return { data: entities };
Frank Bessou's avatar
Frank Bessou committed
    getManyReference: (_resource, _params) => Promise.reject("Not implemented"),
    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 } });
    },
Frank Bessou's avatar
Frank Bessou committed
    updateMany: (_resource, _params) => Promise.reject("Not implemented"),
    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 } });
    },
Frank Bessou's avatar
Frank Bessou committed
    delete: (_resource, _params) => Promise.reject("Not implemented"),
    deleteMany: (_resource, _params) => Promise.reject("Not implemented"),
  };
}