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:
Daniel Lang 2018-04-12 17:23:00 +02:00
parent 926ce07444
commit 3a8bb3b3b2
18 changed files with 21 additions and 690 deletions

View File

@ -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

View File

@ -15,7 +15,7 @@
[ ] `postgres`
[ ] `sqlite`
[ ] `sqljs`
[ ] `websql`
[ ] `react-native`
**TypeORM version:**

View File

@ -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.

View File

@ -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

View File

@ -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`,

View File

@ -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
],

View File

@ -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",

View File

@ -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",

View File

@ -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|

View File

@ -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:

View File

@ -11,5 +11,4 @@ export type DatabaseType =
"sqljs"|
"oracle"|
"mssql"|
"websql"|
"mongodb";

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;`);
}
}
}

View File

@ -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".`;
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
})));
});