diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index daf9c0c..59660cd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,4 +1,4 @@ -# For most projects, this workflow file will not need changing; you simply need +# For most projects, this workflow file will not need changing you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, diff --git a/README.md b/README.md index c561144..d9517fa 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,20 @@ ![](https://raw.githubusercontent.com/Tarasikee/tinydb/v1.0.0-alpha/images/Logo1.png) - # TinyDB Tiny, Powerful, Beautiful ## Contents: - - [Motivation](#motivation) - [Let's start](#lets-start) # Motivation - Let's say you want to build a small project that doesn't require a bulky relational database such as Postgres or MySQL. Instead, you want to use a simple, in-memory database that will cover your needs. -That's where TykeDB comes in. TykeDB is a tiny, simple, and fast in-memory database that you can use to store and retrieve data. It has all the features of a relational database, but it designed to be as lightweight and simple as possible. +That's where TinyDB comes in. TinyDB is a tiny, simple, and fast in-memory database that you can use to store and retrieve data. It has all the features of a relational database, but it designed to be as lightweight and simple as possible. No need to install software or to set up a server. You're ready to go after installing dependencies. # Let's start - -Your entry point is ```@TinyTable``` decorator, where you pass tyke's name. +Your entry point is ```@TinyTable``` decorator, where you pass table's name. There are tons of decorators you can use to customize your database. In the example below, you can see ```@Column``` decorators. @@ -29,20 +25,20 @@ class User { type: "string", unique: true, }) - name!: string; + name!: string @Column({ type: "date", allowNull: true, }) - birthday!: string; + birthday!: string @Column({ type: "boolean", default: false, allowNull: true, }) - isAdmin!: boolean; + isAdmin!: boolean @Column({ allowNull: true, @@ -52,14 +48,14 @@ class User { lang: 'en', } }) - settings!: Record; + settings!: Record @Column({ type: "array", allowNull: true, default: [], }) - friends!: string[]; + friends!: string[] } ``` diff --git a/deps/deps.ts b/deps/deps.ts index 29f84e2..ea1d693 100644 --- a/deps/deps.ts +++ b/deps/deps.ts @@ -1,2 +1,2 @@ -export {parse} from "https://deno.land/std@0.144.0/datetime/mod.ts"; -export { ensureDirSync } from "https://deno.land/std@0.78.0/fs/mod.ts"; \ No newline at end of file +export {parse} from "https://deno.land/std@0.144.0/datetime/mod.ts" +export { ensureDirSync } from "https://deno.land/std@0.78.0/fs/mod.ts" \ No newline at end of file diff --git a/src/classes/Instance.ts b/src/classes/Instance.ts index 15d6c6c..81ec04e 100644 --- a/src/classes/Instance.ts +++ b/src/classes/Instance.ts @@ -1,7 +1,7 @@ import {ColumnsUtils, FileUtils, Schema} from "../mod.ts" interface InstanceOptions { - isNew: boolean; + isNew: boolean } export class Instance { @@ -20,8 +20,8 @@ export class Instance { public delete() { const db = FileUtils.readJson("./database/db.json") - const filteredTable = db[this._schema.name] - .filter(row => row._id !== this._fields._id) + const filteredTable = db[this._schema.name].filter(row => row._id !== this._fields._id) + FileUtils.writeJson("./database/db.json", { ...db, [this._schema.name]: filteredTable diff --git a/src/classes/Model.ts b/src/classes/Model.ts index 1fc7fbc..e4462d9 100644 --- a/src/classes/Model.ts +++ b/src/classes/Model.ts @@ -6,13 +6,22 @@ export class Model { ) { } + private getTable(): T[] { + const db = FileUtils.readJson("./database/db.json") + return db[this.schema.name] ?? [] + } + + + // Creators + public create(args: T) { return new Instance(this.schema, args, {isNew: true}) } + // Finders + public findById(_id: string) { - const db = FileUtils.readJson("./database/db.json") - const table = db[this.schema.name] ?? [] + const table = this.getTable() const candidate = table.find(row => row._id === _id) if (candidate === undefined) { @@ -25,17 +34,12 @@ export class Model { } public find(args: Partial) { - const db = FileUtils.readJson("./database/db.json") - const table = db[this.schema.name] ?? [] + const table = this.getTable() const keys = Object.keys(args) as unknown as Array - const filteredTable = table.filter(row => - keys.every(key => - ObjectUtils.nestedCheck(row, key, args[key]))) - - return filteredTable.map(row => new Instance(this.schema, row, { - isNew: false - })) + return table + .filter(row => keys.every(key => ObjectUtils.nestedCheck(row, key, args[key]))) + .map(row => new Instance(this.schema, row, {isNew: false})) } public findOne(args: Partial) { @@ -43,9 +47,24 @@ export class Model { } public findAll() { - const db = FileUtils.readJson("./database/db.json") - return db[this.schema.name].map(row => new Instance(this.schema, row, { - isNew: false - })) + return this + .getTable() + .map(row => new Instance(this.schema, row, {isNew: false})) + } + + // Hunters + public hunt(args: Partial) { + this.find(args).map(instance => instance.delete()) + return "Successful hunt!" + } + + public huntOne(args: Partial) { + this.findOne(args).delete() + return "Successful single hunt!" + } + + public huntAll() { + this.findAll().map(instance => instance.delete()) + return "Successful absolute hunt!" } } diff --git a/src/classes/Table.ts b/src/classes/Table.ts index f4152eb..885f42e 100644 --- a/src/classes/Table.ts +++ b/src/classes/Table.ts @@ -1,28 +1,28 @@ -import {FileUtils} from "../mod.ts"; +import {FileUtils} from "../mod.ts" export class Table { public static init(name: string) { try { - const isExists = FileUtils.isFileExists("./database/db.json"); + const isExists = FileUtils.isFileExists("./database/db.json") if (isExists) { - return this; + return this } - FileUtils.createOrCheckDir("./database"); - FileUtils.writeJson("./database/db.json", {[name]: []}); - return this; + FileUtils.createOrCheckDir("./database") + FileUtils.writeJson("./database/db.json", {[name]: []}) + return this } catch (e) { - console.error(e.message); + console.error(e.message) } } public static nuke(name: string) { try { - FileUtils.writeJson("./database/db.json", {[name]: []}); - return 'Nuke\'em'; + FileUtils.writeJson("./database/db.json", {[name]: []}) + return 'Nuke\'em' } catch (e) { - console.error(e.message); + console.error(e.message) } } } diff --git a/src/classes/mod.ts b/src/classes/mod.ts index 0ba4547..24d854e 100644 --- a/src/classes/mod.ts +++ b/src/classes/mod.ts @@ -1,5 +1,5 @@ -export {Instance} from "./Instance.ts"; -export {Model} from "./Model.ts"; -export {Schema} from "./Schema.ts"; -export {Table} from "./Table.ts"; +export {Instance} from "./Instance.ts" +export {Model} from "./Model.ts" +export {Schema} from "./Schema.ts" +export {Table} from "./Table.ts" diff --git a/src/decorators/Column.ts b/src/decorators/Column.ts index bb30b19..189de31 100644 --- a/src/decorators/Column.ts +++ b/src/decorators/Column.ts @@ -1,16 +1,16 @@ -import {Reflect} from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts"; -import {ColumnProps} from "../interfaces/Column.ts"; +import {Reflect} from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts" +import {ColumnProps} from "../interfaces/Column.ts" -const formatMetadataKey = Symbol("columns"); +const formatMetadataKey = Symbol("columns") export function getFormat(target: unknown, propertyKey: string) { - return Reflect.getMetadata(formatMetadataKey, target, propertyKey); + return Reflect.getMetadata(formatMetadataKey, target, propertyKey) } export function Column(options: ColumnProps) { const optionsProxy = options.allowNull === undefined ? {...options, allowNull: false} - : {...options, allowNull: true}; + : {...options, allowNull: true} - return Reflect.metadata(formatMetadataKey, optionsProxy); + return Reflect.metadata(formatMetadataKey, optionsProxy) } diff --git a/src/errors/ErrorWithHint.ts b/src/errors/ErrorWithHint.ts index 7eda40c..b6acb15 100644 --- a/src/errors/ErrorWithHint.ts +++ b/src/errors/ErrorWithHint.ts @@ -3,6 +3,6 @@ export class ErrorWithHint extends Error { super(` Message: ${message} Hint: ${hint} - `); + `) } } diff --git a/src/errors/mod.ts b/src/errors/mod.ts index 5cdaa31..a177653 100644 --- a/src/errors/mod.ts +++ b/src/errors/mod.ts @@ -1 +1 @@ -export {ErrorWithHint} from "./ErrorWithHint.ts"; +export {ErrorWithHint} from "./ErrorWithHint.ts" diff --git a/src/interfaces/Column.ts b/src/interfaces/Column.ts index fecbe52..a2e527a 100644 --- a/src/interfaces/Column.ts +++ b/src/interfaces/Column.ts @@ -1,14 +1,14 @@ -export type OptionTypes = "string" | "number" | "boolean" | "date" | "json" | "array"; +export type OptionTypes = "string" | "number" | "boolean" | "date" | "json" | "array" export interface ColumnProps { - unique?: boolean; - type?: OptionTypes; - allowNull?: boolean; + unique?: boolean + type?: OptionTypes + allowNull?: boolean // deno-lint-ignore no-explicit-any - default?: any; + default?: any } export interface ColumnRules { - name: string; - options: ColumnProps; + name: string + options: ColumnProps } diff --git a/src/interfaces/Document.ts b/src/interfaces/Document.ts index dd07af3..b2609d4 100644 --- a/src/interfaces/Document.ts +++ b/src/interfaces/Document.ts @@ -1,4 +1,4 @@ export interface Document { - _id: string; - _tableName: string; + _id: string + _tableName: string } diff --git a/src/mod.ts b/src/mod.ts index e4b51c9..ad7d7bb 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -1,14 +1,14 @@ // Main classes -export {Model, Instance, Schema, Table} from "./classes/mod.ts"; +export {Model, Instance, Schema, Table} from "./classes/mod.ts" // Utils -export {FileUtils, ObjectUtils, ColumnsUtils} from "./utils/mod.ts"; +export {FileUtils, ObjectUtils, ColumnsUtils} from "./utils/mod.ts" // Decorators -export {Column, getFormat, TinyTable} from "./decorators/mod.ts"; +export {Column, getFormat, TinyTable} from "./decorators/mod.ts" // Types -export type {OptionTypes, ColumnProps, ColumnRules, Document} from "./interfaces/mod.ts"; +export type {OptionTypes, ColumnProps, ColumnRules, Document} from "./interfaces/mod.ts" // Errors -export { ErrorWithHint } from "./errors/mod.ts"; \ No newline at end of file +export { ErrorWithHint } from "./errors/mod.ts" \ No newline at end of file diff --git a/src/utils/ColumnsUtils.ts b/src/utils/ColumnsUtils.ts index 2b8997e..9f00500 100644 --- a/src/utils/ColumnsUtils.ts +++ b/src/utils/ColumnsUtils.ts @@ -1,6 +1,6 @@ -import {ColumnRules, OptionTypes} from "../interfaces/mod.ts"; -import {ErrorWithHint} from "../errors/mod.ts"; -import {parse} from "../../deps/deps.ts"; +import {ColumnRules, OptionTypes} from "../interfaces/mod.ts" +import {ErrorWithHint} from "../errors/mod.ts" +import {parse} from "../../deps/deps.ts" export class ColumnsUtils { constructor( @@ -8,70 +8,70 @@ export class ColumnsUtils { private table: Array = [], private record: T ) { - this.run(); + this.run() } private checkType(value: T[keyof T], columnName: string, checkType?: OptionTypes) { - const valueType = typeof value; + const valueType = typeof value if (checkType === "date") { try { - return parse(String(value), "yyyy-MM-dd"); + return parse(String(value), "yyyy-MM-dd") } catch (_) { - throw new Error(`${columnName} must be data`); + throw new Error(`${columnName} must be data`) } } if (checkType === "array") { - if (!Array.isArray(value)) throw new Error(`${columnName} must be array`); - return; + if (!Array.isArray(value)) throw new Error(`${columnName} must be array`) + return } if (checkType === "json") { - if (typeof value === "object" && !Array.isArray(value) && value !== null) return; - throw new Error(`${columnName} must be json`); + if (typeof value === "object" && !Array.isArray(value) && value !== null) return + throw new Error(`${columnName} must be json`) } if (valueType !== checkType) { - throw new Error(`${columnName} must be ${checkType}`); + throw new Error(`${columnName} must be ${checkType}`) } } private unique(column: ColumnRules) { - const name = column.name as keyof T; + const name = column.name as keyof T if (this.table.some(row => row[name] === this.record[name])) { throw new ErrorWithHint( `${String(name)} must be unique`, `${this.record[name]} is already exists` - ); + ) } } private type(column: ColumnRules) { - const name = column.name as keyof T; - const value = this.record[name]; - return this.checkType(value, String(name), column.options.type); + const name = column.name as keyof T + const value = this.record[name] + return this.checkType(value, String(name), column.options.type) } private default(column: ColumnRules) { - const name = column.name as keyof T; - this.record[name] = column.options.default; + const name = column.name as keyof T + this.record[name] = column.options.default } private run() { this.columnRules.map(rule => { if (rule.options.allowNull && this.record[rule.name as keyof T] === undefined && - rule.options.default === undefined) return; + rule.options.default === undefined) return if ( rule.options.default !== undefined && - this.record[rule.name as keyof T] === undefined) this.default(rule); + this.record[rule.name as keyof T] === undefined) this.default(rule) - rule.options.type !== undefined && this.type(rule); - rule.options.unique !== undefined && this.unique(rule); - }); + rule.options.type !== undefined && this.type(rule) + rule.options.unique !== undefined && this.unique(rule) + }) } } diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts index 8210b15..32d8328 100644 --- a/src/utils/FileUtils.ts +++ b/src/utils/FileUtils.ts @@ -3,38 +3,38 @@ import { ensureDirSync } from "../../deps/deps.ts" export class FileUtils { static writeJson(path: string, data: Record | Array): string { try { - Deno.writeTextFileSync(path, JSON.stringify(data)); - return "Written to " + path; + Deno.writeTextFileSync(path, JSON.stringify(data)) + return "Written to " + path } catch (e) { - return e.message; + return e.message } } static isFileExists(path: string): boolean { try { - Deno.statSync(path); - return true; + Deno.statSync(path) + return true } catch (e) { console.log(e.message) - return false; + return false } } static createOrCheckDir(path: string): string { try { - ensureDirSync(path); - return "Created directory " + path; + ensureDirSync(path) + return "Created directory " + path } catch (e) { - return e.message; + return e.message } } static readJson(path: string): Record> { try { - const data = Deno.readTextFileSync(path); - return JSON.parse(data); + const data = Deno.readTextFileSync(path) + return JSON.parse(data) } catch (_e) { - return {}; + return {} } } } diff --git a/src/utils/ObjectUtils.ts b/src/utils/ObjectUtils.ts index 85d3161..545b8d0 100644 --- a/src/utils/ObjectUtils.ts +++ b/src/utils/ObjectUtils.ts @@ -2,6 +2,7 @@ export class ObjectUtils { // deno-lint-ignore no-explicit-any static nestedCheck>(obj: T, key: keyof T, value: any): boolean { + // TODO: changeeeeeees if (typeof obj[key] === "boolean" && typeof value === "boolean") { return obj[key] === value }