Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database driver adaptations mysql #38

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3af23ab
feat:databaseDriverAdaptations - addedd Postgres|Sqlite
tksilicon Aug 4, 2020
184a019
feat:databaseDriverAdaptations - addedd Postgres|Sqlite
tksilicon Aug 4, 2020
638ce2c
feat:databaseDriverAdaptations - addedd Postgres|Sqlite
tksilicon Aug 4, 2020
b181a85
feat:databaseDriverAdaptations - addedd Postgres|Sqlite
tksilicon Aug 4, 2020
d5b500a
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
69a0bd9
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
e004f05
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
37aa379
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
a819428
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
ecbf4f0
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
fcfca4f
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
c022ef4
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
d566ab5
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
882a794
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
4c5f1c8
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
135b742
feat:databaseDriverAdaptations - Postgres|Sqlite
tksilicon Aug 4, 2020
1b1326b
feat:databaseDriverAdaptations - MYSQL
tksilicon Nov 4, 2020
31e8dcc
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 4, 2020
c7b227d
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 4, 2020
f20b1fa
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 4, 2020
ed86710
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 4, 2020
ba33409
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 4, 2020
6631d3b
add isolatedModules:false to tsconfig & readme for Deno 1.6.1
vmasdani Nov 4, 2020
6e90cab
feat:databaseDriverAdaptations - MySQL
tksilicon Nov 5, 2020
0d4ec1c
abstract base dso client
manyuanrong Nov 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
MYSQL_ROOT_PASSWORD: ""
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3


steps:
- uses: actions/checkout@v2
Expand All @@ -31,4 +32,4 @@ jobs:
deno fmt --check
- name: Test
run: |
deno test -c tsconfig.json --allow-net
deno test --allow-net -c tsconfig.json
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ mysql.log
package-lock.json
.vscode
node_modules
test.db
*.code-workspace
9 changes: 8 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
services:
- mysql
- postgresql
- SQLITE3



before_install:
- curl -fsSL https://deno.land/x/install/install.sh | sh
- export PATH="/home/travis/.deno/bin:$PATH"

before_script:
- psql -c 'create database test_orm;' -U postgres

