diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..90bd1b2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: ci + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-16.04 + strategy: + matrix: + deno: ["v1.2.1"] + name: Deno ${{ matrix.deno }} + + services: + postgres: + image: postgres:10.8 + ports: + - 5432:5432 + env: + POSTGRES_USER: "reverb_orm" + POSTGRES_PASSWORD: "reverb_orm" + POSTGRES_DB: "reverb_orm" + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v2 + - name: Setup Deno + uses: denolib/setup-deno@v2 + with: + deno-version: ${{ matrix.deno }} + + - name: Check format + run: | + deno fmt --check + - name: Test + run: | + deno test -c tsconfig.json --allow-net --allow-env \ No newline at end of file diff --git a/deps.ts b/deps.ts index b12d6b4..9fd4878 100644 --- a/deps.ts +++ b/deps.ts @@ -1 +1,3 @@ -import "./src/reflect.ts"; \ No newline at end of file +import "./src/util/reflect.ts"; +export { Client } from "https://deno.land/x/postgres/mod.ts"; +export { ConnectionOptions } from "https://deno.land/x/postgres/connection_params.ts"; diff --git a/mod.ts b/mod.ts index 1f4eb16..79cb3bf 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,4 @@ import "./deps.ts"; export { Entity } from "./src/decorators/entity.ts"; -export { Schema } from "./src/decorators/schema.ts"; \ No newline at end of file +export { Schema } from "./src/decorators/schema.ts"; +export { Deployment } from "./src/core/deployment.ts"; diff --git a/src/common/constants.ts b/src/common/constants.ts index 0e8fe65..28696a5 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -12,4 +12,4 @@ export type SCHEMA_METADATA_KEYS_TYPE = export const DEFINITION_TYPE = { ENTITY: "__entity__", SCHEMA: "__schema__", -} \ No newline at end of file +}; diff --git a/src/core/db_driver.ts b/src/core/db_driver.ts new file mode 100644 index 0000000..24cd375 --- /dev/null +++ b/src/core/db_driver.ts @@ -0,0 +1,7 @@ +import { QueryResult } from "./query_result.ts"; + +export interface DBDriver { + query(query: string, ...args: any[]): Promise; + connect(): Promise; + disconnect(): Promise; +} diff --git a/src/core/deployment.ts b/src/core/deployment.ts new file mode 100644 index 0000000..3da0d89 --- /dev/null +++ b/src/core/deployment.ts @@ -0,0 +1,29 @@ +import { Type } from "../decorators/schema.ts"; +import { Client, ConnectionOptions } from "../../deps.ts"; +import { DBDriver } from "./db_driver.ts"; +import { PostgresDriver } from "./drivers/postgres.ts"; + +export class Deployment { + private readonly driver: DBDriver; + + constructor( + private schema: Type, + connection: Client | ConnectionOptions, + ) { + let client: Client; + if (connection instanceof Client) { + client = connection; + } else { + client = new Client(connection); + } + this.driver = new PostgresDriver(client); + } + + async connect(): Promise { + await this.driver.connect(); + } + + async disconnect(): Promise { + await this.driver.disconnect(); + } +} diff --git a/src/core/drivers/postgres.ts b/src/core/drivers/postgres.ts new file mode 100644 index 0000000..fde9d17 --- /dev/null +++ b/src/core/drivers/postgres.ts @@ -0,0 +1,19 @@ +import { DBDriver } from "../db_driver.ts"; +import { QueryResult } from "../query_result.ts"; +import { Client } from "../../../deps.ts"; + +export class PostgresDriver implements DBDriver { + constructor(private readonly client: Client) {} + + async query(query: string, ...args: any[]): Promise { + return this.client.query(query, args); + } + + async connect(): Promise { + await this.client.connect(); + } + + async disconnect(): Promise { + await this.client.end(); + } +} diff --git a/src/core/query_result.ts b/src/core/query_result.ts new file mode 100644 index 0000000..ce61236 --- /dev/null +++ b/src/core/query_result.ts @@ -0,0 +1,3 @@ +export interface QueryResult { + rows: any[]; +} diff --git a/src/decorators/entity.ts b/src/decorators/entity.ts index dae4492..6bf7f35 100644 --- a/src/decorators/entity.ts +++ b/src/decorators/entity.ts @@ -5,9 +5,8 @@ export interface EntityConfig { } export function Entity(config?: EntityConfig): ClassDecorator { - return (target: Function) => { Reflect.defineMetadata(ENTITY_METADATA, config, target); Reflect.defineMetadata(DEFINITION_TYPE.ENTITY, true, target); - } + }; } diff --git a/src/decorators/schema.ts b/src/decorators/schema.ts index 457776c..3c3b486 100644 --- a/src/decorators/schema.ts +++ b/src/decorators/schema.ts @@ -1,15 +1,22 @@ -import { SCHEMA_METADATA, SCHEMA_METADATA_KEYS, SCHEMA_METADATA_KEYS_TYPE, DEFINITION_TYPE } from "../common/constants.ts"; +import { + SCHEMA_METADATA, + SCHEMA_METADATA_KEYS, + SCHEMA_METADATA_KEYS_TYPE, + DEFINITION_TYPE, +} from "../common/constants.ts"; export interface Type extends Function { new (...args: any[]): T; } export interface SchemaDefinition { - [SCHEMA_METADATA.ENTITIES]?: Type[], + [SCHEMA_METADATA.ENTITIES]?: Type[]; } export function Schema(definition: SchemaDefinition): ClassDecorator { - const propsKeys = (Object.keys(definition) as unknown) as Array; + const propsKeys = (Object.keys(definition) as unknown) as Array< + keyof SchemaDefinition + >; validateSchemaKeys(propsKeys); return (target: Function) => { @@ -19,7 +26,7 @@ export function Schema(definition: SchemaDefinition): ClassDecorator { Reflect.defineMetadata(property, (definition as any)[property], target); } } - } + }; } export const INVALID_SCHEMA_DEFINITION_MESSAGE = ( @@ -35,4 +42,4 @@ export function validateSchemaKeys(keys: SCHEMA_METADATA_KEYS_TYPE[]) { throw new Error(INVALID_SCHEMA_DEFINITION_MESSAGE`${key}`); }; keys.forEach(validateKey); -} \ No newline at end of file +} diff --git a/src/util/reflect.ts b/src/util/reflect.ts index 7f43fd4..84169ca 100644 --- a/src/util/reflect.ts +++ b/src/util/reflect.ts @@ -2159,4 +2159,4 @@ namespace Reflect { return obj; } }); -} \ No newline at end of file +} diff --git a/test.ts b/test.ts index 2b8fdaf..ce4e93e 100644 --- a/test.ts +++ b/test.ts @@ -1,6 +1,6 @@ -import { Entity, Schema } from "./mod.ts"; +import { Entity, Schema, Deployment } from "./mod.ts"; -Deno.test("defineBasicSchema", function (): void { +Deno.test("defineBasicSchema", async function (): Promise { @Entity() class User { id!: number; @@ -11,9 +11,19 @@ Deno.test("defineBasicSchema", function (): void { } @Schema({ - entities: [User], + entities: [User], }) class AppSchema {} - // TODO initialize schema -}); \ No newline at end of file + const deployment = new Deployment(AppSchema, { + hostname: Deno.env.get("DB_HOST") || "127.0.0.1", + user: "reverb_orm", + database: "reverb_orm", + password: "reverb_orm", + port: 5432, + }); + + await deployment.connect(); + + await deployment.disconnect(); +});