convex-ents 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/writer.ts","../src/functions.ts"],"sourcesContent":["import {\n DocumentByName,\n GenericDatabaseWriter,\n GenericDocument,\n TableNamesInDataModel,\n} from \"convex/server\";\nimport { GenericId } from \"convex/values\";\nimport { entWrapper, getReadRule, getWriteRule } from \"./functions\";\nimport {\n EdgeConfig,\n FieldConfig,\n GenericEdgeConfig,\n GenericEntsDataModel,\n} from \"./schema\";\n\nexport class WriterImplBase<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> {\n constructor(\n protected db: GenericDatabaseWriter<EntsDataModel>,\n protected entDefinitions: EntsDataModel,\n protected table: Table\n ) {}\n\n async writeEdges(docId: GenericId<any>, changes: EdgeChanges) {\n await Promise.all(\n Object.values(\n this.entDefinitions[this.table].edges as Record<string, EdgeConfig>\n ).map(async (edgeDefinition) => {\n const idOrIds = changes[edgeDefinition.name];\n if (idOrIds === undefined) {\n return;\n }\n if (edgeDefinition.cardinality === \"single\") {\n if (edgeDefinition.type === \"ref\") {\n if (idOrIds.remove !== undefined) {\n // Cascading delete because 1:1 edges are not optional\n // on the stored field end.\n await this.db.delete(idOrIds.remove as GenericId<any>);\n }\n if (idOrIds.add !== undefined) {\n await this.db.patch(\n idOrIds.add as GenericId<any>,\n { [edgeDefinition.ref]: docId } as any\n );\n }\n }\n } else {\n if (edgeDefinition.type === \"field\") {\n if (idOrIds.remove !== undefined) {\n // Cascading delete because 1:many edges are not optional\n // on the stored field end.\n await Promise.all(\n (idOrIds.remove as GenericId<any>[]).map((id) =>\n this.db.delete(id)\n )\n );\n // This would be behavior for optional edge:\n // await Promise.all(\n // (idOrIds.remove as GenericId<any>[]).map((id) =>\n // this.db.patch(id, {\n // [edgeDefinition.ref]: undefined,\n // } as any)\n // )\n // );\n }\n if (idOrIds.add !== undefined) {\n await Promise.all(\n (idOrIds.add as GenericId<any>[]).map(async (id) =>\n this.db.patch(id, {\n [edgeDefinition.ref]: docId,\n } as any)\n )\n );\n }\n } else {\n let removeEdges: GenericId<any>[] = [];\n if (idOrIds.remove !== undefined) {\n removeEdges = (\n await Promise.all(\n (idOrIds.remove as GenericId<any>[]).map(async (id) =>\n (\n await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.field, (q) =>\n (q.eq(edgeDefinition.field, docId as any) as any).eq(\n edgeDefinition.ref,\n id\n )\n )\n .collect()\n ).concat(\n edgeDefinition.symmetric\n ? await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.ref, (q) =>\n (\n q.eq(edgeDefinition.ref, docId as any) as any\n ).eq(edgeDefinition.field, id)\n )\n .collect()\n : []\n )\n )\n )\n ).map((doc) => (doc as any)._id);\n }\n if (idOrIds.removeEdges !== undefined) {\n removeEdges = idOrIds.removeEdges;\n }\n if (removeEdges.length > 0) {\n await Promise.all(\n removeEdges.map(async (id) => {\n try {\n await this.db.delete(id);\n } catch (e) {\n // TODO:\n // For now we're gonna ignore errors here,\n // because we assume that the only error\n // is \"document not found\", which\n // can be caused by concurrent deletions.\n // In the future we could track which\n // edges are being deleted by this mutation,\n // and skip the call to delete altogether\n }\n })\n );\n }\n\n if (idOrIds.add !== undefined) {\n await Promise.all(\n (idOrIds.add as GenericId<any>[]).map(async (id) => {\n await this.db.insert(edgeDefinition.table, {\n [edgeDefinition.field]: docId,\n [edgeDefinition.ref]: id,\n } as any);\n if (edgeDefinition.symmetric) {\n await this.db.insert(edgeDefinition.table, {\n [edgeDefinition.field]: id,\n [edgeDefinition.ref]: docId,\n } as any);\n }\n })\n );\n }\n }\n }\n })\n );\n }\n\n async checkUniqueness(value: Partial<GenericDocument>, id?: GenericId<any>) {\n await Promise.all(\n Object.values(\n (this.entDefinitions[this.table] as any).fields as Record<\n string,\n FieldConfig\n >\n ).map(async (fieldDefinition) => {\n if (fieldDefinition.unique) {\n const key = fieldDefinition.name;\n const fieldValue = value[key];\n const existing = await this.db\n .query(this.table)\n .withIndex(key, (q) => q.eq(key, value[key] as any))\n .unique();\n if (existing !== null && (id === undefined || existing._id !== id)) {\n throw new Error(\n `In table \"${\n this.table\n }\" cannot create a duplicate document with field \"${key}\" of value \\`${\n fieldValue as string\n }\\`, existing document with ID \"${\n existing._id as string\n }\" already has it.`\n );\n }\n }\n })\n );\n await Promise.all(\n Object.values(\n this.entDefinitions[this.table].edges as Record<string, EdgeConfig>\n ).map(async (edgeDefinition) => {\n if (\n edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"field\" &&\n edgeDefinition.unique\n ) {\n const key = edgeDefinition.field;\n if (value[key] === undefined) {\n return;\n }\n // Enforce uniqueness\n const existing = await this.db\n .query(this.table)\n .withIndex(key, (q) => q.eq(key, value[key] as any))\n .unique();\n if (existing !== null && (id === undefined || existing._id !== id)) {\n throw new Error(\n `In table \"${this.table}\" cannot create a duplicate 1:1 edge \"${\n edgeDefinition.name\n }\" to ID \"${value[key] as string}\", existing document with ID \"${\n existing._id as string\n }\" already has it.`\n );\n }\n }\n })\n );\n }\n\n fieldsOnly(\n value: Partial<\n WithEdgePatches<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ) {\n const fields: GenericDocument = {};\n Object.keys(value).forEach((key) => {\n const edgeDefinition: EdgeConfig | undefined = (\n this.entDefinitions[this.table].edges as EntsDataModel[Table][\"edges\"]\n )[key] as any;\n if (\n edgeDefinition === undefined\n // This doesn't do anything because the edge name doesn't match the field name\n // ||\n // (edgeDefinition.cardinality === \"single\" &&\n // edgeDefinition.type === \"field\")\n ) {\n fields[key] = value[key]!;\n }\n });\n return fields;\n }\n\n async checkReadAndWriteRule(\n operation: \"create\" | \"update\" | \"delete\",\n id: GenericId<Table> | undefined,\n value: Partial<GenericDocument> | undefined\n ) {\n if (id !== undefined) {\n const readPolicy = getReadRule(this.entDefinitions, this.table);\n if (readPolicy !== undefined) {\n const doc = await this.db.get(id);\n if (doc === null) {\n throw new Error(\n `Cannot update document with ID \"${id}\" in table \"${this.table} because it does not exist\"`\n );\n }\n const decision = await readPolicy(doc);\n if (!decision) {\n throw new Error(\n `Cannot update document with ID \"${id}\" from table \"${this.table}\"`\n );\n }\n }\n }\n const writePolicy = getWriteRule(this.entDefinitions, this.table);\n if (writePolicy === undefined) {\n return;\n }\n const ent =\n id === undefined\n ? undefined\n : entWrapper(\n (await this.db.get(id))!,\n this.db,\n this.entDefinitions,\n this.table\n );\n // Replace allows _id and _creationTime, but rules should not\n // rely on them.\n const { _id, _creationTime, ...safeValue } = value ?? {};\n const decision = await writePolicy({\n operation,\n ent: ent as any,\n value: value !== undefined ? (safeValue as any) : undefined,\n });\n if (!decision) {\n if (id === undefined) {\n throw new Error(\n `Cannot insert into table \"${this.table}\": \\`${JSON.stringify(\n value\n )}\\``\n );\n } else if (value === undefined) {\n throw new Error(\n `Cannot delete from table \"${this.table}\" with ID \"${id}\"`\n );\n } else {\n throw new Error(\n `Cannot update document with ID \"${id}\" in table \"${\n this.table\n }\" with: \\`${JSON.stringify(value)}\\``\n );\n }\n }\n }\n}\n\nexport type WithEdges<\n Document extends GenericDocument,\n Edges extends Record<string, GenericEdgeConfig>\n> = Document & {\n [key in keyof Edges as Edges[key][\"cardinality\"] extends \"single\"\n ? never\n : key]?: GenericId<Edges[key][\"to\"]>[];\n};\n\nexport type WithEdgePatches<\n Document extends GenericDocument,\n Edges extends Record<string, GenericEdgeConfig>\n> = Document & {\n [key in keyof Edges as Edges[key][\"cardinality\"] extends \"single\"\n ? never\n : key]?: {\n add?: GenericId<Edges[key][\"to\"]>[];\n remove?: GenericId<Edges[key][\"to\"]>[];\n };\n};\n\nexport type EdgeChanges = Record<\n string,\n {\n add?: GenericId<any>[] | GenericId<any>;\n remove?: GenericId<any>[] | GenericId<any>;\n removeEdges?: GenericId<any>[];\n }\n>;\n","import {\n DocumentByName,\n ExpressionOrValue,\n FieldTypeFromFieldPath,\n FilterBuilder,\n GenericDataModel,\n GenericDatabaseReader,\n GenericDatabaseWriter,\n GenericDocument,\n IndexNames,\n IndexRange,\n IndexRangeBuilder,\n NamedIndex,\n NamedSearchIndex,\n NamedTableInfo,\n PaginationOptions,\n PaginationResult,\n Query,\n QueryInitializer,\n SearchFilter,\n SearchFilterBuilder,\n SearchIndexNames,\n TableNamesInDataModel,\n WithOptionalSystemFields,\n WithoutSystemFields,\n} from \"convex/server\";\nimport { GenericId } from \"convex/values\";\nimport { EdgeConfig, GenericEntsDataModel } from \"./schema\";\nimport {\n EdgeChanges,\n WithEdgePatches,\n WithEdges,\n WriterImplBase,\n} from \"./writer\";\n\n// TODO: Figure out how to make get() variadic\n// type FieldTypes<\n//\n// Table extends TableNamesInDataModel<EntsDataModel>,\n// T extends string[]\n// > = {\n// [K in keyof T]: FieldTypeFromFieldPath<\n// DocumentByName<EntsDataModel, Table>,\n// T[K]\n// >;\n// };\n\nexport interface PromiseOrderedQueryOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[] | null\n > {\n filter(\n predicate: (\n q: FilterBuilder<NamedTableInfo<EntsDataModel, Table>>\n ) => ExpressionOrValue<boolean>\n ): this;\n\n map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ): Promise<TOutput[] | null>;\n\n // TODO: entWrapper for pagination\n paginate(\n paginationOpts: PaginationOptions\n ): Promise<PaginationResult<DocumentByName<EntsDataModel, Table>> | null>;\n\n take(n: number): PromiseEntsOrNull<EntsDataModel, Table>;\n\n first(): PromiseEntOrNull<EntsDataModel, Table>;\n\n unique(): PromiseEntOrNull<EntsDataModel, Table>;\n\n docs(): Promise<DocumentByName<EntsDataModel, Table>[] | null>;\n}\n\nexport interface PromiseQueryOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseOrderedQueryOrNull<EntsDataModel, Table> {\n // TODO: The index variant should not be allowed if\n // this query already used an index\n order(\n order: \"asc\" | \"desc\",\n indexName?: IndexNames<NamedTableInfo<EntsDataModel, Table>>\n ): PromiseOrderedQueryOrNull<EntsDataModel, Table>;\n}\n\nexport interface PromiseTableBase<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> {\n getMany<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n values: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >[]\n ): PromiseEntsOrNulls<EntsDataModel, Table>;\n getMany(ids: GenericId<Table>[]): PromiseEntsOrNulls<EntsDataModel, Table>;\n getManyX<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n values: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >[]\n ): PromiseEnts<EntsDataModel, Table>;\n getManyX(ids: GenericId<Table>[]): PromiseEnts<EntsDataModel, Table>;\n /**\n * Returns the string ID format for the ID in a given table, or null if the ID\n * is from a different table or is not a valid ID.\n *\n * This does not guarantee that the ID exists (i.e. `table(\"foo\").get(id)` may return `null`).\n *\n * @param tableName - The name of the table.\n * @param id - The ID string.\n */\n normalizeId(id: string): GenericId<Table> | null;\n}\n\nexport interface PromiseTable<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseQuery<EntsDataModel, Table>,\n PromiseTableBase<EntsDataModel, Table> {\n get<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n // TODO: Figure out how to make this variadic\n value0: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >\n ): PromiseEntOrNull<EntsDataModel, Table>;\n get(id: GenericId<Table>): PromiseEntOrNull<EntsDataModel, Table>;\n /**\n * Fetch a document from the DB using given index, throw if it doesn't exist.\n */\n getX<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n // TODO: Figure out how to make this variadic\n value0: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >\n ): PromiseEnt<EntsDataModel, Table>;\n /**\n * Fetch a document from the DB for a given ID, throw if it doesn't exist.\n */\n getX(id: GenericId<Table>): PromiseEnt<EntsDataModel, Table>;\n /**\n * Query by running a full text search against a search index.\n *\n * Search queries must always search for some text within the index's\n * `searchField`. This query can optionally add equality filters for any\n * `filterFields` specified in the index.\n *\n * Documents will be returned in relevance order based on how well they\n * match the search text.\n *\n * To learn about full text search, see [Indexes](https://docs.convex.dev/text-search).\n *\n * @param indexName - The name of the search index to query.\n * @param searchFilter - A search filter expression constructed with the\n * supplied {@link SearchFilterBuilder}. This defines the full text search to run\n * along with equality filtering to run within the search index.\n * @returns - A query that searches for matching documents, returning them\n * in relevancy order.\n */\n search<\n IndexName extends SearchIndexNames<NamedTableInfo<EntsDataModel, Table>>\n >(\n indexName: IndexName,\n searchFilter: (\n q: SearchFilterBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedSearchIndex<NamedTableInfo<EntsDataModel, Table>, IndexName>\n >\n ) => SearchFilter\n ): PromiseOrderedQuery<EntsDataModel, Table>;\n}\n\nexport interface PromiseOrderedQueryBase<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> {\n filter(\n predicate: (\n q: FilterBuilder<NamedTableInfo<EntsDataModel, Table>>\n ) => ExpressionOrValue<boolean>\n ): this;\n\n // TODO: entWrapper for pagination\n paginate(\n paginationOpts: PaginationOptions\n ): Promise<PaginationResult<DocumentByName<EntsDataModel, Table>>>;\n\n first(): PromiseEntOrNull<EntsDataModel, Table>;\n\n unique(): PromiseEntOrNull<EntsDataModel, Table>;\n\n docs(): Promise<DocumentByName<EntsDataModel, Table>[]>;\n}\n\nexport interface PromiseOrderedQuery<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n >,\n PromiseOrderedQueryBase<EntsDataModel, Table> {\n map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ): Promise<TOutput[]>;\n\n take(n: number): PromiseEnts<EntsDataModel, Table>;\n\n firstX(): PromiseEnt<EntsDataModel, Table>;\n\n uniqueX(): PromiseEnt<EntsDataModel, Table>;\n}\n\nexport interface PromiseQuery<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseOrderedQuery<EntsDataModel, Table> {\n order(\n order: \"asc\" | \"desc\",\n indexName?: IndexNames<NamedTableInfo<EntsDataModel, Table>>\n ): PromiseOrderedQuery<EntsDataModel, Table>;\n}\n\nclass PromiseQueryOrNullImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n >\n extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[] | null\n >\n implements PromiseQueryOrNull<EntsDataModel, Table>\n{\n constructor(\n protected db: GenericDatabaseReader<EntsDataModel>,\n protected entDefinitions: EntsDataModel,\n protected table: Table,\n protected retrieve: () => Promise<Query<\n NamedTableInfo<EntsDataModel, Table>\n > | null>\n ) {\n super(() => {});\n }\n\n filter(\n predicate: (\n q: FilterBuilder<NamedTableInfo<EntsDataModel, Table>>\n ) => ExpressionOrValue<boolean>\n ): any {\n return new PromiseQueryOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const query = await this.retrieve();\n if (query === null) {\n return null;\n }\n return query.filter(predicate);\n }\n );\n }\n\n async map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ) {\n const array = await this;\n if (array === null) {\n return [];\n }\n return await Promise.all(array.map(callbackFn));\n }\n\n order(\n order: \"asc\" | \"desc\",\n indexName?: IndexNames<NamedTableInfo<EntsDataModel, Table>>\n ): any {\n return new PromiseQueryOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const query = await this.retrieve();\n if (query === null) {\n return null;\n }\n if (indexName !== undefined) {\n return (\n query as QueryInitializer<NamedTableInfo<EntsDataModel, Table>>\n )\n .withIndex(indexName)\n .order(order);\n }\n return query.order(order) as any;\n }\n );\n }\n\n // TODO: RLS for pagination\n async paginate(\n paginationOpts: PaginationOptions\n ): Promise<PaginationResult<DocumentByName<EntsDataModel, Table>> | null> {\n const query = await this.retrieve();\n if (query === null) {\n return null;\n }\n return await query.paginate(paginationOpts);\n }\n\n take(n: number) {\n return new PromiseEntsOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n return await this._take(n);\n },\n false\n );\n }\n\n first() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this._take(1);\n if (docs === null) {\n return nullRetriever;\n }\n const [doc] = docs;\n return loadedRetriever(doc);\n },\n false\n );\n }\n\n firstX() {\n return new PromiseEntWriterImpl(\n this.db as any,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this._take(1);\n if (docs === null) {\n return nullRetriever;\n }\n const [doc] = docs;\n if (doc === undefined) {\n throw new Error(\"Query returned no documents\");\n }\n return loadedRetriever(doc);\n },\n false\n );\n }\n\n unique() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this._take(2);\n if (docs === null) {\n return nullRetriever;\n }\n if (docs.length === 0) {\n return nullRetriever;\n }\n if (docs.length === 2) {\n throw new Error(\"unique() query returned more than one result\");\n }\n const [doc] = docs;\n return loadedRetriever(doc);\n },\n false\n );\n }\n\n uniqueX() {\n return new PromiseEntWriterImpl(\n this.db as any,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this._take(2);\n if (docs === null) {\n return nullRetriever;\n }\n if (docs.length === 0) {\n throw new Error(\"Query returned no documents\");\n }\n if (docs.length === 2) {\n throw new Error(\"unique() query returned more than one result\");\n }\n const [doc] = docs;\n return loadedRetriever(doc);\n },\n true\n );\n }\n\n async docs() {\n const query = await this.retrieve();\n if (query === null) {\n return null;\n }\n const docs = await query.collect();\n return filterByReadRule(\n this.db,\n this.entDefinitions,\n this.table,\n docs,\n false\n );\n }\n\n then<\n TResult1 =\n | Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n | null,\n TResult2 = never\n >(\n onfulfilled?:\n | ((\n value:\n | Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n | null\n ) => TResult1 | PromiseLike<TResult1>)\n | undefined\n | null,\n onrejected?:\n | ((reason: any) => TResult2 | PromiseLike<TResult2>)\n | undefined\n | null\n ): Promise<TResult1 | TResult2> {\n return this.docs()\n .then((documents) =>\n documents === null\n ? null\n : documents.map((doc) =>\n entWrapper(doc, this.db, this.entDefinitions, this.table)\n )\n )\n .then(onfulfilled, onrejected);\n }\n\n async _take(n: number) {\n const query = await this.retrieve();\n if (query === null) {\n return null;\n }\n const readPolicy = getReadRule(this.entDefinitions, this.table);\n if (readPolicy === undefined) {\n return await query.take(n);\n }\n let numItems = n;\n const docs = [];\n let hasMore = true;\n const iterator = query[Symbol.asyncIterator]();\n while (hasMore && docs.length < n) {\n const page = [];\n for (let i = 0; i < numItems; i++) {\n const { done, value } = await iterator.next();\n if (done) {\n hasMore = false;\n break;\n }\n page.push(value);\n }\n docs.push(\n ...(await filterByReadRule(\n this.db,\n this.entDefinitions,\n this.table,\n page,\n false\n ))!.slice(0, n - docs.length)\n );\n numItems = Math.min(64, numItems * 2);\n }\n return docs;\n }\n}\n\nclass PromiseTableImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseQueryOrNullImpl<EntsDataModel, Table> {\n constructor(\n db: GenericDatabaseReader<EntsDataModel>,\n entDefinitions: EntsDataModel,\n table: Table\n ) {\n super(db, entDefinitions, table, async () => db.query(table));\n }\n\n get(...args: any[]) {\n return this.getImpl(args);\n }\n\n getX(...args: any[]) {\n return this.getImpl(args, true);\n }\n\n getMany(...args: any[]) {\n return this.getManyImpl(args);\n }\n\n getManyX(...args: any[]) {\n return this.getManyImpl(args, true);\n }\n\n getImpl(args: any[], throwIfNull = false) {\n return new PromiseEntWriterImpl(\n this.db as any,\n this.entDefinitions,\n this.table,\n args.length === 1\n ? async () => {\n const id = args[0] as GenericId<Table>;\n if (this.db.normalizeId(this.table, id) === null) {\n throw new Error(`Invalid id \\`${id}\\` for table \"${this.table}\"`);\n }\n return {\n id,\n doc: async () => {\n const doc = await this.db.get(id);\n if (throwIfNull && doc === null) {\n throw new Error(\n `Document not found with id \\`${id}\\` in table \"${this.table}\"`\n );\n }\n return doc;\n },\n } as any; // any because PromiseEntWriterImpl expects non-nullable\n }\n : async () => {\n const [indexName, value] = args;\n const doc = await this.db\n .query(this.table)\n .withIndex(indexName, (q) => q.eq(indexName, value))\n .unique();\n if (throwIfNull && doc === null) {\n throw new Error(\n `Table \"${this.table}\" does not contain document with field \"${indexName}\" = \\`${value}\\``\n );\n }\n return loadedRetriever(doc);\n },\n throwIfNull\n );\n }\n\n getManyImpl(args: any[], throwIfNull = false) {\n return new PromiseEntsOrNullImpl(\n this.db as any,\n this.entDefinitions as any,\n this.table,\n args.length === 1\n ? async () => {\n const ids = args[0] as GenericId<Table>[];\n ids.forEach((id) => {\n if (this.db.normalizeId(this.table, id) === null) {\n throw new Error(\n `Invalid id \\`${id}\\` for table \"${this.table}\"`\n );\n }\n });\n return await Promise.all(\n ids.map(async (id) => {\n const doc = await this.db.get(id);\n if (doc === null) {\n throw new Error(\n `Document not found with id \\`${id}\\` in table \"${this.table}\"`\n );\n }\n return doc;\n })\n );\n }\n : async () => {\n const [indexName, values] = args;\n return (await Promise.all(\n (values as any[]).map(async (value) => {\n const doc = await this.db\n .query(this.table)\n .withIndex(indexName, (q) => q.eq(indexName, value))\n .unique();\n if (throwIfNull && doc === null) {\n throw new Error(\n `Table \"${this.table}\" does not contain document with field \"${indexName}\" = \\`${value}\\``\n );\n }\n return doc;\n })\n )) as any;\n },\n throwIfNull\n );\n }\n\n normalizeId(id: string): GenericId<Table> | null {\n return this.db.normalizeId(this.table, id);\n }\n\n // normalizeId or throw\n normalizeIdX(id: string): GenericId<Table> {\n const normalized = this.normalizeId(id);\n if (normalized === null) {\n throw new Error(`Invalid id \\`${id}\\` for table \"${this.table}\"`);\n }\n return normalized;\n }\n\n withIndex(\n indexName: IndexNames<NamedTableInfo<EntsDataModel, Table>>,\n indexRange?: (\n q: IndexRangeBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedIndex<NamedTableInfo<EntsDataModel, Table>, typeof indexName>\n >\n ) => IndexRange\n ) {\n return new PromiseQueryOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const query = await this.retrieve();\n return (\n query as QueryInitializer<NamedTableInfo<EntsDataModel, Table>>\n ).withIndex(indexName, indexRange);\n }\n );\n }\n\n search<\n IndexName extends SearchIndexNames<NamedTableInfo<EntsDataModel, Table>>\n >(\n indexName: IndexName,\n searchFilter: (\n q: SearchFilterBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedSearchIndex<NamedTableInfo<EntsDataModel, Table>, IndexName>\n >\n ) => SearchFilter\n ) {\n return new PromiseQueryOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const query = await this.retrieve();\n return (\n query as QueryInitializer<NamedTableInfo<EntsDataModel, Table>>\n ).withSearchIndex(indexName, searchFilter) as any;\n }\n );\n }\n}\n\n// This lazy promise materializes objects, so chaining to this type of\n// lazy promise performs one operation for each\n// retrieved document in JavaScript, basically as if using `Promise.all()`.\nexport interface PromiseEntsOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[] | null\n > {\n // TODO: At this point there is nothing query specific here, and we can either:\n // 1. Return a generic lazy promise of the list.\n // 2. Not give any methods, because they might lead devs down the wrong path.\n // // This just returns the first retrieved document, it does not optimize\n // // the previous steps in the query.\n // first(): PromiseEntOrNull<EntsDataModel, Table>;\n // // This just returns the unique retrieved document, it does not optimize\n // // the previous steps in the query. Otherwise it behaves like db.query().unique().\n // unique(): PromiseEntOrNull<EntsDataModel, Table>;\n\n map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ): Promise<TOutput[] | null>;\n\n docs(): Promise<DocumentByName<EntsDataModel, Table>[] | null>;\n}\n\n// This lazy promise materializes objects, so chaining to this type of\n// lazy promise performs one operation for each\n// retrieved document in JavaScript, basically as if using\n// `Promise.all()`.\nexport interface PromiseEnts<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n > {\n // TODO: At this point there is nothing query specific here, and we can either:\n // 1. Return a generic lazy promise of the list.\n // 2. Not give any methods, because they might lead devs down the wrong path.\n // // This just returns the first retrieved document, it does not optimize\n // // the previous steps in the query.\n // first(): PromiseEntOrNull<EntsDataModel, Table>;\n // // This just returns the first retrieved document, or throws if there\n // // are no documents. It does not optimize the previous steps in the query.\n // firstX(): PromiseEnt<EntsDataModel, Table>;\n // // This just returns the unique retrieved document, it does not optimize\n // // the previous steps in the query. Otherwise it behaves like db.query().unique().\n // unique(): PromiseEntOrNull<EntsDataModel, Table>;\n // // This just returns the unique retrieved document, or throws if there\n // // are no documents. It does not optimize the previous steps in the query.\n // // Otherwise it behaves like db.query().unique().\n // uniqueX(): PromiseEnt<EntsDataModel, Table>;\n\n map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ): Promise<TOutput[]>;\n\n docs(): Promise<DocumentByName<EntsDataModel, Table>[]>;\n}\n\nclass PromiseEntsOrNullImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n >\n extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[] | null\n >\n implements PromiseEntsOrNull<EntsDataModel, Table>\n{\n constructor(\n private db: GenericDatabaseReader<EntsDataModel>,\n private entDefinitions: EntsDataModel,\n private table: Table,\n private retrieve: () => Promise<\n DocumentByName<EntsDataModel, Table>[] | null\n >,\n private throwIfNull: boolean\n ) {\n super(() => {});\n }\n\n async map<TOutput>(\n callbackFn: (\n value: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>,\n index: number,\n array: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n ) => Promise<TOutput> | TOutput\n ) {\n const array = await this;\n if (array === null) {\n return [];\n }\n return await Promise.all(array.map(callbackFn));\n }\n\n first() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this.retrieve();\n if (docs === null) {\n return nullRetriever;\n }\n return loadedRetriever(docs[0] ?? null);\n },\n false\n );\n }\n\n firstX() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this.retrieve();\n if (docs === null) {\n return nullRetriever;\n }\n const doc = docs[0] ?? undefined;\n if (doc === undefined) {\n throw new Error(\"Query returned no documents\");\n }\n return loadedRetriever(doc);\n },\n true\n );\n }\n\n unique() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this.retrieve();\n if (docs === null) {\n return nullRetriever;\n }\n if (docs.length > 1) {\n throw new Error(\"unique() query returned more than one result\");\n }\n return loadedRetriever(docs[0] ?? null);\n },\n false\n );\n }\n\n uniqueX() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const docs = await this.retrieve();\n if (docs === null) {\n return nullRetriever;\n }\n if (docs.length > 1) {\n throw new Error(\"unique() query returned more than one result\");\n }\n if (docs.length < 1) {\n throw new Error(\"unique() query returned no documents\");\n }\n return loadedRetriever(docs[0]);\n },\n true\n );\n }\n\n async docs() {\n const docs = await this.retrieve();\n return filterByReadRule(\n this.db,\n this.entDefinitions,\n this.table,\n docs,\n this.throwIfNull\n );\n }\n\n then<\n TResult1 =\n | Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n | null,\n TResult2 = never\n >(\n onfulfilled?:\n | ((\n value:\n | Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n | null\n ) => TResult1 | PromiseLike<TResult1>)\n | undefined\n | null,\n onrejected?:\n | ((reason: any) => TResult2 | PromiseLike<TResult2>)\n | undefined\n | null\n ): Promise<TResult1 | TResult2> {\n return this.docs()\n .then((docs) =>\n docs === null\n ? null\n : docs.map((doc) =>\n entWrapper(doc, this.db, this.entDefinitions, this.table)\n )\n )\n .then(onfulfilled, onrejected);\n }\n}\n\n// This lazy promise materializes objects, so chaining to this type of\n// lazy promise performs one operation for each\n// retrieved document in JavaScript, basically as if using\n// `Promise.all()`.\nexport interface PromiseEntsOrNulls<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n (Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel> | null)[]\n > {}\n\nexport interface PromiseEdgeEntsOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseEntsOrNull<EntsDataModel, Table> {\n /**\n * Returns whether there is an ent with given ID on the other side\n * the edge. Returns null if chained to a null result.\n * @param id The ID of the ent on the other end of the edge\n */\n has(id: GenericId<Table>): Promise<boolean | null>;\n}\n\nexport interface PromiseEdgeEnts<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseEnts<EntsDataModel, Table> {\n /**\n * Returns whether there is an ent with given ID on the other side\n * the edge.\n * @param id The ID of the ent on the other end of the edge\n */\n has(id: GenericId<Table>): Promise<boolean>;\n}\n\nclass PromiseEdgeOrNullImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n >\n extends PromiseEntsOrNullImpl<EntsDataModel, Table>\n implements PromiseEdgeEntsOrNull<EntsDataModel, Table>\n{\n constructor(\n db: GenericDatabaseReader<EntsDataModel>,\n entDefinitions: EntsDataModel,\n table: Table,\n private field: string,\n private retrieveRange: (\n indexRange: (\n q: IndexRangeBuilder<DocumentByName<EntsDataModel, Table>, any>\n ) => any\n ) => Promise<DocumentByName<EntsDataModel, Table>[] | null>\n ) {\n super(db, entDefinitions, table, () => retrieveRange((q) => q), false);\n }\n\n async has(id: GenericId<Table>) {\n const docs = await this.retrieveRange((q) => q.eq(this.field, id as any));\n return (docs?.length ?? 0) > 0;\n }\n}\n\nexport interface PromiseEntOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n > | null> {\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdgeOrNull<EntsDataModel, Table, Edge>;\n\n doc(): Promise<DocumentByName<EntsDataModel, Table> | null>;\n}\n\nexport interface PromiseEnt<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>\n > {\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdge<EntsDataModel, Table, Edge>;\n\n edgeX<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdgeOrThrow<EntsDataModel, Table, Edge>;\n\n doc(): Promise<DocumentByName<EntsDataModel, Table>>;\n}\n\nclass PromiseEntOrNullImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n >\n extends Promise<Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n > | null>\n implements PromiseEntOrNull<EntsDataModel, Table>\n{\n constructor(\n protected db: GenericDatabaseReader<EntsDataModel>,\n protected entDefinitions: EntsDataModel,\n protected table: Table,\n protected retrieve: DocRetriever<\n GenericId<Table> | null,\n DocumentByName<EntsDataModel, Table> | null\n >,\n protected throwIfNull: boolean\n ) {\n super(() => {});\n }\n\n async doc() {\n const { id, doc: getDoc } = await this.retrieve();\n if (id === null) {\n return null;\n }\n const doc = await getDoc();\n if (doc === null) {\n return null;\n }\n const readPolicy = getReadRule(this.entDefinitions, this.table);\n if (readPolicy !== undefined) {\n const decision = await readPolicy(\n entWrapper(doc, this.db, this.entDefinitions, this.table)\n );\n if (this.throwIfNull && !decision) {\n throw new Error(\n `Document cannot be read with id \\`${doc._id as string}\\` in table \"${\n this.table\n }\"`\n );\n }\n return decision ? doc : null;\n }\n return doc;\n }\n\n then<\n TResult1 = Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n > | null,\n TResult2 = never\n >(\n onfulfilled?:\n | ((\n value: Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n > | null\n ) => TResult1 | PromiseLike<TResult1>)\n | undefined\n | null,\n onrejected?:\n | ((reason: any) => TResult2 | PromiseLike<TResult2>)\n | undefined\n | null\n ): Promise<TResult1 | TResult2> {\n return this.doc()\n .then((doc) =>\n doc === null\n ? null\n : entWrapper(doc, this.db, this.entDefinitions, this.table)\n )\n .then(onfulfilled, onrejected);\n }\n\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(edge: Edge) {\n return this.edgeImpl(edge);\n }\n\n edgeX<Edge extends keyof EntsDataModel[Table][\"edges\"]>(edge: Edge) {\n return this.edgeImpl(edge, true);\n }\n\n edgeImpl<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge,\n throwIfNull = false\n ) {\n const edgeDefinition: EdgeConfig = (\n this.entDefinitions[this.table].edges as EntsDataModel[Table][\"edges\"]\n )[edge] as any;\n\n if (edgeDefinition.cardinality === \"multiple\") {\n if (edgeDefinition.type === \"ref\") {\n return new PromiseEdgeOrNullImpl(\n this.db,\n this.entDefinitions,\n edgeDefinition.to,\n edgeDefinition.ref,\n async (indexRange) => {\n const { id } = await this.retrieve();\n if (id === null) {\n return null;\n }\n const edgeDocs = await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.field, (q) =>\n indexRange(q.eq(edgeDefinition.field, id as any) as any)\n )\n .collect();\n return (\n await Promise.all(\n edgeDocs.map((edgeDoc) =>\n this.db.get(edgeDoc[edgeDefinition.ref] as any)\n )\n )\n ).filter(<TValue>(doc: TValue | null, i: number): doc is TValue => {\n if (doc === null) {\n throw new Error(\n `Dangling reference for edge \"${edgeDefinition.name}\" in ` +\n `table \"${this.table}\" for document with ID \"${id}\": ` +\n `Could not find a document with ID \"${\n edgeDocs[i][edgeDefinition.field] as string\n }\"` +\n ` in table \"${edgeDefinition.to}\" (edge document ID is \"${\n edgeDocs[i]._id as string\n }\").`\n );\n }\n return true;\n });\n }\n ) as any;\n }\n return new PromiseQueryOrNullImpl(\n this.db,\n this.entDefinitions,\n edgeDefinition.to,\n async () => {\n const { id } = await this.retrieve();\n if (id === null) {\n return null;\n }\n return this.db\n .query(edgeDefinition.to)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, id as any)\n );\n }\n ) as any;\n }\n\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n edgeDefinition.to,\n async () => {\n const { id, doc: getDoc } = await this.retrieve();\n if (id === null) {\n return nullRetriever;\n }\n\n if (edgeDefinition.type === \"ref\") {\n const otherDoc = await this.db\n .query(edgeDefinition.to)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, id as any)\n )\n .unique();\n if (throwIfNull && otherDoc === null) {\n throw new Error(\n `Edge \"${\n edgeDefinition.name\n }\" does not exist for document with ID \"${id as string}\"`\n );\n }\n return loadedRetriever(otherDoc);\n }\n const doc = (await getDoc())!;\n const otherId = doc[edgeDefinition.field] as any;\n return {\n id: otherId,\n doc: async () => {\n const otherDoc = await this.db.get(otherId);\n if (otherDoc === null) {\n throw new Error(\n `Dangling reference for edge \"${edgeDefinition.name}\" in ` +\n `table \"${this.table}\" for document with ID \"${id}\": ` +\n `Could not find a document with ID \"${otherId}\"` +\n ` in table \"${edgeDefinition.to}\".`\n );\n }\n return otherDoc;\n },\n };\n },\n throwIfNull\n ) as any;\n }\n}\n\nexport function entWrapper<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n>(\n fields: DocumentByName<EntsDataModel, Table>,\n db: GenericDatabaseReader<EntsDataModel>,\n entDefinitions: EntsDataModel,\n table: Table\n): Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel> {\n const doc = { ...fields };\n const queryInterface = new PromiseEntWriterImpl(\n db as any,\n entDefinitions as any,\n table,\n async () => ({ id: doc._id as any, doc: async () => doc }),\n // this `true` doesn't matter, the queryInterface cannot be awaited\n true\n );\n Object.defineProperty(doc, \"edge\", {\n value: (edge: any) => {\n return queryInterface.edge(edge);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.defineProperty(doc, \"edgeX\", {\n value: (edge: any) => {\n return queryInterface.edgeX(edge);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.defineProperty(doc, \"patch\", {\n value: (value: any) => {\n return queryInterface.patch(value);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.defineProperty(doc, \"replace\", {\n value: (value: any) => {\n return queryInterface.replace(value);\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.defineProperty(doc, \"delete\", {\n value: () => {\n return queryInterface.delete();\n },\n enumerable: false,\n writable: false,\n configurable: false,\n });\n Object.entries((entDefinitions as any)[table].defaults).map(\n ([field, value]) => {\n if (doc[field] === undefined) {\n (doc as any)[field] = value;\n }\n }\n );\n return doc as any;\n}\n\nexport function entsTableFactory<\n Database extends GenericDatabaseReader<any>,\n EntsDataModel extends GenericEntsDataModel\n>(\n db: Database,\n entDefinitions: EntsDataModel\n): Database extends GenericDatabaseWriter<any>\n ? EntsTableWriter<EntsDataModel>\n : EntsTable<EntsDataModel> {\n return (\n table: TableNamesInDataModel<EntsDataModel>,\n indexName?: string,\n indexRange?: any\n ) => {\n // Consider being strict here if people struggle with setup:\n // if (typeof db?.query !== \"function\") {\n // throw new Error(\n // `Expected context with \\`db\\`, got \\`${JSON.stringify(db)}\\``\n // );\n // }\n if (typeof table !== \"string\") {\n throw new Error(`Expected table name, got \\`${table as any}\\``);\n }\n if (indexName !== undefined) {\n return new PromiseTableImpl(db, entDefinitions, table).withIndex(\n indexName,\n indexRange\n );\n }\n if ((db as any).insert !== undefined) {\n return new PromiseTableWriterImpl(\n db as unknown as GenericDatabaseWriter<any>,\n entDefinitions,\n table\n ) as any;\n }\n return new PromiseTableImpl(db, entDefinitions, table);\n };\n}\n\ntype EntsTable<EntsDataModel extends GenericEntsDataModel> = {\n <\n Table extends TableNamesInDataModel<EntsDataModel>,\n IndexName extends IndexNames<NamedTableInfo<EntsDataModel, Table>>\n >(\n table: Table,\n indexName: IndexName,\n indexRange?: (\n q: IndexRangeBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedIndex<NamedTableInfo<EntsDataModel, Table>, IndexName>\n >\n ) => IndexRange\n ): PromiseQuery<EntsDataModel, Table>;\n <Table extends TableNamesInDataModel<EntsDataModel>>(\n table: Table\n ): PromiseTable<EntsDataModel, Table>;\n};\n\ntype EntsTableWriter<EntsDataModel extends GenericEntsDataModel> = {\n <\n Table extends TableNamesInDataModel<EntsDataModel>,\n IndexName extends IndexNames<NamedTableInfo<EntsDataModel, Table>>\n >(\n table: Table,\n indexName: IndexName,\n indexRange?: (\n q: IndexRangeBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedIndex<NamedTableInfo<EntsDataModel, Table>, IndexName>\n >\n ) => IndexRange\n ): PromiseTable<EntsDataModel, Table>;\n <Table extends TableNamesInDataModel<EntsDataModel>>(\n table: Table\n ): PromiseTableWriter<Table, EntsDataModel>;\n};\n\ndeclare class EntInstance<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> {\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdge<EntsDataModel, Table, Edge>;\n edgeX<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdgeOrThrow<EntsDataModel, Table, Edge>;\n}\n\nexport type Ent<\n Table extends TableNamesInDataModel<EntsDataModel>,\n Doc extends DocumentByName<EntsDataModel, Table>,\n EntsDataModel extends GenericEntsDataModel\n> = Doc & EntInstance<EntsDataModel, Table>;\n\nexport type GenericEnt<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> = Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>;\n\nexport type PromiseEdge<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n Edge extends keyof EntsDataModel[Table][\"edges\"]\n> = EntsDataModel[Table][\"edges\"][Edge][\"cardinality\"] extends \"multiple\"\n ? EntsDataModel[Table][\"edges\"][Edge][\"type\"] extends \"ref\"\n ? PromiseEdgeEnts<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : PromiseQuery<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : EntsDataModel[Table][\"edges\"][Edge][\"type\"] extends \"ref\"\n ? PromiseEntOrNull<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : PromiseEnt<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>;\n\nexport type PromiseEdgeOrThrow<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n Edge extends keyof EntsDataModel[Table][\"edges\"]\n> = EntsDataModel[Table][\"edges\"][Edge][\"cardinality\"] extends \"multiple\"\n ? EntsDataModel[Table][\"edges\"][Edge][\"type\"] extends \"ref\"\n ? PromiseEdgeEnts<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : PromiseQuery<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : EntsDataModel[Table][\"edges\"][Edge][\"type\"] extends \"ref\"\n ? PromiseEnt<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>\n : PromiseEnt<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>;\n\ntype PromiseEdgeOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>,\n Edge extends keyof EntsDataModel[Table][\"edges\"]\n> = EntsDataModel[Table][\"edges\"][Edge][\"cardinality\"] extends \"multiple\"\n ? EntsDataModel[Table][\"edges\"][Edge][\"type\"] extends \"ref\"\n ? PromiseEdgeEntsOrNull<\n EntsDataModel,\n EntsDataModel[Table][\"edges\"][Edge][\"to\"]\n >\n : PromiseQueryOrNull<\n EntsDataModel,\n EntsDataModel[Table][\"edges\"][Edge][\"to\"]\n >\n : PromiseEntOrNull<EntsDataModel, EntsDataModel[Table][\"edges\"][Edge][\"to\"]>;\n\nexport interface PromiseOrderedQueryWriter<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n EntWriter<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>[]\n >,\n PromiseOrderedQueryBase<EntsDataModel, Table> {\n map<TOutput>(\n callbackFn: (\n value: EntWriter<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n >,\n index: number,\n array: EntWriter<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n >[]\n ) => Promise<TOutput> | TOutput\n ): Promise<TOutput[]>;\n\n take(n: number): PromiseEntsWriter<EntsDataModel, Table>;\n\n firstX(): PromiseEntWriter<EntsDataModel, Table>;\n\n uniqueX(): PromiseEntWriter<EntsDataModel, Table>;\n}\n\nexport interface PromiseQueryWriter<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseOrderedQueryWriter<EntsDataModel, Table> {\n order(\n order: \"asc\" | \"desc\",\n indexName?: IndexNames<NamedTableInfo<EntsDataModel, Table>>\n ): PromiseOrderedQueryWriter<EntsDataModel, Table>;\n}\n\n// This lazy promise materializes objects, so chaining to this type of\n// lazy promise performs one operation for each\n// retrieved document in JavaScript, basically as if using\n// `Promise.all()`.\nexport interface PromiseEntsWriter<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseEnts<EntsDataModel, Table> {\n // This just returns the first retrieved document, or throws if there\n // are no documents. It does not optimize the previous steps in the query.\n firstX(): PromiseEntWriter<EntsDataModel, Table>;\n\n // This just returns the unique retrieved document, or throws if there\n // are no documents. It does not optimize the previous steps in the query.\n // Otherwise it behaves like db.query().unique().\n uniqueX(): PromiseEntWriter<EntsDataModel, Table>;\n}\n\nexport interface PromiseTableWriter<\n Table extends TableNamesInDataModel<EntsDataModel>,\n EntsDataModel extends GenericEntsDataModel\n> extends PromiseQueryWriter<EntsDataModel, Table>,\n PromiseTableBase<EntsDataModel, Table> {\n get<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n // TODO: Figure out how to make this variadic\n value0: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >\n ): PromiseEntWriterOrNull<EntsDataModel, Table>;\n get(id: GenericId<Table>): PromiseEntWriterOrNull<EntsDataModel, Table>;\n /**\n * Fetch a document from the DB using given index, throw if it doesn't exist.\n */\n getX<\n Indexes extends EntsDataModel[Table][\"indexes\"],\n Index extends keyof Indexes\n >(\n indexName: Index,\n // TODO: Figure out how to make this variadic\n value0: FieldTypeFromFieldPath<\n DocumentByName<EntsDataModel, Table>,\n Indexes[Index][0]\n >\n ): PromiseEnt<EntsDataModel, Table>;\n /**\n * Fetch a document from the DB for a given ID, throw if it doesn't exist.\n */\n getX(id: GenericId<Table>): PromiseEntWriter<EntsDataModel, Table>;\n /**\n * Query by running a full text search against a search index.\n *\n * Search queries must always search for some text within the index's\n * `searchField`. This query can optionally add equality filters for any\n * `filterFields` specified in the index.\n *\n * Documents will be returned in relevance order based on how well they\n * match the search text.\n *\n * To learn about full text search, see [Indexes](https://docs.convex.dev/text-search).\n *\n * @param indexName - The name of the search index to query.\n * @param searchFilter - A search filter expression constructed with the\n * supplied {@link SearchFilterBuilder}. This defines the full text search to run\n * along with equality filtering to run within the search index.\n * @returns - A query that searches for matching documents, returning them\n * in relevancy order.\n */\n search<\n IndexName extends SearchIndexNames<NamedTableInfo<EntsDataModel, Table>>\n >(\n indexName: IndexName,\n searchFilter: (\n q: SearchFilterBuilder<\n DocumentByName<EntsDataModel, Table>,\n NamedSearchIndex<NamedTableInfo<EntsDataModel, Table>, IndexName>\n >\n ) => SearchFilter\n ): PromiseOrderedQueryWriter<EntsDataModel, Table>;\n /**\n * Insert a new document into a table.\n *\n * @param table - The name of the table to insert a new document into.\n * @param value - The {@link Value} to insert into the given table.\n * @returns - {@link GenericId} of the new document.\n */\n // TODO: Chain methods to get the written document?\n insert(\n value: WithoutSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ): PromiseEntId<EntsDataModel, Table>;\n /**\n * Insert new documents into a table.\n *\n * @param table - The name of the table to insert a new document into.\n * @param value - The {@link Value} to insert into the given table.\n * @returns - {@link GenericId} of the new document.\n */\n // TODO: Chain methods to get the written documents?\n insertMany(\n values: WithoutSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >[]\n ): Promise<GenericId<Table>[]>;\n}\n\nclass PromiseTableWriterImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseTableImpl<EntsDataModel, Table> {\n private base: WriterImplBase<EntsDataModel, Table>;\n\n constructor(\n protected db: GenericDatabaseWriter<EntsDataModel>,\n entDefinitions: EntsDataModel,\n table: Table\n ) {\n super(db, entDefinitions, table);\n this.base = new WriterImplBase(db, entDefinitions, table);\n }\n\n insert(\n value: WithoutSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ) {\n return new PromiseEntIdImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n await this.base.checkReadAndWriteRule(\"create\", undefined, value);\n await this.base.checkUniqueness(value);\n const fields = this.base.fieldsOnly(value as any);\n const docId = await this.db.insert(this.table, fields as any);\n const edges: EdgeChanges = {};\n Object.keys(value).forEach((key) => {\n const edgeDefinition: EdgeConfig = (\n this.entDefinitions[this.table]\n .edges as EntsDataModel[Table][\"edges\"]\n )[key] as any;\n if (\n edgeDefinition === undefined ||\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"field\")\n ) {\n return;\n }\n if (edgeDefinition.cardinality === \"single\") {\n throw new Error(\"Cannot set 1:1 edge from optional end.\");\n }\n edges[key] = { add: value[key] };\n });\n await this.base.writeEdges(docId, edges);\n return docId;\n }\n );\n }\n\n // TODO: fluent API\n async insertMany(\n values: WithoutSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >[]\n ) {\n return await Promise.all(values.map((value) => this.insert(value)));\n }\n}\n\nexport interface PromiseEntWriterOrNull<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<EntWriter<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n > | null> {\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdgeOrNull<EntsDataModel, Table, Edge>;\n\n doc(): Promise<DocumentByName<EntsDataModel, Table> | null>;\n}\n\nexport interface PromiseEntWriter<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<\n EntWriter<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>\n > {\n edge<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdge<EntsDataModel, Table, Edge>;\n\n edgeX<Edge extends keyof EntsDataModel[Table][\"edges\"]>(\n edge: Edge\n ): PromiseEdgeOrThrow<EntsDataModel, Table, Edge>;\n\n doc(): Promise<DocumentByName<EntsDataModel, Table>>;\n\n /**\n * Patch this existing document, shallow merging it with the given partial\n * document.\n *\n * New fields are added. Existing fields are overwritten. Fields set to\n * `undefined` are removed.\n *\n * @param value - The partial {@link GenericDocument} to merge into this document. If this new value\n * specifies system fields like `_id`, they must match the document's existing field values.\n */\n patch(\n value: Partial<\n WithEdgePatches<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ): Promise<PromiseEntId<EntsDataModel, Table>>;\n\n /**\n * Replace the value of an existing document, overwriting its old value.\n *\n * @param value - The new {@link GenericDocument} for the document. This value can omit the system fields,\n * and the database will preserve them in.\n */\n replace(\n value: WithOptionalSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ): Promise<PromiseEntId<EntsDataModel, Table>>;\n\n /**\n * Delete this existing document.\n *\n * @param id - The {@link GenericId} of the document to remove.\n */\n delete(): Promise<GenericId<Table>>;\n}\n\nclass PromiseEntWriterImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends PromiseEntOrNullImpl<EntsDataModel, Table> {\n private base: WriterImplBase<EntsDataModel, Table>;\n\n constructor(\n protected db: GenericDatabaseWriter<EntsDataModel>,\n protected entDefinitions: EntsDataModel,\n protected table: Table,\n protected retrieve: DocRetriever<\n GenericId<Table> | null,\n DocumentByName<EntsDataModel, Table> | null\n >,\n protected throwIfNull: boolean\n ) {\n super(db, entDefinitions, table, retrieve, throwIfNull);\n this.base = new WriterImplBase(db, entDefinitions, table);\n }\n\n patch(\n value: Partial<\n WithEdgePatches<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ) {\n return new PromiseEntIdImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const { id: docId } = await this.retrieve();\n const id = docId!;\n await this.base.checkReadAndWriteRule(\"update\", id, value);\n await this.base.checkUniqueness(value, id);\n const fields = this.base.fieldsOnly(value);\n await this.db.patch(id, fields);\n\n const edges: EdgeChanges = {};\n await Promise.all(\n Object.keys(value).map(async (key) => {\n const edgeDefinition: EdgeConfig = (\n this.entDefinitions[this.table]\n .edges as EntsDataModel[Table][\"edges\"]\n )[key] as any;\n if (\n edgeDefinition === undefined ||\n (edgeDefinition.cardinality === \"single\" &&\n edgeDefinition.type === \"field\")\n ) {\n return;\n }\n if (edgeDefinition.cardinality === \"single\") {\n throw new Error(\"Cannot set 1:1 edge from optional end.\");\n // const existing = await this.db\n // .query(edgeDefinition.to)\n // .withIndex(edgeDefinition.ref, (q) =>\n // q.eq(edgeDefinition.ref, docId as any)\n // )\n // .unique();\n\n // edges[key] = {\n // add: value[key] as GenericId<any>,\n // remove: existing?._id as GenericId<any> | undefined,\n // };\n } else {\n edges[key] = value[key] as any;\n }\n })\n );\n await this.base.writeEdges(id, edges);\n return id;\n }\n );\n }\n\n replace(\n value: WithOptionalSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ) {\n return new PromiseEntIdImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const { id } = await this.retrieve();\n const docId = id!;\n await this.base.checkReadAndWriteRule(\"update\", docId, value);\n await this.base.checkUniqueness(value, docId);\n const fields = this.base.fieldsOnly(value as any);\n await this.db.replace(docId, fields as any);\n\n const edges: EdgeChanges = {};\n\n await Promise.all(\n Object.values(\n this.entDefinitions[this.table].edges as Record<string, EdgeConfig>\n ).map(async (edgeDefinition) => {\n const key = edgeDefinition.name;\n const idOrIds = value[key];\n if (edgeDefinition.cardinality === \"single\") {\n if (edgeDefinition.type === \"ref\") {\n const oldDoc = (await this.db.get(docId))!;\n if (oldDoc[key] !== undefined && oldDoc[key] !== idOrIds) {\n // This should be only allowed if the edge is optional\n // on the field side.\n // TODO: Write this info into the ref side of the edge in defineEntSchema.\n // TODO: Even better encode this in types so that replace\n // doesn't have this single edge in the signature.\n throw new Error(\"Cannot set 1:1 edge from optional end.\");\n // edges[key] = {\n // add: idOrIds as GenericId<any>,\n // remove: oldDoc[key] as GenericId<any> | undefined,\n // };\n }\n }\n } else {\n if (edgeDefinition.type === \"field\") {\n // TODO: Same issue around optionality as above\n const existing = (\n await this.db\n .query(edgeDefinition.to)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, docId as any)\n )\n .collect()\n ).map((doc) => doc._id);\n edges[key] = {\n add: idOrIds as GenericId<any>[],\n remove: existing as GenericId<any>[],\n };\n } else {\n const requested = new Set(idOrIds ?? []);\n const remove = (\n await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.field, (q) =>\n q.eq(edgeDefinition.field, docId as any)\n )\n .collect()\n )\n .map((doc) => [doc._id, doc[edgeDefinition.ref]] as const)\n .concat(\n edgeDefinition.symmetric\n ? (\n await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, docId as any)\n )\n .collect()\n ).map(\n (doc) => [doc._id, doc[edgeDefinition.field]] as const\n )\n : []\n )\n .filter(([_edgeId, otherId]) => {\n if (requested.has(otherId as any)) {\n requested.delete(otherId as any);\n return false;\n }\n return true;\n })\n .map(([edgeId]) => edgeId);\n edges[key] = {\n add: Array.from(requested) as GenericId<any>[],\n removeEdges: remove as GenericId<any>[],\n };\n }\n }\n })\n );\n await this.base.writeEdges(docId, edges);\n return docId;\n }\n );\n }\n\n async delete() {\n const { id: docId } = await this.retrieve();\n const id = docId!;\n await this.base.checkReadAndWriteRule(\"delete\", id, undefined);\n let memoized: GenericDocument | undefined = undefined;\n const oldDoc = async () => {\n if (memoized !== undefined) {\n return memoized;\n }\n return (memoized = (await this.db.get(id))!);\n };\n const edges: EdgeChanges = {};\n await Promise.all(\n Object.values(\n this.entDefinitions[this.table].edges as Record<string, EdgeConfig>\n ).map(async (edgeDefinition) => {\n const key = edgeDefinition.name;\n if (edgeDefinition.cardinality === \"single\") {\n if (edgeDefinition.type === \"ref\") {\n edges[key] = {\n remove: (await oldDoc())[key] as GenericId<any> | undefined,\n };\n }\n } else {\n if (edgeDefinition.type === \"field\") {\n const existing = (\n await this.db\n .query(edgeDefinition.to)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, id as any)\n )\n .collect()\n ).map((doc) => doc._id);\n edges[key] = { remove: existing as GenericId<any>[] };\n } else {\n const existing = (\n await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.field, (q) =>\n q.eq(edgeDefinition.field, id as any)\n )\n .collect()\n )\n .concat(\n edgeDefinition.symmetric\n ? await this.db\n .query(edgeDefinition.table)\n .withIndex(edgeDefinition.ref, (q) =>\n q.eq(edgeDefinition.ref, id as any)\n )\n .collect()\n : []\n )\n .map((doc) => doc._id);\n edges[key] = { removeEdges: existing as GenericId<any>[] };\n }\n }\n })\n );\n await this.db.delete(id);\n await this.base.writeEdges(id, edges);\n return id;\n }\n}\n\ndeclare class EntWriterInstance<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends EntInstance<EntsDataModel, Table> {\n /**\n * Patch this existing document, shallow merging it with the given partial\n * document.\n *\n * New fields are added. Existing fields are overwritten. Fields set to\n * `undefined` are removed.\n *\n * @param value - The partial {@link GenericDocument} to merge into this document. If this new value\n * specifies system fields like `_id`, they must match the document's existing field values.\n */\n patch(\n value: Partial<\n WithEdgePatches<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ): PromiseEntId<EntsDataModel, Table>;\n\n /**\n * Replace the value of this existing document, overwriting its old value.\n *\n * @param value - The new {@link GenericDocument} for the document. This value can omit the system fields,\n * and the database will preserve them in.\n */\n replace(\n value: WithOptionalSystemFields<\n WithEdges<\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel[Table][\"edges\"]\n >\n >\n ): PromiseEntId<EntsDataModel, Table>;\n\n /**\n * Delete this existing document.\n *\n * @param id - The {@link GenericId} of the document to remove.\n */\n delete(): Promise<GenericId<Table>>;\n}\n\n// This type is strange: The ordering is strange,\n// and the `Doc` would not have to be generic:\n// This is all just so that the type shows useful\n// informatin when hovering values.\ntype EntWriter<\n Table extends TableNamesInDataModel<EntsDataModel>,\n Doc extends DocumentByName<EntsDataModel, Table>,\n EntsDataModel extends GenericEntsDataModel\n> = Doc & EntWriterInstance<EntsDataModel, Table>;\n\nexport type GenericEntWriter<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> = EntWriter<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>;\n\nexport interface PromiseEntId<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n> extends Promise<GenericId<Table>> {\n get(): PromiseEntWriter<EntsDataModel, Table>;\n}\n\nclass PromiseEntIdImpl<\n EntsDataModel extends GenericEntsDataModel,\n Table extends TableNamesInDataModel<EntsDataModel>\n >\n extends Promise<GenericId<Table>>\n implements PromiseEntId<EntsDataModel, Table>\n{\n constructor(\n private db: GenericDatabaseWriter<EntsDataModel>,\n private entDefinitions: EntsDataModel,\n private table: Table,\n private retrieve: () => Promise<GenericId<Table>>\n ) {\n super(() => {});\n }\n\n get() {\n return new PromiseEntOrNullImpl(\n this.db,\n this.entDefinitions,\n this.table,\n async () => {\n const id = await this.retrieve();\n return { id, doc: async () => this.db.get(id) };\n },\n true\n ) as any;\n }\n\n then<TResult1 = GenericId<Table>, TResult2 = never>(\n onfulfilled?:\n | ((value: GenericId<Table>) => TResult1 | PromiseLike<TResult1>)\n | undefined\n | null,\n onrejected?:\n | ((reason: any) => TResult2 | PromiseLike<TResult2>)\n | undefined\n | null\n ): Promise<TResult1 | TResult2> {\n return this.retrieve().then(onfulfilled, onrejected);\n }\n}\n\nexport type DocRetriever<ID, Doc> = () => Promise<{\n id: ID;\n doc: () => Promise<Doc>;\n}>;\n\nconst nullRetriever = {\n id: null,\n doc: async () => null,\n};\n\n// function idRetriever<\n// DataModel extends GenericDataModel,\n// Table extends TableNamesInDataModel<DataModel>\n// >(db: GenericDatabaseReader<DataModel>, id: GenericId<Table>) {\n// return {\n// id,\n// doc: async () => db.get(id),\n// };\n// }\n\nfunction loadedRetriever<\n DataModel extends GenericDataModel,\n Table extends TableNamesInDataModel<DataModel>\n>(doc: DocumentByName<DataModel, Table> | null) {\n return {\n id: (doc?._id ?? null) as GenericId<Table> | null,\n doc: async () => doc,\n };\n}\n\ntype Rules = Record<string, RuleConfig>;\n\ntype RuleConfig = {\n read?: (doc: GenericDocument) => Promise<boolean>;\n write?: (\n args:\n | {\n operation: \"create\";\n ent: undefined;\n value: WithoutSystemFields<GenericDocument>;\n }\n | {\n operation: \"update\";\n ent: Ent<any, GenericDocument, any>;\n value: Partial<WithoutSystemFields<GenericDocument>>;\n }\n | {\n operation: \"delete\";\n ent: Ent<any, GenericDocument, any>;\n value: undefined;\n }\n ) => Promise<boolean>;\n};\n\nexport function addEntRules<EntsDataModel extends GenericEntsDataModel>(\n entDefinitions: EntsDataModel,\n rules: {\n [Table in keyof EntsDataModel]?: Table extends TableNamesInDataModel<EntsDataModel>\n ? {\n read?: (\n ent: Ent<Table, DocumentByName<EntsDataModel, Table>, EntsDataModel>\n ) => Promise<boolean>;\n write?: (\n args:\n | {\n operation: \"create\";\n ent: undefined;\n value: WithoutSystemFields<\n DocumentByName<EntsDataModel, Table>\n >;\n }\n | {\n operation: \"update\";\n ent: Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n >;\n value: Partial<\n WithoutSystemFields<DocumentByName<EntsDataModel, Table>>\n >;\n }\n | {\n operation: \"delete\";\n ent: Ent<\n Table,\n DocumentByName<EntsDataModel, Table>,\n EntsDataModel\n >;\n value: undefined;\n }\n ) => Promise<boolean>;\n }\n : never;\n }\n): EntsDataModel {\n return { ...entDefinitions, rules };\n}\n\nasync function filterByReadRule(\n db: GenericDatabaseReader<any>,\n entDefinitions: GenericEntsDataModel,\n table: string,\n docs: GenericDocument[] | null,\n throwIfNull: boolean\n) {\n if (docs === null) {\n return null;\n }\n const readPolicy = getReadRule(entDefinitions, table);\n if (readPolicy !== undefined) {\n const decisions = await Promise.all(\n docs.map(async (doc) => {\n const decision = await readPolicy(\n entWrapper(doc, db, entDefinitions, table)\n );\n if (throwIfNull && !decision) {\n throw new Error(\n `Document cannot be read with id \\`${\n doc._id as string\n }\\` in table \"${table}\"`\n );\n }\n return decision;\n })\n );\n return docs.filter((_, i) => decisions[i]);\n }\n return docs;\n}\n\nexport function getReadRule(\n entDefinitions: GenericEntsDataModel,\n table: string\n) {\n return (entDefinitions.rules as Rules)?.[table]?.read;\n}\n\nexport function getWriteRule(\n entDefinitions: GenericEntsDataModel,\n table: string\n) {\n return (entDefinitions.rules as Rules)?.[table]?.write;\n}\n"],"mappings":"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","names":["decision"]}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "convex-ents",
3
+ "version": "0.1.0",
4
+ "description": "Relations, default values, unique fields, RLS for Convex",
5
+ "keywords": [
6
+ "relations",
7
+ "orm",
8
+ "edges",
9
+ "schema",
10
+ "convex"
11
+ ],
12
+ "homepage": "https://labs.convex.dev/convex-ents",
13
+ "bugs": "https://github.com/xixixao/convex-ents/issues",
14
+ "repository": "https://github.com/xixixao/convex-ents",
15
+ "license": "Apache-2.0",
16
+ "author": "xixixao",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "scripts": {
23
+ "build": "npx tsup src --dts --sourcemap --clean",
24
+ "docs": "cd docs && npm run dev",
25
+ "lint": "tsc && eslint . && cd test && npm run lint",
26
+ "prepublishOnly": "npm run build",
27
+ "test": "cd test && npm run test"
28
+ },
29
+ "peerDependencies": {
30
+ "convex": "^1.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "20.6.0",
34
+ "@typescript-eslint/eslint-plugin": "^6.18.1",
35
+ "eslint": "8.49.0",
36
+ "npm-run-all": "^4.1.5",
37
+ "tsup": "^8.0.1",
38
+ "typescript": "^5.3.3"
39
+ }
40
+ }