mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
back
This commit is contained in:
213
packages/appwrite/src/dataProvider.ts
Normal file
213
packages/appwrite/src/dataProvider.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import { DataProvider } from "@refinedev/core";
|
||||
import { Client as Appwrite, Databases, Permission, Role, ID } from "appwrite";
|
||||
import {
|
||||
getAppwriteFilters,
|
||||
getAppwritePagination,
|
||||
getAppwriteSorting,
|
||||
} from "./utils";
|
||||
|
||||
export const dataProvider = (
|
||||
appwriteClient: Appwrite,
|
||||
options: { databaseId: string } = { databaseId: "default" },
|
||||
): Required<DataProvider> => {
|
||||
const { databaseId } = options;
|
||||
|
||||
const database = new Databases(appwriteClient);
|
||||
|
||||
return {
|
||||
getList: async ({ resource, pagination, filters, sorters }) => {
|
||||
const {
|
||||
current = 1,
|
||||
pageSize = 10,
|
||||
mode = "server",
|
||||
} = pagination ?? {};
|
||||
|
||||
const appwriteFilters = getAppwriteFilters(filters);
|
||||
|
||||
const appwritePagination =
|
||||
mode === "server"
|
||||
? getAppwritePagination(current, pageSize)
|
||||
: [];
|
||||
|
||||
const appwriteSorts = getAppwriteSorting(sorters);
|
||||
|
||||
const { total: total, documents: data } =
|
||||
await database.listDocuments<any>(databaseId, resource, [
|
||||
...appwriteFilters,
|
||||
...appwritePagination,
|
||||
...appwriteSorts,
|
||||
]);
|
||||
|
||||
return {
|
||||
data: data.map(({ $id, ...restData }: { $id: string }) => ({
|
||||
id: $id,
|
||||
...restData,
|
||||
})) as any,
|
||||
total,
|
||||
};
|
||||
},
|
||||
getOne: async ({ resource, id }) => {
|
||||
const { $id, ...restData } = await database.getDocument(
|
||||
databaseId,
|
||||
resource,
|
||||
id.toString(),
|
||||
);
|
||||
|
||||
return {
|
||||
data: {
|
||||
id: $id,
|
||||
...restData,
|
||||
},
|
||||
} as any;
|
||||
},
|
||||
update: async ({ resource, id, variables, meta }) => {
|
||||
const permissions = [
|
||||
Permission.read(Role.any()),
|
||||
Permission.write(Role.any()),
|
||||
...(meta?.readPermissions ?? ""),
|
||||
...(meta?.writePermissions ?? ""),
|
||||
];
|
||||
const { $id, ...restData } = await database.updateDocument(
|
||||
databaseId,
|
||||
resource,
|
||||
id.toString(),
|
||||
variables as any,
|
||||
permissions,
|
||||
);
|
||||
|
||||
return {
|
||||
data: {
|
||||
id: $id,
|
||||
...restData,
|
||||
},
|
||||
} as any;
|
||||
},
|
||||
create: async ({ resource, variables, meta }) => {
|
||||
const permissions = [
|
||||
Permission.read(Role.any()),
|
||||
Permission.write(Role.any()),
|
||||
...(meta?.readPermissions ?? ""),
|
||||
...(meta?.writePermissions ?? ""),
|
||||
];
|
||||
|
||||
const { $id, ...restData } = await database.createDocument(
|
||||
databaseId,
|
||||
resource,
|
||||
meta?.documentId ?? ID.unique(),
|
||||
variables as unknown as object,
|
||||
permissions,
|
||||
);
|
||||
|
||||
return {
|
||||
data: {
|
||||
id: $id,
|
||||
...restData,
|
||||
},
|
||||
} as any;
|
||||
},
|
||||
createMany: async ({ resource, variables, meta }) => {
|
||||
const permissions = [
|
||||
Permission.read(Role.any()),
|
||||
Permission.write(Role.any()),
|
||||
...(meta?.readPermissions ?? ""),
|
||||
...(meta?.writePermissions ?? ""),
|
||||
];
|
||||
const data = await Promise.all(
|
||||
variables.map((document) =>
|
||||
database.createDocument<any>(
|
||||
databaseId,
|
||||
resource,
|
||||
meta?.documentId ?? ID.unique(),
|
||||
document as unknown as any,
|
||||
permissions,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
data: data.map(({ $id, ...restData }) => ({
|
||||
id: $id,
|
||||
...restData,
|
||||
})),
|
||||
} as any;
|
||||
},
|
||||
deleteOne: async ({ resource, id }) => {
|
||||
await database.deleteDocument(databaseId, resource, id.toString());
|
||||
|
||||
return {
|
||||
data: { id },
|
||||
} as any;
|
||||
},
|
||||
deleteMany: async ({ resource, ids }) => {
|
||||
await Promise.all(
|
||||
ids.map((id) =>
|
||||
database.deleteDocument(
|
||||
databaseId,
|
||||
resource,
|
||||
id.toString(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
data: ids.map((id) => ({
|
||||
id,
|
||||
})),
|
||||
} as any;
|
||||
},
|
||||
getMany: async ({ resource, ids }) => {
|
||||
const data = await Promise.all(
|
||||
ids.map((id) =>
|
||||
database.getDocument<any>(
|
||||
databaseId,
|
||||
resource,
|
||||
id.toString(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
data: data.map(({ $id, ...restData }) => ({
|
||||
id: $id,
|
||||
...restData,
|
||||
})),
|
||||
} as any;
|
||||
},
|
||||
updateMany: async ({ resource, ids, variables, meta }) => {
|
||||
const permissions = [
|
||||
Permission.read(Role.any()),
|
||||
Permission.write(Role.any()),
|
||||
...(meta?.readPermissions ?? ""),
|
||||
...(meta?.writePermissions ?? ""),
|
||||
];
|
||||
const data = await Promise.all(
|
||||
ids.map((id) =>
|
||||
database.updateDocument<any>(
|
||||
databaseId,
|
||||
resource,
|
||||
id.toString(),
|
||||
variables as unknown as object,
|
||||
permissions,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
data: data.map(({ $id, ...restData }) => ({
|
||||
id: $id,
|
||||
...restData,
|
||||
})),
|
||||
} as any;
|
||||
},
|
||||
getApiUrl: () => {
|
||||
throw Error(
|
||||
"'getApiUrl' method is not implemented on refine-appwrite data provider.",
|
||||
);
|
||||
},
|
||||
custom: () => {
|
||||
throw Error(
|
||||
"'custom' method is not implemented on refine-appwrite data provider.",
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
27
packages/appwrite/src/index.ts
Normal file
27
packages/appwrite/src/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export * from "./dataProvider";
|
||||
export * from "./liveProvider";
|
||||
|
||||
export {
|
||||
Account,
|
||||
AppwriteException,
|
||||
Avatars,
|
||||
Client as Appwrite,
|
||||
Databases,
|
||||
Functions,
|
||||
Locale,
|
||||
Query,
|
||||
Storage,
|
||||
Teams,
|
||||
Permission,
|
||||
ID,
|
||||
Role,
|
||||
} from "appwrite";
|
||||
|
||||
export type {
|
||||
Models,
|
||||
Payload,
|
||||
UploadProgress,
|
||||
QueryTypes,
|
||||
QueryTypesList,
|
||||
RealtimeResponseEvent,
|
||||
} from "appwrite";
|
||||
46
packages/appwrite/src/liveProvider.ts
Normal file
46
packages/appwrite/src/liveProvider.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { LiveProvider } from "@refinedev/core";
|
||||
import { Client as Appwrite } from "appwrite";
|
||||
import { getRefineEvent } from "./utils";
|
||||
|
||||
export const liveProvider = (
|
||||
appwriteClient: Appwrite,
|
||||
options: { databaseId: string } = { databaseId: "default" },
|
||||
): LiveProvider => {
|
||||
const { databaseId } = options;
|
||||
return {
|
||||
subscribe: ({ channel, types, params, callback }): any => {
|
||||
const resource = channel.replace("resources/", "");
|
||||
|
||||
let appwriteChannel;
|
||||
|
||||
if (params?.ids) {
|
||||
appwriteChannel = params.ids.map(
|
||||
(id) =>
|
||||
`databases.${databaseId}.collections.${resource}.documents.${id}`,
|
||||
);
|
||||
} else {
|
||||
appwriteChannel = `databases.${databaseId}.collections.${resource}.documents`;
|
||||
}
|
||||
|
||||
return appwriteClient.subscribe(appwriteChannel, (event) => {
|
||||
const refineEvent = getRefineEvent(event.events[0]);
|
||||
if (
|
||||
types.includes("*") ||
|
||||
(refineEvent && types.includes(refineEvent))
|
||||
) {
|
||||
callback({
|
||||
channel,
|
||||
type:
|
||||
getRefineEvent(event.events[0]) ?? event.events[0],
|
||||
payload: event.payload as any,
|
||||
date: new Date(event.timestamp * 1000),
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
unsubscribe: async (unsubscribe: () => void) => {
|
||||
unsubscribe();
|
||||
},
|
||||
};
|
||||
};
|
||||
23
packages/appwrite/src/utils/generateFilter.ts
Normal file
23
packages/appwrite/src/utils/generateFilter.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { CrudFilter } from "@refinedev/core";
|
||||
import { Query } from "appwrite";
|
||||
|
||||
export const generateFilter = (filter: CrudFilter) => {
|
||||
switch (filter.operator) {
|
||||
case "eq":
|
||||
return Query.equal(filter.field, filter.value);
|
||||
case "ne":
|
||||
return Query.notEqual(filter.field, filter.value);
|
||||
case "gt":
|
||||
return Query.greaterThan(filter.field, filter.value);
|
||||
case "gte":
|
||||
return Query.greaterThanEqual(filter.field, filter.value);
|
||||
case "lt":
|
||||
return Query.lessThan(filter.field, filter.value);
|
||||
case "lte":
|
||||
return Query.lessThanEqual(filter.field, filter.value);
|
||||
case "contains":
|
||||
return Query.search(filter.field, `%${filter.value}%`);
|
||||
default:
|
||||
throw new Error(`Operator ${filter.operator} is not supported`);
|
||||
}
|
||||
};
|
||||
29
packages/appwrite/src/utils/getAppwriteFilters.ts
Normal file
29
packages/appwrite/src/utils/getAppwriteFilters.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { CrudFilters } from "@refinedev/core";
|
||||
import { generateFilter } from "./generateFilter";
|
||||
|
||||
type GetAppwriteFiltersType = {
|
||||
(filters?: CrudFilters): string[];
|
||||
};
|
||||
|
||||
export const getAppwriteFilters: GetAppwriteFiltersType = (filters) => {
|
||||
const appwriteFilters: string[] = [];
|
||||
|
||||
for (const filter of filters ?? []) {
|
||||
if (
|
||||
filter.operator !== "or" &&
|
||||
filter.operator !== "and" &&
|
||||
"field" in filter
|
||||
) {
|
||||
const filterField = filter.field === "id" ? "$id" : filter.field;
|
||||
|
||||
appwriteFilters.push(
|
||||
generateFilter({
|
||||
...filter,
|
||||
field: filterField,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return appwriteFilters;
|
||||
};
|
||||
5
packages/appwrite/src/utils/getAppwritePagination.ts
Normal file
5
packages/appwrite/src/utils/getAppwritePagination.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Query } from "appwrite";
|
||||
|
||||
export const getAppwritePagination = (current: number, pageSize: number) => {
|
||||
return [Query.offset((current - 1) * pageSize), Query.limit(pageSize)];
|
||||
};
|
||||
23
packages/appwrite/src/utils/getAppwriteSorting.ts
Normal file
23
packages/appwrite/src/utils/getAppwriteSorting.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { CrudSorting } from "@refinedev/core";
|
||||
import { Query } from "appwrite";
|
||||
|
||||
type GetAppwriteSortingType = {
|
||||
(sorts?: CrudSorting): string[];
|
||||
};
|
||||
|
||||
export const getAppwriteSorting: GetAppwriteSortingType = (sorters) => {
|
||||
const sorts: string[] = [];
|
||||
|
||||
if (sorters) {
|
||||
sorters.map((item) => {
|
||||
const field = item.field === "id" ? "$id" : item.field;
|
||||
if (item.order === "asc") {
|
||||
sorts.push(Query.orderAsc(field));
|
||||
} else {
|
||||
sorts.push(Query.orderDesc(field));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return sorts;
|
||||
};
|
||||
14
packages/appwrite/src/utils/getRefineEvent.ts
Normal file
14
packages/appwrite/src/utils/getRefineEvent.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { LiveEvent } from "@refinedev/core";
|
||||
|
||||
export const getRefineEvent = (
|
||||
event: string,
|
||||
): LiveEvent["type"] | undefined => {
|
||||
if (event.includes(".create")) {
|
||||
return "created";
|
||||
} else if (event.includes(".update")) {
|
||||
} else if (event.includes(".delete")) {
|
||||
return "deleted";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
5
packages/appwrite/src/utils/index.ts
Normal file
5
packages/appwrite/src/utils/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from "./getRefineEvent";
|
||||
export * from "./generateFilter";
|
||||
export * from "./getAppwriteFilters";
|
||||
export * from "./getAppwriteSorting";
|
||||
export * from "./getAppwritePagination";
|
||||
Reference in New Issue
Block a user