This commit is contained in:
Stefan Pejcic
2024-05-08 19:58:53 +02:00
parent 440d98beff
commit 8595a9f4e5
2479 changed files with 591504 additions and 0 deletions

View 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.",
);
},
};
};

View 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";

View 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();
},
};
};

View 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`);
}
};

View 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;
};

View 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)];
};

View 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;
};

View 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;
};

View File

@@ -0,0 +1,5 @@
export * from "./getRefineEvent";
export * from "./generateFilter";
export * from "./getAppwriteFilters";
export * from "./getAppwriteSorting";
export * from "./getAppwritePagination";