mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
removed websql and systemjs
Support for WebSql and System.js have has been dropped after a discussion (#1918) as they are cannot be fully supported and aren't used that much
This commit is contained in:
parent
926ce07444
commit
3a8bb3b3b2
@ -66,6 +66,7 @@ composite check constraint, on table level. E.g. `@Check("chk_name", "name <> 'a
|
||||
* CLI commands changed from `migrations:create`, `migrations:generate`, `migrations:revert` and `migrations:run` to `migration:create`, `migration:generate`, `migration:revert` and `migration:run`
|
||||
* changed the way how migrations work (more info in #1315). Now migration table contains `id` column with auto-generated keys, you need to re-create migrations table or add new column manually.
|
||||
* entity schemas syntax was changed
|
||||
* dropped support for WebSql and SystemJS
|
||||
|
||||
## 0.1.19
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
[ ] `postgres`
|
||||
[ ] `sqlite`
|
||||
[ ] `sqljs`
|
||||
[ ] `websql`
|
||||
[ ] `react-native`
|
||||
|
||||
**TypeORM version:**
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ Some TypeORM features:
|
||||
* supports closure table pattern
|
||||
* schema declaration in models or separate configuration files
|
||||
* connection configuration in json / xml / yml / env formats
|
||||
* supports MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / WebSQL / sql.js
|
||||
* supports MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / sql.js
|
||||
* supports MongoDB NoSQL database
|
||||
* works in NodeJS / Browser / Ionic / Cordova / React Native / Electron platforms
|
||||
* TypeScript and JavaScript support
|
||||
@ -238,8 +238,7 @@ typeorm init --name MyProject --database mysql
|
||||
```
|
||||
|
||||
Where `name` is the name of your project and `database` is the database you'll use.
|
||||
Database can be one of the following values: `mysql`, `mariadb`, `postgres`, `sqlite`, `mssql`, `oracle`,
|
||||
`websql`, `mongodb`.
|
||||
Database can be one of the following values: `mysql`, `mariadb`, `postgres`, `sqlite`, `mssql`, `oracle`, `mongodb`, `cordova`, `react-native`.
|
||||
|
||||
This command will generate a new project in the `MyProject` directory with the following files:
|
||||
|
||||
@ -534,8 +533,7 @@ createConnection({
|
||||
|
||||
We are using MySQL in this example, but you can use any other supported database.
|
||||
To use another database, simply change the `type` in the options to the database type you are using:
|
||||
mysql, mariadb, postgres, sqlite, mssql, oracle,
|
||||
websql, cordova, react-native or mongodb.
|
||||
mysql, mariadb, postgres, sqlite, mssql, oracle, cordova, react-native or mongodb.
|
||||
Also make sure to use your own host, port, username, password and database settings.
|
||||
|
||||
We added our Photo entity to the list of entities for this connection.
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
* [`mysql` / `mariadb` connection options](#mysql--mariadb-connection-options)
|
||||
* [`postgres` connection options](#postgres-connection-options)
|
||||
* [`sqlite` connection options](#sqlite-connection-options)
|
||||
* [`websql` connection options](#websql-connection-options)
|
||||
* [`cordova` connection options](#cordova-connection-options)
|
||||
* [`react-native` connection options](#react-native-connection-options)
|
||||
* [`mssql` connection options](#mssql-connection-options)
|
||||
@ -21,7 +20,7 @@ Connection options is a connection configuration object you pass to `createConne
|
||||
## Common connection options
|
||||
|
||||
* `type` - Database type. You must specify what database engine you use.
|
||||
Possible values are "mysql", "postgres", "mariadb", "sqlite", "cordova", "oracle", "mssql", "websql", "mongodb", "sqljs", "react-native".
|
||||
Possible values are "mysql", "postgres", "mariadb", "sqlite", "cordova", "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)`
|
||||
@ -172,16 +171,6 @@ See [SSL options](https://github.com/mysqljs/mysql#ssl-options).
|
||||
|
||||
* `database` - Database path. For example "./mydb.sql"
|
||||
|
||||
## `websql` connection options
|
||||
|
||||
* `database` - Database name
|
||||
|
||||
* `version` - Version string of the database
|
||||
|
||||
* `description` - Database description
|
||||
|
||||
* `size` - The size of the database
|
||||
|
||||
## `cordova` connection options
|
||||
|
||||
* `database` - Database name
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* [Column types](#column-types)
|
||||
* [Column types for `mysql` / `mariadb`](#column-types-for-mysql--mariadb)
|
||||
* [Column types for `postgres`](#column-types-for-postgres)
|
||||
* [Column types for `sqlite` / `websql`](#column-types-for-sqlite--websql--cordova)
|
||||
* [Column types for `sqlite` / `cordova` / `react-native`](#column-types-for-sqlite--cordova--react-native)
|
||||
* [Column types for `mssql`](#column-types-for-mssql)
|
||||
* [`simple-array` column type](#simple-array-column-type)
|
||||
* [`simple-json` column type](#simple-json-column-type)
|
||||
@ -254,7 +254,7 @@ or
|
||||
`circle`, `path`, `polygon`, `cidr`, `enum`, `inet`, `macaddr`, `bit`, `bit varying`,
|
||||
`varbit`, `tsvector`, `tsquery`, `uuid`, `xml`, `json`, `jsonb`
|
||||
|
||||
### Column types for `sqlite` / `websql` / `cordova`
|
||||
### Column types for `sqlite` / `cordova` / `react-native`
|
||||
|
||||
`int`, `int2`, `int8`, `integer`, `tinyint`, `smallint`, `mediumint`, `bigint`, `decimal`,
|
||||
`numeric`, `float`, `double`, `real`, `double precision`, `datetime`, `varying character`,
|
||||
|
||||
@ -11,7 +11,7 @@ TypeORM was tested on Node.js version 4 and above.
|
||||
|
||||
## Browser
|
||||
|
||||
There is an experimental version of TypeORM that runs in the browser using WebSQL.
|
||||
You can use [sql.js](https://github.com/kripken/sql.js) in the browser.
|
||||
There are two ways how it can be used in browser:
|
||||
|
||||
* **Webpack / ES2015 Module**
|
||||
@ -27,28 +27,11 @@ There are two ways how it can be used in browser:
|
||||
]
|
||||
```
|
||||
|
||||
* **SystemJS**
|
||||
|
||||
If you want to use SystemJS as a module loader than three precompiled files are included for you to use.
|
||||
|
||||
```
|
||||
- typeorm-browser.js
|
||||
- typeorm-browser.min.js (Minified version)
|
||||
- typeorm-browser.js.map (Sourcemap)
|
||||
```
|
||||
|
||||
Since these files are generated by the TypeScript compiler they are affected by the [issue, that SystemJS 0.20 does not support them](https://github.com/systemjs/systemjs/issues/1587). When using SystemJS@0.19.47 everything works.
|
||||
For an example see [typeorm/browser-example](https://github.com/typeorm/browser-example).
|
||||
|
||||
**Example of configuration**
|
||||
|
||||
```typescript
|
||||
createConnection({
|
||||
type: "websql",
|
||||
database: "test",
|
||||
version: 1,
|
||||
description: "test database",
|
||||
size: 2 * 1024 * 1024,
|
||||
type: "sqljs",
|
||||
entities: [
|
||||
Photo
|
||||
],
|
||||
|
||||
55
gulpfile.ts
55
gulpfile.ts
@ -9,8 +9,6 @@ const del = require("del");
|
||||
const shell = require("gulp-shell");
|
||||
const replace = require("gulp-replace");
|
||||
const rename = require("gulp-rename");
|
||||
const file = require("gulp-file");
|
||||
const uglify = require("gulp-uglify");
|
||||
const mocha = require("gulp-mocha");
|
||||
const chai = require("chai");
|
||||
const tslint = require("gulp-tslint");
|
||||
@ -70,20 +68,9 @@ export class Gulpfile {
|
||||
"!./src/typeorm-model-shim.ts",
|
||||
"!./src/platform/PlatformTools.ts"
|
||||
])
|
||||
.pipe(gulp.dest("./build/systemjs/typeorm"))
|
||||
.pipe(gulp.dest("./build/browser/src"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates special main file for browser build.
|
||||
*/
|
||||
@Task()
|
||||
browserCopyMainBrowserFile() {
|
||||
return gulp.src("./package.json", { read: false })
|
||||
.pipe(file("typeorm.ts", `export * from "./typeorm/index";`))
|
||||
.pipe(gulp.dest("./build/systemjs"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces PlatformTools with browser-specific implementation called BrowserPlatformTools.
|
||||
*/
|
||||
@ -91,32 +78,9 @@ export class Gulpfile {
|
||||
browserCopyPlatformTools() {
|
||||
return gulp.src("./src/platform/BrowserPlatformTools.template")
|
||||
.pipe(rename("PlatformTools.ts"))
|
||||
.pipe(gulp.dest("./build/systemjs/typeorm/platform"))
|
||||
.pipe(gulp.dest("./build/browser/src/platform"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs files compilation of browser-specific source code.
|
||||
*/
|
||||
@MergedTask()
|
||||
browserCompileSystemJS() {
|
||||
const tsProject = ts.createProject("tsconfig.json", {
|
||||
outFile: "typeorm-browser.js",
|
||||
module: "system",
|
||||
"lib": ["es5", "es6", "dom"],
|
||||
typescript: require("typescript")
|
||||
});
|
||||
const tsResult = gulp.src(["./build/systemjs/**/*.ts", "./node_modules/reflect-metadata/**/*.d.ts", "./node_modules/@types/**/*.ts"])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(tsProject());
|
||||
|
||||
return [
|
||||
tsResult.js
|
||||
.pipe(sourcemaps.write(".", { sourceRoot: "", includeContent: true }))
|
||||
.pipe(gulp.dest("./build/package"))
|
||||
];
|
||||
}
|
||||
|
||||
@MergedTask()
|
||||
browserCompile() {
|
||||
const tsProject = ts.createProject("tsconfig.json", {
|
||||
@ -136,21 +100,10 @@ export class Gulpfile {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Uglifys all code.
|
||||
*/
|
||||
@Task()
|
||||
browserUglify() {
|
||||
return gulp.src("./build/package/typeorm-browser.js")
|
||||
.pipe(uglify())
|
||||
.pipe(rename("typeorm-browser.min.js"))
|
||||
.pipe(gulp.dest("./build/package"));
|
||||
}
|
||||
|
||||
@Task()
|
||||
browserClearPackageDirectory(cb: Function) {
|
||||
return del([
|
||||
"./build/systemjs/**"
|
||||
"./build/browser/**"
|
||||
]);
|
||||
}
|
||||
|
||||
@ -264,9 +217,9 @@ export class Gulpfile {
|
||||
package() {
|
||||
return [
|
||||
"clean",
|
||||
["browserCopySources", "browserCopyMainBrowserFile", "browserCopyPlatformTools"],
|
||||
["packageCompile", "browserCompile", "browserCompileSystemJS"],
|
||||
["packageMoveCompiledFiles", "browserUglify"],
|
||||
["browserCopySources", "browserCopyPlatformTools"],
|
||||
["packageCompile", "browserCompile"],
|
||||
"packageMoveCompiledFiles",
|
||||
[
|
||||
"browserClearPackageDirectory",
|
||||
"packageClearPackageDirectory",
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "typeorm",
|
||||
"private": true,
|
||||
"version": "0.2.0-alpha.46",
|
||||
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL, MongoDB databases.",
|
||||
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.",
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md",
|
||||
"author": {
|
||||
@ -31,9 +31,7 @@
|
||||
"sql-server",
|
||||
"sql-server-orm",
|
||||
"oracle",
|
||||
"oracle-orm",
|
||||
"websql",
|
||||
"websql-orm"
|
||||
"oracle-orm"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.2",
|
||||
@ -48,7 +46,6 @@
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-file": "^0.4.0",
|
||||
"gulp-istanbul": "^1.1.3",
|
||||
"gulp-mocha": "^5.0.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
@ -57,7 +54,6 @@
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"gulp-tslint": "^8.1.3",
|
||||
"gulp-typescript": "^4.0.2",
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"gulpclass": "^0.1.2",
|
||||
"husky": "^0.14.3",
|
||||
"lint-staged": "^7.0.0",
|
||||
|
||||
@ -3,7 +3,6 @@ import {PostgresConnectionOptions} from "../driver/postgres/PostgresConnectionOp
|
||||
import {SqliteConnectionOptions} from "../driver/sqlite/SqliteConnectionOptions";
|
||||
import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions";
|
||||
import {OracleConnectionOptions} from "../driver/oracle/OracleConnectionOptions";
|
||||
import {WebSqlConnectionOptions} from "../driver/websql/WebSqlConnectionOptions";
|
||||
import {MongoConnectionOptions} from "../driver/mongodb/MongoConnectionOptions";
|
||||
import {CordovaConnectionOptions} from "../driver/cordova/CordovaConnectionOptions";
|
||||
import {SqljsConnectionOptions} from "../driver/sqljs/SqljsConnectionOptions";
|
||||
@ -20,7 +19,6 @@ export type ConnectionOptions =
|
||||
SqliteConnectionOptions|
|
||||
SqlServerConnectionOptions|
|
||||
OracleConnectionOptions|
|
||||
WebSqlConnectionOptions|
|
||||
CordovaConnectionOptions|
|
||||
ReactNativeConnectionOptions|
|
||||
SqljsConnectionOptions|
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import {MissingDriverError} from "../error/MissingDriverError";
|
||||
import {MongoDriver} from "./mongodb/MongoDriver";
|
||||
import {WebsqlDriver} from "./websql/WebsqlDriver";
|
||||
import {SqlServerDriver} from "./sqlserver/SqlServerDriver";
|
||||
import {OracleDriver} from "./oracle/OracleDriver";
|
||||
import {SqliteDriver} from "./sqlite/SqliteDriver";
|
||||
@ -41,8 +40,6 @@ export class DriverFactory {
|
||||
return new OracleDriver(connection);
|
||||
case "mssql":
|
||||
return new SqlServerDriver(connection);
|
||||
case "websql":
|
||||
return new WebsqlDriver(connection);
|
||||
case "mongodb":
|
||||
return new MongoDriver(connection);
|
||||
default:
|
||||
|
||||
@ -11,5 +11,4 @@ export type DatabaseType =
|
||||
"sqljs"|
|
||||
"oracle"|
|
||||
"mssql"|
|
||||
"websql"|
|
||||
"mongodb";
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
import {BaseConnectionOptions} from "../../connection/BaseConnectionOptions";
|
||||
|
||||
/**
|
||||
* Websql-specific connection options.
|
||||
*/
|
||||
export interface WebSqlConnectionOptions extends BaseConnectionOptions {
|
||||
|
||||
/**
|
||||
* Database type.
|
||||
*/
|
||||
readonly type: "websql";
|
||||
|
||||
/**
|
||||
* Storage type or path to the storage.
|
||||
*/
|
||||
readonly database: string;
|
||||
|
||||
/**
|
||||
* Database version.
|
||||
*/
|
||||
readonly version: string;
|
||||
|
||||
/**
|
||||
* Database description.
|
||||
*/
|
||||
readonly description: string;
|
||||
|
||||
/**
|
||||
* Database size.
|
||||
*/
|
||||
readonly size: number;
|
||||
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
import {DriverUtils} from "../DriverUtils";
|
||||
import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
import {DriverOptionNotSetError} from "../../error/DriverOptionNotSetError";
|
||||
import {WebsqlQueryRunner} from "./WebsqlQueryRunner";
|
||||
import {Connection} from "../../connection/Connection";
|
||||
import {WebSqlConnectionOptions} from "./WebSqlConnectionOptions";
|
||||
import {AbstractSqliteDriver} from "../sqlite-abstract/AbstractSqliteDriver";
|
||||
|
||||
/**
|
||||
* Organizes communication with WebSQL in the browser.
|
||||
*/
|
||||
export class WebsqlDriver extends AbstractSqliteDriver {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Connection options.
|
||||
*/
|
||||
options: WebSqlConnectionOptions;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(connection: Connection) {
|
||||
super(connection);
|
||||
|
||||
this.options = connection.options as WebSqlConnectionOptions;
|
||||
Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
|
||||
this.database = this.options.database;
|
||||
|
||||
// validate options to make sure everything is set
|
||||
// if (!this.options.host)
|
||||
// throw new DriverOptionNotSetError("host");
|
||||
// if (!this.options.username)
|
||||
// throw new DriverOptionNotSetError("username");
|
||||
if (!this.options.database)
|
||||
throw new DriverOptionNotSetError("database");
|
||||
// todo: what about extra options: version, description, size
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Performs connection to the database.
|
||||
*/
|
||||
async connect(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes connection with the database.
|
||||
*/
|
||||
disconnect(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
// if (!this.databaseConnection)
|
||||
// throw new ConnectionIsNotSetError("websql");
|
||||
|
||||
// return new Promise<void>((ok, fail) => {
|
||||
// const handler = (err: any) => err ? fail(err) : ok();
|
||||
// todo: find out how to close connection
|
||||
// ok();
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query runner used to execute database queries.
|
||||
*/
|
||||
createQueryRunner(mode: "master"|"slave" = "master"): WebsqlQueryRunner {
|
||||
return new WebsqlQueryRunner(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares given value to a value to be persisted, based on its column type and metadata.
|
||||
*/
|
||||
preparePersistentValue(value: any, columnMetadata: ColumnMetadata): any {
|
||||
if (columnMetadata.type === "json") {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
return super.preparePersistentValue(value, columnMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares given value to a value to be persisted, based on its column type or metadata.
|
||||
*/
|
||||
prepareHydratedValue(value: any, columnMetadata: ColumnMetadata): any {
|
||||
if (columnMetadata.type === "json") {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
|
||||
return super.prepareHydratedValue(value, columnMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces parameters in the given sql with special escaping character
|
||||
* and an array of parameter names to be passed to a query.
|
||||
*/
|
||||
escapeQueryWithParameters(sql: string, parameters: ObjectLiteral, nativeParameters: ObjectLiteral): [string, any[]] {
|
||||
const escapedParameters: any[] = Object.keys(nativeParameters).map(key => nativeParameters[key]);
|
||||
if (!parameters || !Object.keys(parameters).length)
|
||||
return [sql, escapedParameters];
|
||||
|
||||
const keys = Object.keys(parameters).map(parameter => "(:(\\.\\.\\.)?" + parameter + "\\b)").join("|");
|
||||
sql = sql.replace(new RegExp(keys, "g"), (key: string) => {
|
||||
let value: any;
|
||||
if (key.substr(0, 4) === ":...") {
|
||||
value = parameters[key.substr(4)];
|
||||
} else {
|
||||
value = parameters[key.substr(1)];
|
||||
}
|
||||
|
||||
if (value instanceof Function) {
|
||||
return value();
|
||||
|
||||
}
|
||||
// Websql doesn't support queries boolean values. Therefore 1 and 0 has to be used.
|
||||
else if ((typeof value) === "boolean") {
|
||||
escapedParameters.push((value ? 1 : 0));
|
||||
return "?";
|
||||
} else {
|
||||
escapedParameters.push(value);
|
||||
return "?";
|
||||
}
|
||||
}); // todo: make replace only in value statements, otherwise problems
|
||||
return [sql, escapedParameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a column name.
|
||||
*/
|
||||
escape(columnName: string): string {
|
||||
return columnName; // "`" + columnName + "`";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build full table name with database name, schema name and table name.
|
||||
* E.g. "myDB"."mySchema"."myTable"
|
||||
*/
|
||||
buildTableName(tableName: string, schema?: string, database?: string): string {
|
||||
return tableName;
|
||||
}
|
||||
}
|
||||
@ -1,353 +0,0 @@
|
||||
import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {TransactionAlreadyStartedError} from "../../error/TransactionAlreadyStartedError";
|
||||
import {TransactionNotStartedError} from "../../error/TransactionNotStartedError";
|
||||
import {Table} from "../../schema-builder/table/Table";
|
||||
import {QueryRunnerAlreadyReleasedError} from "../../error/QueryRunnerAlreadyReleasedError";
|
||||
import {QueryFailedError} from "../../error/QueryFailedError";
|
||||
import {AbstractSqliteQueryRunner} from "../sqlite-abstract/AbstractSqliteQueryRunner";
|
||||
import {WebsqlDriver} from "./WebsqlDriver";
|
||||
import {Broadcaster} from "../../subscriber/Broadcaster";
|
||||
|
||||
/**
|
||||
* Declare a global function that is only available in browsers that support WebSQL.
|
||||
*/
|
||||
declare function openDatabase(...params: any[]): any;
|
||||
|
||||
/**
|
||||
* Runs queries on a single websql database connection.
|
||||
*/
|
||||
export class WebsqlQueryRunner extends AbstractSqliteQueryRunner {
|
||||
|
||||
/**
|
||||
* Real database connection from a connection pool used to perform queries.
|
||||
*/
|
||||
protected databaseConnection: any;
|
||||
|
||||
/**
|
||||
* Promise used to obtain a database connection for a first time.
|
||||
*/
|
||||
protected databaseConnectionPromise: Promise<any>;
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: WebsqlDriver;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(driver: WebsqlDriver) {
|
||||
super();
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.broadcaster = new Broadcaster(this);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates/uses database connection from the connection pool to perform further operations.
|
||||
* Returns obtained database connection.
|
||||
*/
|
||||
connect(): Promise<any> {
|
||||
if (this.databaseConnection)
|
||||
return Promise.resolve(this.databaseConnection);
|
||||
|
||||
if (this.databaseConnectionPromise)
|
||||
return this.databaseConnectionPromise;
|
||||
|
||||
const options = Object.assign({}, {
|
||||
database: this.driver.options.database,
|
||||
version: this.driver.options.version,
|
||||
description: this.driver.options.description,
|
||||
size: this.driver.options.size,
|
||||
}, this.driver.options.extra || {});
|
||||
|
||||
this.databaseConnectionPromise = new Promise<void>((ok, fail) => {
|
||||
this.databaseConnection = openDatabase(
|
||||
options.database,
|
||||
options.version,
|
||||
options.description,
|
||||
options.size,
|
||||
);
|
||||
ok(this.databaseConnection);
|
||||
});
|
||||
|
||||
return this.databaseConnectionPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts transaction.
|
||||
*/
|
||||
async startTransaction(): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
if (this.isTransactionActive)
|
||||
throw new TransactionAlreadyStartedError();
|
||||
|
||||
this.isTransactionActive = true;
|
||||
// await this.query("BEGIN TRANSACTION");
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits transaction.
|
||||
* Error will be thrown if transaction was not started.
|
||||
*/
|
||||
async commitTransaction(): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
if (!this.isTransactionActive)
|
||||
throw new TransactionNotStartedError();
|
||||
|
||||
// await this.query("COMMIT");
|
||||
this.isTransactionActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollbacks transaction.
|
||||
* Error will be thrown if transaction was not started.
|
||||
*/
|
||||
async rollbackTransaction(): Promise<void> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
if (!this.isTransactionActive)
|
||||
throw new TransactionNotStartedError();
|
||||
|
||||
// await this.query("ROLLBACK");
|
||||
this.isTransactionActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given SQL query.
|
||||
*/
|
||||
query(query: string, parameters?: any[]): Promise<any> {
|
||||
if (this.isReleased)
|
||||
throw new QueryRunnerAlreadyReleasedError();
|
||||
|
||||
return new Promise(async (ok, fail) => {
|
||||
try {
|
||||
const db = await this.connect();
|
||||
// todo(dima): check if transaction is not active
|
||||
|
||||
this.driver.connection.logger.logQuery(query, parameters, this);
|
||||
const queryStartTime = +new Date();
|
||||
|
||||
db.transaction((tx: any) => {
|
||||
tx.executeSql(query, parameters, (tx: any, result: any) => {
|
||||
|
||||
// log slow queries if maxQueryExecution time is set
|
||||
const maxQueryExecutionTime = this.driver.connection.options.maxQueryExecutionTime;
|
||||
const queryEndTime = +new Date();
|
||||
const queryExecutionTime = queryEndTime - queryStartTime;
|
||||
if (maxQueryExecutionTime && queryExecutionTime > maxQueryExecutionTime)
|
||||
this.driver.connection.logger.logQuerySlow(queryExecutionTime, query, parameters, this);
|
||||
|
||||
if (query.substr(0, 11) === "INSERT INTO") {
|
||||
ok(result.insertId);
|
||||
}
|
||||
else {
|
||||
const rows = Object
|
||||
.keys(result.rows)
|
||||
.filter(key => key !== "length")
|
||||
.map(key => result.rows[key]);
|
||||
ok(rows);
|
||||
}
|
||||
|
||||
}, (tx: any, err: any) => {
|
||||
this.driver.connection.logger.logQueryError(err, query, parameters, this);
|
||||
return fail(new QueryFailedError(query, parameters, err));
|
||||
});
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
fail(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new row with given values into the given table.
|
||||
* Returns value of the generated column if given and generate column exist in the table.
|
||||
// todo: check if it works
|
||||
async insert(tableName: string, keyValues: ObjectLiteral): Promise<InsertResult> {
|
||||
const keys = Object.keys(keyValues);
|
||||
const columns = keys.map(key => `"${key}"`).join(", ");
|
||||
const values = keys.map((key, index) => "$" + (index + 1)).join(",");
|
||||
const generatedColumns = this.connection.hasMetadata(tableName) ? this.connection.getMetadata(tableName).generatedColumns : [];
|
||||
const sql = columns.length > 0 ? (`INSERT INTO "${tableName}"(${columns}) VALUES (${values})`) : `INSERT INTO "${tableName}" DEFAULT VALUES`;
|
||||
const parameters = keys.map(key => keyValues[key]);
|
||||
|
||||
return new Promise<InsertResult>(async (ok, fail) => {
|
||||
this.driver.connection.logger.logQuery(sql, parameters, this);
|
||||
|
||||
const db = await this.connect();
|
||||
// todo: check if transaction is not active
|
||||
db.transaction((tx: any) => {
|
||||
tx.executeSql(sql, parameters, (tx: any, result: any) => {
|
||||
const generatedMap = generatedColumns.reduce((map, generatedColumn) => {
|
||||
const value = generatedColumn.isPrimary && generatedColumn.generationStrategy === "increment" && result["insertId"] ? result["insertId"] : keyValues[generatedColumn.databaseName];
|
||||
if (!value) return map;
|
||||
return OrmUtils.mergeDeep(map, generatedColumn.createValueMap(value));
|
||||
}, {} as ObjectLiteral);
|
||||
|
||||
ok({
|
||||
result: undefined,
|
||||
generatedMap: Object.keys(generatedMap).length > 0 ? generatedMap : undefined
|
||||
});
|
||||
|
||||
}, (tx: any, err: any) => {
|
||||
this.driver.connection.logger.logQueryError(err, sql, parameters, this);
|
||||
return fail(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}*/
|
||||
|
||||
// TODO: finish the table schema loading
|
||||
/**
|
||||
* Loads all tables (with given names) from the database and creates a Table from them.
|
||||
*/
|
||||
async getTables(tableNames: string[]): Promise<Table[]> {
|
||||
|
||||
// if no tables given then no need to proceed
|
||||
if (!tableNames || !tableNames.length)
|
||||
return [];
|
||||
|
||||
const tableNamesString = tableNames.map(tableName => `'${tableName}'`).join(", ");
|
||||
|
||||
// load tables, columns, indices and foreign keys
|
||||
const dbTables: ObjectLiteral[] = await this.query(`SELECT * FROM sqlite_master WHERE type = 'table' AND name IN (${tableNamesString})`);
|
||||
|
||||
// if tables were not found in the db, no need to proceed
|
||||
if (!dbTables || !dbTables.length)
|
||||
return [];
|
||||
|
||||
// create table schemas for loaded tables
|
||||
return Promise.all(dbTables.map(async dbTable => {
|
||||
const table = new Table({name: dbTable["name"]});
|
||||
|
||||
// load columns and indices
|
||||
/*const [dbColumns, dbIndices, dbForeignKeys]: ObjectLiteral[][] = await Promise.all([
|
||||
this.query(`PRAGMA table_info("${dbTable["name"]}")`),
|
||||
this.query(`PRAGMA index_list("${dbTable["name"]}")`),
|
||||
this.query(`PRAGMA foreign_key_list("${dbTable["name"]}")`),
|
||||
]);
|
||||
|
||||
// find column name with auto increment
|
||||
let autoIncrementColumnName: string|undefined = undefined;
|
||||
const tableSql: string = dbTable["sql"];
|
||||
if (tableSql.indexOf("AUTOINCREMENT") !== -1) {
|
||||
autoIncrementColumnName = tableSql.substr(0, tableSql.indexOf("AUTOINCREMENT"));
|
||||
const comma = autoIncrementColumnName.lastIndexOf(",");
|
||||
const bracket = autoIncrementColumnName.lastIndexOf("(");
|
||||
if (comma !== -1) {
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(comma);
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(0, autoIncrementColumnName.lastIndexOf("\""));
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(autoIncrementColumnName.indexOf("\"") + 1);
|
||||
|
||||
} else if (bracket !== -1) {
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(bracket);
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(0, autoIncrementColumnName.lastIndexOf("\""));
|
||||
autoIncrementColumnName = autoIncrementColumnName.substr(autoIncrementColumnName.indexOf("\"") + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// create columns from the loaded columns
|
||||
table.columns = dbColumns.map(dbColumn => {
|
||||
const tableColumn = new TableColumn();
|
||||
tableColumn.table = table;
|
||||
tableColumn.name = dbColumn["name"];
|
||||
tableColumn.type = dbColumn["type"].toLowerCase();
|
||||
tableColumn.default = dbColumn["dflt_value"] !== null && dbColumn["dflt_value"] !== undefined ? dbColumn["dflt_value"] : undefined;
|
||||
tableColumn.isNullable = dbColumn["notnull"] === 0;
|
||||
tableColumn.isPrimary = dbColumn["pk"] === 1;
|
||||
tableColumn.comment = ""; // todo later
|
||||
tableColumn.isGenerated = autoIncrementColumnName === dbColumn["name"];
|
||||
const columnForeignKeys = dbForeignKeys
|
||||
.filter(foreignKey => foreignKey["from"] === dbColumn["name"])
|
||||
.map(foreignKey => {
|
||||
const keyName = namingStrategy.foreignKeyName(dbTable["name"], [foreignKey["from"]], foreignKey["table"], [foreignKey["to"]]);
|
||||
return new TableForeignKey(keyName, [foreignKey["from"]], [foreignKey["to"]], foreignKey["table"], foreignKey["on_delete"]); // todo: how sqlite return from and to when they are arrays? (multiple column foreign keys)
|
||||
});
|
||||
table.addForeignKeys(columnForeignKeys);
|
||||
return tableColumn;
|
||||
});
|
||||
|
||||
// create primary key schema
|
||||
await Promise.all(dbIndices
|
||||
.filter(index => index["origin"] === "pk")
|
||||
.map(async index => {
|
||||
const indexInfos: ObjectLiteral[] = await this.query(`PRAGMA index_info("${index["name"]}")`);
|
||||
const indexColumns = indexInfos.map(indexInfo => indexInfo["name"]);
|
||||
indexColumns.forEach(indexColumn => {
|
||||
table.primaryKeys.push(new TablePrimaryKey(index["name"], indexColumn));
|
||||
});
|
||||
}));
|
||||
|
||||
// create index schemas from the loaded indices
|
||||
const indicesPromises = dbIndices
|
||||
.filter(dbIndex => {
|
||||
return dbIndex["origin"] !== "pk" &&
|
||||
(!table.foreignKeys.find(foreignKey => foreignKey.name === dbIndex["name"])) &&
|
||||
(!table.primaryKeys.find(primaryKey => primaryKey.name === dbIndex["name"]));
|
||||
})
|
||||
.map(dbIndex => dbIndex["name"])
|
||||
.filter((value, index, self) => self.indexOf(value) === index) // unqiue
|
||||
.map(async dbIndexName => {
|
||||
const dbIndex = dbIndices.find(dbIndex => dbIndex["name"] === dbIndexName);
|
||||
const indexInfos: ObjectLiteral[] = await this.query(`PRAGMA index_info("${dbIndex!["name"]}")`);
|
||||
const indexColumns = indexInfos.map(indexInfo => indexInfo["name"]);
|
||||
|
||||
// check if db index is generated by sqlite itself and has special use case
|
||||
if (dbIndex!["name"].substr(0, "sqlite_autoindex".length) === "sqlite_autoindex") {
|
||||
if (dbIndex!["unique"] === 1) { // this means we have a special index generated for a column
|
||||
// so we find and update the column
|
||||
indexColumns.forEach(columnName => {
|
||||
const column = table.columns.find(column => column.name === columnName);
|
||||
if (column)
|
||||
column.isUnique = true;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
|
||||
} else {
|
||||
return new TableIndex(dbTable["name"], dbIndex!["name"], indexColumns, dbIndex!["unique"] === "1");
|
||||
}
|
||||
});
|
||||
|
||||
const indices = await Promise.all(indicesPromises);
|
||||
table.indices = indices.filter(index => !!index) as TableIndex[];*/
|
||||
|
||||
return table;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all tables from the currently connected database.
|
||||
*/
|
||||
async clearDatabase(): Promise<void> {
|
||||
// await this.query(`PRAGMA foreign_keys = OFF;`);
|
||||
await this.startTransaction();
|
||||
try {
|
||||
const selectDropsQuery = `select 'drop table "' || name || '";' as query from sqlite_master where type = 'table' and name != 'sqlite_sequence'`;
|
||||
const dropQueries: ObjectLiteral[] = await this.query(selectDropsQuery);
|
||||
await Promise.all(dropQueries.map(q => this.query(q["query"])));
|
||||
await this.commitTransaction();
|
||||
|
||||
} catch (error) {
|
||||
try { // we throw original error even if rollback thrown an error
|
||||
await this.rollbackTransaction();
|
||||
} catch (rollbackError) { }
|
||||
throw error;
|
||||
|
||||
// await this.query(`PRAGMA foreign_keys = ON;`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@ export class MissingDriverError extends Error {
|
||||
constructor(driverType: string) {
|
||||
super();
|
||||
Object.setPrototypeOf(this, MissingDriverError.prototype);
|
||||
this.message = `Wrong driver: "${driverType}" given. Supported drivers are: "cordova", "mariadb", "mongodb", "mssql", "mysql", "oracle", "postgres", "sqlite", "sqljs", "websql".`;
|
||||
this.message = `Wrong driver: "${driverType}" given. Supported drivers are: "cordova", "mariadb", "mongodb", "mssql", "mysql", "oracle", "postgres", "sqlite", "sqljs", "react-native".`;
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,7 +12,6 @@ import {ReturningStatementNotSupportedError} from "../error/ReturningStatementNo
|
||||
import {ReturningResultsEntityUpdator} from "./ReturningResultsEntityUpdator";
|
||||
import {SqljsDriver} from "../driver/sqljs/SqljsDriver";
|
||||
import {MysqlDriver} from "../driver/mysql/MysqlDriver";
|
||||
import {WebsqlDriver} from "../driver/websql/WebsqlDriver";
|
||||
import {BroadcasterResult} from "../subscriber/BroadcasterResult";
|
||||
import {AbstractSqliteDriver} from "../driver/sqlite-abstract/AbstractSqliteDriver";
|
||||
import {OrderByCondition} from "../find-options/OrderByCondition";
|
||||
@ -359,8 +358,7 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
|
||||
const newParameters: ObjectLiteral = {};
|
||||
let parametersCount = this.connection.driver instanceof MysqlDriver ||
|
||||
this.connection.driver instanceof OracleDriver ||
|
||||
this.connection.driver instanceof AbstractSqliteDriver ||
|
||||
this.connection.driver instanceof WebsqlDriver
|
||||
this.connection.driver instanceof AbstractSqliteDriver
|
||||
? 0 : Object.keys(this.expressionMap.nativeParameters).length;
|
||||
if (metadata) {
|
||||
EntityMetadata.createPropertyPath(metadata, valuesSet).forEach(propertyPath => {
|
||||
@ -389,8 +387,7 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
|
||||
|
||||
if (this.connection.driver instanceof MysqlDriver ||
|
||||
this.connection.driver instanceof OracleDriver ||
|
||||
this.connection.driver instanceof AbstractSqliteDriver ||
|
||||
this.connection.driver instanceof WebsqlDriver) {
|
||||
this.connection.driver instanceof AbstractSqliteDriver) {
|
||||
newParameters[paramName] = value;
|
||||
} else {
|
||||
this.expressionMap.nativeParameters[paramName] = value;
|
||||
@ -422,8 +419,7 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
|
||||
|
||||
if (this.connection.driver instanceof MysqlDriver ||
|
||||
this.connection.driver instanceof OracleDriver ||
|
||||
this.connection.driver instanceof AbstractSqliteDriver ||
|
||||
this.connection.driver instanceof WebsqlDriver) {
|
||||
this.connection.driver instanceof AbstractSqliteDriver) {
|
||||
newParameters[key] = value;
|
||||
} else {
|
||||
this.expressionMap.nativeParameters[key] = value;
|
||||
@ -439,8 +435,7 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
|
||||
// because some drivers like mysql depend on order of parameters
|
||||
if (this.connection.driver instanceof MysqlDriver ||
|
||||
this.connection.driver instanceof OracleDriver ||
|
||||
this.connection.driver instanceof AbstractSqliteDriver ||
|
||||
this.connection.driver instanceof WebsqlDriver) {
|
||||
this.connection.driver instanceof AbstractSqliteDriver) {
|
||||
this.expressionMap.nativeParameters = Object.assign(newParameters, this.expressionMap.nativeParameters);
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "../../../../src/index";
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
active: boolean;
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
import "reflect-metadata";
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Connection } from "../../../src/connection/Connection";
|
||||
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
|
||||
import { User } from "./entity/user";
|
||||
|
||||
describe("github issues > #1441 Does not load data with websql by running findone and contition boolean (Ionic)", () => {
|
||||
|
||||
let connections: Connection[] = [];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
enabledDrivers: ["websql"]
|
||||
}));
|
||||
beforeEach(() => reloadTestingDatabases(connections));
|
||||
after(() => closeTestingConnections(connections));
|
||||
|
||||
it("should to create a query using a boolean conditional that returns result", () => Promise.all(connections.map(async connection => {
|
||||
|
||||
const user = new User();
|
||||
user.name = "Timber";
|
||||
user.active = true;
|
||||
await user.save();
|
||||
|
||||
let loadeduser = await User.findOne({ active: true });
|
||||
|
||||
expect(loadeduser).not.to.be.undefined;
|
||||
|
||||
})));
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user