feat: added Capacitor driver (#7695)

* added new driver for Capacitor

* updated CHANGELOG.md
This commit is contained in:
Chris 2021-05-29 11:46:45 +02:00 committed by GitHub
parent 620aac9e0f
commit 0f7a778398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 243 additions and 4 deletions

View File

@ -1,3 +1,11 @@
## 0.2.33 (UNRELEASED)
### Bug fixes
### Features
* added capacitor driver ([#7695](https://github.com/typeorm/typeorm/pull/7695))
## [0.2.32](https://github.com/typeorm/typeorm/compare/0.2.31...0.2.32) (2021-03-30)
### Bug Fixes

View File

@ -6,6 +6,7 @@
* [`postgres` / `cockroachdb` connection options](#postgres--cockroachdb-connection-options)
* [`sqlite` connection options](#sqlite-connection-options)
* [`better-sqlite3` connection options](#better-sqlite3-connection-options)
* [`capacitor` connection options](#capacitor-connection-options)
* [`cordova` connection options](#cordova-connection-options)
* [`react-native` connection options](#react-native-connection-options)
* [`nativescript` connection options](#nativescript-connection-options)
@ -23,8 +24,8 @@ Connection options is a connection configuration you pass to `createConnection`
## Common connection options
* `type` - Database type. You must specify what database engine you use.
Possible values are "mysql", "postgres", "cockroachdb", "mariadb", "sqlite", "better-sqlite3", "cordova", "nativescript",
"oracle", "mssql", "mongodb", "sqljs", "react-native".
Possible values are "mysql", "postgres", "cockroachdb", "mariadb", "sqlite", "better-sqlite3", "capacitor", "cordova",
"nativescript", "oracle", "mssql", "mongodb", "sqljs", "react-native".
This option is **required**.
* `name` - Connection name. You'll use it to get connection you need using `getConnection(name: string)`
@ -196,6 +197,12 @@ See [SSL options](https://github.com/mysqljs/mysql#ssl-options).
* `prepareDatabase` - Function to run before a database is used in typeorm. You can access original better-sqlite3 Database object here.
## `capacitor` connection options
* `database` - Database name (capacitor-sqlite will add the suffix `SQLite.db`)
* `driver` - The capacitor-sqlite instance. For example, `new SQLiteConnection(CapacitorSQLite)`.
## `cordova` connection options
* `database` - Database name

View File

@ -14,6 +14,7 @@ import {AuroraDataApiConnectionOptions} from "../driver/aurora-data-api/AuroraDa
import {SapConnectionOptions} from "../driver/sap/SapConnectionOptions";
import {AuroraDataApiPostgresConnectionOptions} from "../driver/aurora-data-api-pg/AuroraDataApiPostgresConnectionOptions";
import {BetterSqlite3ConnectionOptions} from "../driver/better-sqlite3/BetterSqlite3ConnectionOptions";
import {CapacitorConnectionOptions} from "../driver/capacitor/CapacitorConnectionOptions";
/**
@ -37,4 +38,5 @@ export type ConnectionOptions =
AuroraDataApiConnectionOptions|
AuroraDataApiPostgresConnectionOptions|
ExpoConnectionOptions|
BetterSqlite3ConnectionOptions;
BetterSqlite3ConnectionOptions |
CapacitorConnectionOptions;

View File

@ -17,6 +17,7 @@ import {Driver} from "./Driver";
import {Connection} from "../connection/Connection";
import {SapDriver} from "./sap/SapDriver";
import {BetterSqlite3Driver} from "./better-sqlite3/BetterSqlite3Driver";
import {CapacitorDriver} from "./capacitor/CapacitorDriver";
/**
* Helps to create drivers.
@ -63,6 +64,8 @@ export class DriverFactory {
return new AuroraDataApiDriver(connection);
case "aurora-data-api-pg":
return new AuroraDataApiPostgresDriver(connection);
case "capacitor":
return new CapacitorDriver(connection);
default:
throw new MissingDriverError(type);
}

View File

@ -0,0 +1,21 @@
import { BaseConnectionOptions } from "../../connection/BaseConnectionOptions";
/**
* Sqlite-specific connection options.
*/
export interface CapacitorConnectionOptions extends BaseConnectionOptions {
/**
* Database type.
*/
readonly type: "capacitor";
/**
* Database name (capacitor-sqlite will add the suffix `SQLite.db`)
*/
readonly database: string;
/**
* The capacitor-sqlite instance. For example, `new SQLiteConnection(CapacitorSQLite)`.
*/
readonly driver: any;
}

View File

@ -0,0 +1,99 @@
import { AbstractSqliteDriver } from "../sqlite-abstract/AbstractSqliteDriver";
import { CapacitorConnectionOptions } from "./CapacitorConnectionOptions";
import { CapacitorQueryRunner } from "./CapacitorQueryRunner";
import { QueryRunner } from "../../query-runner/QueryRunner";
import { Connection } from "../../connection/Connection";
import {
DriverOptionNotSetError,
DriverPackageNotInstalledError,
} from "../../error";
import { ReplicationMode } from "../types/ReplicationMode";
export class CapacitorDriver extends AbstractSqliteDriver {
driver: any;
options: CapacitorConnectionOptions;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
super(connection);
this.database = this.options.database;
this.driver = this.options.driver;
// validate options to make sure everything is set
if (!this.options.database)
throw new DriverOptionNotSetError("database");
if (!this.options.driver) throw new DriverOptionNotSetError("driver");
// load sqlite package
this.sqlite = this.options.driver;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Performs connection to the database.
*/
async connect(): Promise<void> {
this.databaseConnection = this.createDatabaseConnection();
await this.databaseConnection;
}
/**
* Closes connection with database.
*/
async disconnect(): Promise<void> {
this.queryRunner = undefined;
const databaseConnection = await this.databaseConnection;
return databaseConnection.close().then(() => {
this.databaseConnection = undefined;
});
}
/**
* Creates a query runner used to execute database queries.
*/
createQueryRunner(mode: ReplicationMode): QueryRunner {
if (!this.queryRunner)
this.queryRunner = new CapacitorQueryRunner(this);
return this.queryRunner;
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* Creates connection with the database.
*/
protected async createDatabaseConnection() {
const connection = await this.sqlite.createConnection(
this.options.database,
false,
"no-encryption",
1
);
await connection.open();
// we need to enable foreign keys in sqlite to make sure all foreign key related features
// working properly. this also makes onDelete to work with sqlite.
await connection.execute(`PRAGMA foreign_keys = ON;`);
return connection;
}
protected loadDependencies(): void {
this.sqlite = this.driver;
if (!this.driver) {
throw new DriverPackageNotInstalledError(
"Capacitor",
"@capacitor-community/sqlite"
);
}
}
}

View File

@ -0,0 +1,98 @@
import { QueryRunnerAlreadyReleasedError } from "../../error/QueryRunnerAlreadyReleasedError";
import { QueryFailedError } from "../../error/QueryFailedError";
import { AbstractSqliteQueryRunner } from "../sqlite-abstract/AbstractSqliteQueryRunner";
import { CapacitorDriver } from "./CapacitorDriver";
import { Broadcaster } from "../../subscriber/Broadcaster";
import { ObjectLiteral } from "../..";
/**
* Runs queries on a single sqlite database connection.
*/
export class CapacitorQueryRunner extends AbstractSqliteQueryRunner {
/**
* Database driver used by connection.
*/
driver: CapacitorDriver;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(driver: CapacitorDriver) {
super();
this.driver = driver;
this.connection = driver.connection;
this.broadcaster = new Broadcaster(this);
}
async executeSet(set: { statement: string; values?: any[] }[]) {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError();
const databaseConnection = await this.connect();
return databaseConnection.executeSet(set, false);
}
/**
* Executes a given SQL query.
*/
async query(query: string, parameters?: any[]): Promise<any> {
if (this.isReleased) throw new QueryRunnerAlreadyReleasedError();
const databaseConnection = await this.connect();
this.driver.connection.logger.logQuery(query, parameters, this);
let pResult: Promise<any>;
const command = query.substr(0, query.indexOf(" "));
if (
[
"PRAGMA",
"BEGIN",
"ROLLBACK",
"COMMIT",
"CREATE",
"ALTER",
"DROP",
].indexOf(command) !== -1
) {
pResult = databaseConnection.execute(query, false);
} else if (["INSERT", "UPDATE", "DELETE"].indexOf(command) !== -1) {
pResult = databaseConnection
.run(query, parameters, false)
.then(
({
changes,
}: {
changes: { changes?: number; lastId?: number };
}) => changes.lastId || changes.changes
);
} else {
pResult = databaseConnection
.query(query, parameters)
.then(({ values }: { values: any[] }) => values);
}
return pResult.catch((err: any) => {
this.driver.connection.logger.logQueryError(
err,
query,
parameters,
this
);
throw new QueryFailedError(query, parameters, err);
});
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral): string[] {
return Object.keys(objectLiteral).map((key) => `"${key}"` + "=?");
}
}

View File

@ -18,4 +18,5 @@ export type DatabaseType =
"aurora-data-api"|
"aurora-data-api-pg"|
"expo"|
"better-sqlite3";
"better-sqlite3" |
"capacitor";