swc/crates/swc_bundler/tests/.cache/deno/91d50db2db9f158f1437cc38fc3506a9de0bc11c.ts
2021-11-09 20:42:49 +09:00

225 lines
5.6 KiB
TypeScript

// Loaded from https://deno.land/x/denodb@v1.0.18/lib/database.ts
import type { Connector } from "./connectors/connector.ts";
import type {
FieldMatchingTable,
Model,
ModelFields,
ModelSchema,
} from "./model.ts";
import { QueryBuilder, QueryDescription } from "./query-builder.ts";
import {
PostgresConnector,
PostgresOptions,
} from "./connectors/postgres-connector.ts";
import {
SQLite3Connector,
SQLite3Options,
} from "./connectors/sqlite3-connector.ts";
import { MySQLConnector, MySQLOptions } from "./connectors/mysql-connector.ts";
import {
MongoDBConnector,
MongoDBOptions,
} from "./connectors/mongodb-connector.ts";
import { formatResultToModelInstance } from "./helpers/results.ts";
import { Translator } from "./translators/translator.ts";
import { SQLTranslator } from "./translators/sql-translator.ts";
type DatabaseOptions =
| DatabaseDialect
| {
dialect: DatabaseDialect;
debug?: boolean;
};
export type SyncOptions = {
/** If tables should be dropped if they exist. */
drop?: boolean;
};
export type DatabaseDialect = "postgres" | "sqlite3" | "mysql" | "mongo";
/** Database client which interacts with an external database instance. */
export class Database {
private _dialect: DatabaseDialect;
private _connector: Connector;
private _queryBuilder: QueryBuilder;
private _models: ModelSchema[] = [];
private _debug: boolean;
/** Initialize database given a dialect and options.
*
* const db = new Database("sqlite3", {
* filepath: "./db.sqlite"
* });
*
* const db = new Database({
* dialect: "sqlite3",
* debug: true
* }, { ... });
*/
constructor(
databaseOptionsOrDialect: DatabaseOptions,
connectionOptions:
| PostgresOptions
| SQLite3Options
| MySQLOptions
| MongoDBOptions,
) {
this._dialect = typeof databaseOptionsOrDialect === "object"
? databaseOptionsOrDialect.dialect
: databaseOptionsOrDialect;
this._debug = typeof databaseOptionsOrDialect === "object"
? databaseOptionsOrDialect.debug ?? false
: false;
this._queryBuilder = new QueryBuilder();
switch (this._dialect) {
case "postgres":
this._connector = new PostgresConnector(
connectionOptions as PostgresOptions,
);
break;
case "sqlite3":
this._connector = new SQLite3Connector(
connectionOptions as SQLite3Options,
);
break;
case "mysql":
this._connector = new MySQLConnector(connectionOptions as MySQLOptions);
break;
case "mongo":
this._connector = new MongoDBConnector(
connectionOptions as MongoDBOptions,
);
break;
default:
throw new Error(
`No connector was found for the given dialect: ${this._dialect}.`,
);
}
}
/** Test database connection. */
ping() {
return this._connector.ping();
}
/** Get the database dialect. */
getDialect() {
return this._dialect;
}
/* Get the database connector. */
getConnector() {
return this._connector;
}
/** Create the given models in the current database.
*
* await db.sync({ drop: true });
*/
async sync(options: SyncOptions = {}) {
if (options.drop) {
for (const model of this._models) {
await model.drop();
}
}
for (const model of this._models) {
await model.createTable();
}
}
/** Associate all the required information for a model to connect to a database.
*
* await db.link([Flight, Airport]);
*/
link(models: ModelSchema[]) {
this._models = models;
this._models.forEach((model) =>
model._link({
queryBuilder: this._queryBuilder,
database: this,
})
);
return this;
}
/** Pass on any query to the database.
*
* await db.query("SELECT * FROM `flights`");
*/
async query(query: QueryDescription): Promise<Model | Model[]> {
if (this._debug) {
console.log(query);
}
const results = await this._connector.query(query);
return Array.isArray(results)
? results.map((result) =>
formatResultToModelInstance(query.schema, result)
)
: formatResultToModelInstance(query.schema, results);
}
/** Compute field matchings tables for model usage. */
_computeModelFieldMatchings(
table: string,
fields: ModelFields,
withTimestamps: boolean,
): {
toClient: FieldMatchingTable;
toDatabase: FieldMatchingTable;
} {
const databaseDialect = this.getDialect();
const translator = databaseDialect === "mongo"
? new Translator()
: new SQLTranslator(databaseDialect);
const modelFields = { ...fields };
if (withTimestamps) {
modelFields.updatedAt = "";
modelFields.createdAt = "";
}
const toDatabase: FieldMatchingTable = Object.entries(modelFields).reduce(
(prev: any, [clientFieldName, fieldType]) => {
const databaseFieldName = typeof fieldType !== "string" && fieldType.as
? fieldType.as
: (translator.formatFieldNameToDatabase(clientFieldName) as string);
prev[clientFieldName] = databaseFieldName;
prev[`${table}.${clientFieldName}`] = `${table}.${databaseFieldName}`;
return prev;
},
{},
);
const toClient: FieldMatchingTable = Object.entries(toDatabase).reduce(
(prev, [clientFieldName, databaseFieldName]) => ({
...prev,
[databaseFieldName]: clientFieldName,
}),
{},
);
return { toDatabase, toClient };
}
/** Close the current database connection. */
async close() {
return this._connector.close();
}
}