diff --git a/examples/whyLesan/performance.ts b/examples/whyLesan/performance.ts new file mode 100644 index 00000000..471c1eb9 --- /dev/null +++ b/examples/whyLesan/performance.ts @@ -0,0 +1,354 @@ +import { + ActFn, + lesan, + MongoClient, + number, + object, + ObjectId, + objectIdValidation, + RelationDataType, + RelationSortOrderType, + string, +} from "../../mod.ts"; + +const coreApp = lesan(); + +const client = await new MongoClient("mongodb://127.0.0.1:27017/").connect(); + +const db = client.db("performance"); + +coreApp.odm.setDb(db); + +// ================== MODEL SECTION ================== +// ------------------ Country Model ------------------ +const pure = { + name: string(), + population: number(), + abb: string(), +}; +const countryRelations = {}; +const countries = coreApp.odm.newModel( + "country", + pure, + countryRelations, +); + +// ------------------ Province Model ------------------ +const provinceRelations = { + country: { + optional: false, + schemaName: "country", + type: "single" as RelationDataType, + relatedRelations: { + provinces: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + provincesByPopulation: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "population", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, +}; + +const provinces = coreApp.odm.newModel( + "province", + pure, + provinceRelations, +); + +// ------------------ City Model ------------------ +const cityRelations = { + country: { + optional: false, + schemaName: "country", + type: "single" as RelationDataType, + relatedRelations: { + cities: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + citiesByPopulation: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "population", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, + province: { + optional: false, + schemaName: "province", + type: "single" as RelationDataType, + relatedRelations: { + cities: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + citiesByPopulation: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "population", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, +}; + +const cities = coreApp.odm.newModel( + "city", + pure, + cityRelations, +); + +// ------------------ User Model ------------------ +const userPure = { + name: string(), + family: string(), + age: number(), +}; + +const userRelations = { + country: { + optional: false, + schemaName: "country", + type: "single" as RelationDataType, + relatedRelations: { + users: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + usersByAge: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "age", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, + province: { + optional: false, + schemaName: "province", + type: "single" as RelationDataType, + relatedRelations: { + users: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + usersByAge: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "age", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, + city: { + optional: false, + schemaName: "city", + type: "single" as RelationDataType, + relatedRelations: { + users: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "_id", + order: "desc" as RelationSortOrderType, + }, + }, + usersByAge: { + type: "multiple" as RelationDataType, + limit: 50, + sort: { + field: "age", + order: "desc" as RelationSortOrderType, + }, + }, + }, + }, +}; + +const users = coreApp.odm.newModel( + "user", + userPure, + userRelations, +); + +// ================== FUNCTIONS SECTION ================== +// ------------------ Country Founctions ------------------ +// ------------------ Add Country ------------------ +const addCountryValidator = () => { + return object({ + set: object(pure), + get: coreApp.schemas.selectStruct("country", 1), + }); +}; + +const addCountry: ActFn = async (body) => { + const { name, population, abb } = body.details.set; + return await countries.insertOne({ + doc: { + name, + population, + abb, + }, + projection: body.details.get, + }); +}; + +coreApp.acts.setAct({ + schema: "country", + actName: "addCountry", + validator: addCountryValidator(), + fn: addCountry, +}); + +// ------------------ get Countries ------------------ +const getCountriesValidator = () => { + return object({ + set: object({}), + get: coreApp.schemas.selectStruct("country", 2), + }); +}; +const getCountries: ActFn = async (body) => { + const { + set, + get, + } = body.details; + + return await countries + .aggregation({ + pipeline: [], + projection: get, + }) + .toArray(); +}; + +coreApp.acts.setAct({ + schema: "country", + actName: "getCountries", + validator: getCountriesValidator(), + fn: getCountries, +}); + +// ------------------ Province Founctions ------------------ +// ------------------ Add Propvince ------------------ +const addProvinceValidator = () => { + return object({ + set: object({ + ...pure, + countryId: objectIdValidation, + }), + get: coreApp.schemas.selectStruct("province", 1), + }); +}; + +const addProvince: ActFn = async (body) => { + const { name, population, abb, countryId } = body.details.set; + return await provinces.insertOne({ + doc: { + name, + population, + abb, + }, + relations: { + country: { + _ids: new ObjectId(countryId), + relatedRelations: { + provinces: true, + provincesByPopulation: true, + }, + }, + }, + projection: body.details.get, + }); +}; + +coreApp.acts.setAct({ + schema: "province", + actName: "addProvince", + validator: addProvinceValidator(), + fn: addProvince, +}); + +// ------------------ City Founctions ------------------ +// ------------------ Add City ------------------ +const addCityValidator = () => { + return object({ + set: object({ + ...pure, + countryId: objectIdValidation, + provinceId: objectIdValidation, + }), + get: coreApp.schemas.selectStruct("city", 1), + }); +}; + +const addCity: ActFn = async (body) => { + const { name, population, abb, countryId, provinceId } = body.details.set; + + return await cities.insertOne({ + doc: { + name, + population, + abb, + }, + relations: { + country: { + _ids: new ObjectId(countryId), + relatedRelations: { + cities: true, + citiesByPopulation: true, + }, + }, + province: { + _ids: new ObjectId(provinceId), + relatedRelations: { + cities: true, + citiesByPopulation: true, + }, + }, + }, + projection: body.details.get, + }); +}; + +coreApp.acts.setAct({ + schema: "city", + actName: "addCity", + validator: addCityValidator(), + fn: addCity, +}); diff --git a/src/models/pure/getPureModel.ts b/src/models/pure/getPureModel.ts index bbee2606..9ef0f9d3 100644 --- a/src/models/pure/getPureModel.ts +++ b/src/models/pure/getPureModel.ts @@ -1,4 +1,5 @@ import { throwError } from "../../utils/throwError.ts"; +import { getPureSchema } from "../mod.ts"; import { schemaFns, TSchemas } from "../mod.ts"; /** @@ -8,6 +9,6 @@ import { schemaFns, TSchemas } from "../mod.ts"; export const getPureModel = (schemasObj: TSchemas, name: string) => { const schemas = schemaFns(schemasObj).getSchemas(); return schemas[name] - ? schemas[name].pure + ? getPureSchema(schemas, name) : throwError(`Schema ${name} is not exist in the Schema Object`); }; diff --git a/src/models/schema/createStruct.ts b/src/models/schema/createStruct.ts index eefbf49b..13abdff0 100644 --- a/src/models/schema/createStruct.ts +++ b/src/models/schema/createStruct.ts @@ -1,7 +1,7 @@ import { assign, object } from "../../npmDeps.ts"; import { createEmbedded } from "./createEmbedded.ts"; import { getSchema } from "./getSchema.ts"; -import { TSchemas } from "./mod.ts"; +import { getPureSchema, TSchemas } from "./mod.ts"; /** * create struct features, struct feature is used for create client of db. @@ -29,9 +29,8 @@ import { TSchemas } from "./mod.ts"; * ), */ export const createStruct = (schemas: TSchemas, schemaName: string) => { - const schema = getSchema(schemas, schemaName); return assign( - object(schema.pure), + object(getPureSchema(schemas, schemaName)), object(createEmbedded(schemas, schemaName)), ); }; diff --git a/src/models/schema/getFlattenPureFromRelations.ts b/src/models/schema/getFlattenPureFromRelations.ts index beaa4194..c5762259 100644 --- a/src/models/schema/getFlattenPureFromRelations.ts +++ b/src/models/schema/getFlattenPureFromRelations.ts @@ -1,11 +1,12 @@ import { object } from "../../npmDeps.ts"; +import { getPureSchema } from "./getPureSchema.ts"; import { getSchema } from "./getSchema.ts"; import { TSchemas } from "./mod.ts"; export const getFlattenPureFromRelations = ( schemas: TSchemas, schemaName: string, - relationType: "MainRelations" | "RelatedRelations" | "All" + relationType: "MainRelations" | "RelatedRelations" | "All", ) => { const schema = getSchema(schemas, schemaName); let pureSchemas = {}; @@ -15,7 +16,7 @@ export const getFlattenPureFromRelations = ( pureSchemas = { ...pureSchemas, [property]: object( - schemas[schema.mainRelations[property].schemaName]?.pure + getPureSchema(schemas, schema.mainRelations[property].schemaName), ), }; } @@ -25,7 +26,7 @@ export const getFlattenPureFromRelations = ( pureSchemas = { ...pureSchemas, [property]: object( - schemas[schema.relatedRelations[property].schemaName]?.pure + getPureSchema(schemas, schema.relatedRelations[property].schemaName), ), }; } diff --git a/src/models/schema/getPureFromMainRelations.ts b/src/models/schema/getPureFromMainRelations.ts index 15b372fa..fd14951a 100644 --- a/src/models/schema/getPureFromMainRelations.ts +++ b/src/models/schema/getPureFromMainRelations.ts @@ -1,6 +1,6 @@ import { array, object, optional } from "../../npmDeps.ts"; import { getSchema } from "./getSchema.ts"; -import { TSchemas } from "./mod.ts"; +import { getPureSchema, TSchemas } from "./mod.ts"; export const getPureFromMainRelations = ( schemas: TSchemas, @@ -15,15 +15,23 @@ export const getPureFromMainRelations = ( [property]: schema.mainRelations[property].type === "single" ? schema.mainRelations[property].optional === true ? optional( - object(schemas[schema.mainRelations[property].schemaName]?.pure), + object( + getPureSchema(schemas, schema.mainRelations[property].schemaName), + ), + ) + : object( + getPureSchema(schemas, schema.mainRelations[property].schemaName), ) - : object(schemas[schema.mainRelations[property].schemaName]?.pure) : schema.mainRelations[property].optional === true ? optional(array( - object(schemas[schema.mainRelations[property].schemaName]?.pure), + object( + getPureSchema(schemas, schema.mainRelations[property].schemaName), + ), )) : array( - object(schemas[schema.mainRelations[property].schemaName]?.pure), + object( + getPureSchema(schemas, schema.mainRelations[property].schemaName), + ), ), }; } diff --git a/src/models/schema/getPureFromRelatedRelations.ts b/src/models/schema/getPureFromRelatedRelations.ts index 11883e11..ce255761 100644 --- a/src/models/schema/getPureFromRelatedRelations.ts +++ b/src/models/schema/getPureFromRelatedRelations.ts @@ -1,3 +1,4 @@ +import { getPureSchema } from "https://deno.land/x/lesan@v0.0.98/src/models/mod.ts"; import { array, object } from "../../npmDeps.ts"; import { getSchema } from "./getSchema.ts"; import { TSchemas } from "./mod.ts"; @@ -32,7 +33,9 @@ export const getPureFromRelatedRelations = ( pureSchemas = { ...pureSchemas, [property]: array( - object(schemas[schema.relatedRelations[property].schemaName]?.pure), + object( + getPureSchema(schemas, schema.relatedRelations[property].schemaName), + ), ), }; } diff --git a/src/models/schema/getPureSchema.ts b/src/models/schema/getPureSchema.ts index 0e57ce0a..503a79be 100644 --- a/src/models/schema/getPureSchema.ts +++ b/src/models/schema/getPureSchema.ts @@ -17,5 +17,11 @@ export const getPureSchema = (schemas: TSchemas, schemaName: string) => { throw new Error(`Schema ${schemaName} not found`); } - return schema.pure; + const pure = schema.pure; + + if (schema.options && schema.options.excludes) { + schema.options.excludes.forEach((p) => delete pure[p]); + } + + return pure; }; diff --git a/src/models/types.ts b/src/models/types.ts index 15202939..4f8fb3cd 100644 --- a/src/models/types.ts +++ b/src/models/types.ts @@ -113,4 +113,5 @@ export interface IModel { relations: Record; mainRelations: Record; relatedRelations: Record; + options?: { excludes?: (string | number)[] }; } diff --git a/src/odm/mod.ts b/src/odm/mod.ts index 8f297c98..a61e4c66 100644 --- a/src/odm/mod.ts +++ b/src/odm/mod.ts @@ -1,9 +1,9 @@ import { Database } from "../deps.ts"; import { - IPureFields, - IRelationsFileds, - TRelation, - TSchemas, + IPureFields, + IRelationsFileds, + TRelation, + TSchemas, } from "../models/mod.ts"; import { schemaFns } from "../models/mod.ts"; import { assert, enums } from "../npmDeps.ts"; @@ -11,37 +11,38 @@ import { throwError } from "../utils/throwError.ts"; import { newModel } from "./newModel/mod.ts"; export const odm = (schemasObj: TSchemas) => { - let mongoDb: Database; + let mongoDb: Database; - const setDb = (db: Database) => (mongoDb = db); + const setDb = (db: Database) => (mongoDb = db); - const getDbClient = () => mongoDb; + const getDbClient = () => mongoDb; - const getCollection = (collection: string) => { - const db = getDbClient(); - const getSchemas = enums(schemaFns(schemasObj).getSchemasKeys()); - assert(collection, getSchemas); - return db - ? db.collection(collection) - : throwError("No database connection"); - }; + const getCollection = (collection: string) => { + const db = getDbClient(); + const getSchemas = enums(schemaFns(schemasObj).getSchemasKeys()); + assert(collection, getSchemas); + return db + ? db.collection(collection) + : throwError("No database connection"); + }; - return { - setDb, - getCollection, - newModel: ( - name: string, - pureFields: PF, - relations: TR, - ) => - newModel( - mongoDb, - schemasObj, - name, - pureFields, - relations, - ), - }; + return { + setDb, + getCollection, + newModel: ( + name: string, + pureFields: PF, + relations: TR, + options?: { excludes?: Partial<(keyof PF)>[] }, + ) => newModel( + mongoDb, + schemasObj, + name, + pureFields, + relations, + options, + ), + }; }; export * from "./utils/mod.ts"; diff --git a/src/odm/newModel/mod.ts b/src/odm/newModel/mod.ts index e42fe63d..58f4c7b5 100644 --- a/src/odm/newModel/mod.ts +++ b/src/odm/newModel/mod.ts @@ -40,6 +40,7 @@ export const newModel = < name: string, pureFields: PF, relations: TR, + options?: { excludes?: Partial<(keyof PF)>[] }, ) => { type InferPureFieldsType = { [key in keyof PF]?: Infer; @@ -85,6 +86,7 @@ export const newModel = < relations, mainRelations, relatedRelations: {}, + options: (options as { excludes?: (string | number)[] }), }; interface IFindModelInputs {