script:
- deno test --unstable --allow-net -c tsconfig.json test.ts
- deno test --allow-net --allow-read --allow-write -c tsconfig.json test.ts
61 changes: 42 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
![GitHub release](https://img.shields.io/github/release/manyuanrong/dso.svg)
![(Deno)](https://img.shields.io/badge/deno-1.0.0-green.svg)


`dso` is a simple ORM Library based on [deno_mysql](https://github.com/manyuanrong/deno_mysql)

Other databases to be supported include - [Deno-Postgres](https://github.com/deno-postgres/deno-postgres) and [Deno-Sqlite](https://github.com/dyedgreen/deno-sqlite).


### Example

```ts
Expand Down Expand Up @@ -58,17 +62,25 @@ class UserModel extends BaseModel {
public myUniqueIndex!: Index;
}

const userModel = dso.define(UserModel);
const userModel = dso.mysqlClient.define(UserModel);

const config: ClientConfig = {
hostname: "127.0.0.1",
port: 3306,
poolSize: 3, // optional
debug: false,
username: "root",
password: "",
db: "",
};




async function main() {
// The database must be created before linking
await dso.connect({
hostname: "127.0.0.1",
port: 3306,
username: "root",
password: "",
db: "dbname"
});
// The database must be created before linking with the configuration object
await dso.mysqlClient.connect(mysqlConfig);


/*
When installing or initializing a database,
Expand All @@ -80,14 +92,22 @@ async function main() {
== WARNING! ==
Using true as the parameter will reset your whole database! Use with caution.
*/
await dso.sync(false);
await dso.mysqlClient.sync(false);

// You can add records using insert method
const insertId = await userModel.insert({
name: "user1",
password: "password"
});

// You can add records using insertRowsAffected method (works for only MySQL, Postgres and Sqlite)
// Returns the number of rows inserted inserted
const insertId = await userModel.insertRowsAffected({
name: "user1",
password: "password",
phoneNumber: "08135539123"
});

// You can use the Model.findById method to get a record
const user = await userModel.findById(1);

Expand Down Expand Up @@ -123,7 +143,8 @@ Since this library needs to use Typescript Decorators and other features, a cust
"allowJs": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "esnext"
"module": "esnext",
"isolatedModules": false
}
}
```
Expand All @@ -143,12 +164,13 @@ Set whether query debugging information is displayed
dso.showQueryLog = true;
```

#### dso.connect
#### dso.mysqlClient.connect

You need to use this method to link to the database before you can manipulate the database
See the approprite configuration object specified earlier. Example below is for MySQL

```ts
await dso.connect({
await dso.mysqlClient.connect({
hostname: "127.0.0.1", // database hostname
port: 3306, // database port
username: "root", // database username
Expand All @@ -157,7 +179,7 @@ await dso.connect({
});
```

#### dso.define()
#### dso.mysqlClient.define()

Add an annotated `Model` instance and return the instance.

Expand Down Expand Up @@ -191,12 +213,13 @@ export default const userModel = dso.define(UserModel);
// userModel.findById(...)
// userModel.findAll(...)
// userModel.findOne(...)
// userModel.insert(...)
// userModel.insert(...) // works for MySQL and Sqlite ONLY
// userModel.insertRowsAffected(...)
// userModel.update(...)
// userModel.delete(...)
```

#### dso.sync
#### dso.mysqlClient.sync

When installing or initializing a database, you can use sync to synchronize the database model to the database.

Expand All @@ -207,14 +230,14 @@ const force = true; // force
await dso.sync(force);
```

#### dso.transaction<T>(processor: (transaction: Transaction) => Promise<T>): Promise<T>
#### dso.mysqlClient.transaction<T>(processor: (transaction: Transaction) => Promise<T>): Promise<T>

Create and start a transaction.

New `Model` instances must be obtained through `getModel(Model)`. Otherwise, it will not be controlled by transactions.

```ts
const result = await dso.transaction<boolean>(async trans => {
const result = await dso.mysqlClient.transaction<boolean>(async trans => {
const userModel = trans.getModel(UserModel);
const topicModel = trans.getModel(TopicModel);

Expand Down Expand Up @@ -264,4 +287,4 @@ Following types of an index are available
| fulltext | true

#### Character sets
list of valid character sets is based on https://dev.mysql.com/doc/refman/8.0/en/charset-charsets.html
list of valid character sets is based on https://dev.mysql.com/doc/refman/8.0/en/charset-charsets.html
13 changes: 12 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,15 @@ services:
- 3306:3306
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
MYSQL_ROOT_PASSWORD: ""
MYSQL_ROOT_PASSWORD: ""
postgres:
image: postgres:10.8
ports:
- 5432:5432
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: ""
POSTGRES_DB: "test_orm"
sqlite:
image: keinos/sqlite3:latest

2 changes: 2 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ export {
replaceParams,
Where,
} from "./deps.ts";

export { dso } from "./src/dso.ts";
export * from "./src/field.ts";
export * from "./src/index.ts";
export * from "./src/charset.ts";
export * from "./src/model.ts";
export * from "./src/util.ts";
export * from "./src/types.ts";
9 changes: 5 additions & 4 deletions src/Reflect.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// deno-fmt-ignore-file
// @ts-nocheck
/*! *****************************************************************************
Copyright (C) Microsoft. All rights reserved.
Expand Down Expand Up @@ -780,13 +781,13 @@ namespace Reflect {
process.env &&
process.env["REFLECT_METADATA_USE_MAP_POLYFILL"] === "true";
const _Map: typeof Map = !usePolyfill &&
typeof Map === "function" &&
typeof Map.prototype.entries === "function"
typeof Map === "function" &&
typeof Map.prototype.entries === "function"
? Map
: CreateMapPolyfill();
const _Set: typeof Set = !usePolyfill &&
typeof Set === "function" &&
typeof Set.prototype.entries === "function"
typeof Set === "function" &&
typeof Set.prototype.entries === "function"
? Set
: CreateSetPolyfill();
const _WeakMap: typeof WeakMap =
Expand Down
90 changes: 90 additions & 0 deletions src/drivers/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Query } from "../../deps.ts";
import { dso } from "../dso.ts";
import { BaseModel } from "../model.ts";
import { DriverName } from "../types.ts";

export interface DsoConnection {
query<T = any>(sql: string, params?: any[]): Promise<T>;
execute<T = any>(sql: string, params?: any[]): Promise<T>;
}

export interface PoolInfo {
size: number | undefined;
maxSize: number | undefined;
available: number | undefined;
}

/**
* DSO client
*/
export abstract class DsoClient {
/** get driver name */
abstract get driverName(): DriverName;

/** get pool info */
abstract get pool(): PoolInfo | undefined;

/**
* connect to database
* @param config config for client
* @returns Clinet instance
*/
abstract connect<T>(config: T): Promise<this>;

abstract async useConnection<T>(
fn: (conn: DsoConnection) => Promise<T>,
): Promise<T>;

/**
* close connection
*/
abstract async close(): Promise<void>;

abstract async transaction<T>(
processor: (transaction: DsoTransaction) => Promise<T>,
client: DsoClient,
): Promise<T>;

/**
* query custom
* @param query
*/
async query(query: Query | string): Promise<any[]> {
const sql = typeof query === "string" ? query : query.build();
dso.showQueryLog && console.log(`\n[ DSO:QUERY ]\nSQL:\t ${sql}\n`);
const result = this.useConnection((conn) => {
return conn.query(sql);
});
dso.showQueryLog && console.log(`RESULT:\t`, result, `\n`);
return result;
}

/**
* excute custom
* @param query
*/
async execute(query: Query | string) {
const sql = typeof query === "string" ? query : query.build();
dso.showQueryLog && console.log(`\n[ DSO:EXECUTE ]\nSQL:\t ${sql}\n`);
const result = this.useConnection((conn) => {
return conn.execute(sql);
});
dso.showQueryLog && console.log(`RESULT:\t`, result, `\n`);
return result;
}
}

export class DsoTransaction {
#connection: DsoConnection;

constructor(conn: DsoConnection) {
this.#connection = conn;
}

getModel<T extends BaseModel>(
Model: { new (conn: DsoConnection): T },
): T {
const model = new Model(this.#connection);
return model;
}
}
68 changes: 68 additions & 0 deletions src/drivers/mysql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
Client,
ClientConfig,
Connection,
} from "https://deno.land/x/[email protected]/mod.ts";
import { DriverName } from "../types.ts";
import { DsoClient, DsoConnection, DsoTransaction, PoolInfo } from "./base.ts";

class MySqlConnection implements DsoConnection {
#connection: Connection;

constructor(conn: Connection) {
this.#connection = conn;
}

async query<T = any>(sql: string, params?: any[]): Promise<T> {
const result = await this.#connection.query(sql, params);
return result as T;
}

async execute<T = any>(sql: string, params?: any[]): Promise<T> {
const result = await this.#connection.execute(sql, params);
return result as T;
}
}

export class MysqlClient extends DsoClient {
#client: Client = new Client();

get driverName(): DriverName {
return DriverName.MYSQL;
}

async close(): Promise<void> {
this.#client.close();
}

async connect(config: ClientConfig): Promise<this> {
await this.#client.connect(config);
return this;
}

get pool(): PoolInfo {
const poolInfo = {
size: this.#client.pool?.size,
maxSize: this.#client.pool?.maxSize,
available: this.#client.pool?.available,
};
return poolInfo;
}

useConnection<T>(fn: (conn: DsoConnection) => Promise<T>): Promise<T> {
return this.#client.useConnection((mysqlConn) => {
return fn(new MySqlConnection(mysqlConn));
});
}

async transaction<T>(
processor: (transaction: DsoTransaction) => Promise<T>,
): Promise<T> {
return (
await this.#client.transaction(async (conn) => {
const trans = new DsoTransaction(new MySqlConnection(conn));
return await processor(trans);
})
) as T;
}
}
Loading