diff --git a/README.md b/README.md index 5a03c7d..d14d263 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Odin +# Odin Odin is an implementation of [**Active Record**](https://en.wikipedia.org/wiki/Active_record_pattern) pattern in [**TypeScript**](https://typescriptlang.com). [![NPM Version](https://img.shields.io/npm/v/@foxify/odin.svg)](https://www.npmjs.com/package/@foxify/odin) -[![Node Version](https://img.shields.io/node/v/foxify.svg)](https://nodejs.org) +[![Node Version](https://img.shields.io/node/v/@foxify/odin.svg)](https://nodejs.org) [![TypeScript Version](https://img.shields.io/npm/types/@foxify/odin.svg)](https://www.typescriptlang.org) [![Tested With Jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://github.com/facebook/jest) [![Pull Requests](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/foxifyjs/odin/pulls) @@ -22,12 +22,11 @@ Odin is an implementation of [**Active Record**](https://en.wikipedia.org/wiki/A ## Table of Content -- [Odin](#odin) - - [Installation](#installation) - - [Usage](#usage) - - [Features](#features) - - [TODO (RoadMap to version 1.0.0)](#todo-roadmap-to-version-100) - - [Support](#support) +- [Installation](#installation) +- [Usage](#usage) +- [Features](#features) +- [TODO (RoadMap to version 1.0.0)](#todo-roadmap-to-version-100) +- [Support](#support) ## Installation diff --git a/src/utils.ts b/src/utils.ts index 35ff802..dffa3f9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,6 @@ import * as callerId from "caller-id"; import { ObjectId } from "mongodb"; +import { date, object, string } from "prototyped.js/es6/methods"; import * as Odin from "."; export * from "prototyped.js/es6/methods"; @@ -44,7 +45,7 @@ export function define( * getGetterName("first_name"); // getFirstNameAttribute */ export const getGetterName = (key: string) => - `get${exports.string.capitalize(exports.string.camelCase(key))}Attribute`; + `get${string.capitalize(string.camelCase(key))}Attribute`; /** * Generates setter name for the given key @@ -54,7 +55,7 @@ export const getGetterName = (key: string) => * getSetterName("first_name"); // setFirstNameAttribute */ export const getSetterName = (key: string) => - `set${exports.string.capitalize(exports.string.camelCase(key))}Attribute`; + `set${string.capitalize(string.camelCase(key))}Attribute`; /** * Generates collection name for the given name @@ -64,9 +65,9 @@ export const getSetterName = (key: string) => * makeCollectionName("user_account"); // user_accounts */ export const makeCollectionName = (name: string) => { - const key = exports.string.snakeCase(name).split("_"); + const key = string.snakeCase(name).split("_"); - key.push(exports.string.pluralize(key.pop() as string)); + key.push(string.pluralize(key.pop() as string)); return key.join("_"); }; @@ -81,7 +82,7 @@ export const makeCollectionName = (name: string) => { export const makeCollectionType = (name: string) => { const key = name.split("_"); - key.push(exports.string.pluralize(key.pop() as string, 1)); + key.push(string.pluralize(key.pop() as string, 1)); return key.join("_"); }; @@ -134,3 +135,41 @@ export const prepareValue = (field: string, value: any) => { return new ObjectId(value); }; + +export const prepareToRead = (document: any): any => { + if ( + !document || + !(object.isObject(document) || typeof document === "object") || + date.isDate(document) + ) return document; + + if (Array.isArray(document)) return document.map(prepareToRead); + + return object.mapValues( + object.mapKeys(document, (value, key) => key === "_id" ? "id" : key), + (value, key) => isID(key as string) ? + value && value.toString() : + prepareToRead(value) + ); +}; + +export const prepareToStore = (document: any): any => { + if ( + !document || + !(object.isObject(document) || typeof document === "object") || + date.isDate(document) + ) return document; + + if (Array.isArray(document)) return document.map(prepareToStore); + + return object.mapValues( + object.mapKeys(document, (value, key) => key === "id" ? "_id" : key), + (value, key) => isID(key as string) ? + ( + ObjectId.isValid(value) ? + new ObjectId(value) : + prepareToStore(value) + ) : + prepareToStore(value) + ); +}; diff --git a/test/DB.ts b/test/DB.ts index 1df7172..11d34e3 100644 --- a/test/DB.ts +++ b/test/DB.ts @@ -200,7 +200,7 @@ test("db.first (callback style)", (done) => { }); }); -test("db.where", (done) => { +test("db.where [simple]", (done) => { DB.collection(COLLECTION).where("name", "foo").get((err, res) => { expect(err).toBe(null); expect(res).toEqual(ITEMS.filter(({ name }) => name === "foo")); @@ -209,7 +209,18 @@ test("db.where", (done) => { }); }); -test("db.orWhere", (done) => { +test("db.where [complex]", (done) => { + DB.collection(COLLECTION) + .where(q => q.where("name", "foo")) + .get((err, res) => { + expect(err).toBe(null); + expect(res).toEqual(ITEMS.filter(({ name }) => name === "foo")); + + done(); + }); +}); + +test("db.orWhere [simple]", (done) => { DB.collection(COLLECTION).where("name", "foo").orWhere("style", "async").get((err, res) => { expect(err).toBe(null); expect(res).toEqual(ITEMS.filter(({ name, style }) => name === "foo" || style === "async")); @@ -218,6 +229,18 @@ test("db.orWhere", (done) => { }); }); +test("db.orWhere [complex]", (done) => { + DB.collection(COLLECTION) + .where(q => q.where("name", "foo")) + .orWhere(q => q.where("style", "async")) + .get((err, res) => { + expect(err).toBe(null); + expect(res).toEqual(ITEMS.filter(({ name, style }) => name === "foo" || style === "async")); + + done(); + }); +}); + test("db.whereLike", (done) => { DB.collection(COLLECTION).whereLike("name", "foo").get((err, res) => { expect(err).toBe(null);