Comparing version 3.4.3 to 3.5.0
@@ -154,2 +154,11 @@ import { Extract, Dict, Awaitable, MaybeArray, Intersect } from 'cosmokit'; | ||
} | ||
interface IndexDef<K extends string = string> { | ||
name?: string; | ||
keys: { | ||
[P in K]?: 'asc' | 'desc'; | ||
}; | ||
} | ||
interface Index<K extends string = string> extends IndexDef<K> { | ||
unique?: boolean; | ||
} | ||
interface Transformer<S = any, T = any> { | ||
@@ -181,2 +190,5 @@ types: Field.Type<S>[]; | ||
abstract withTransaction(callback: (session?: any) => Promise<void>): Promise<void>; | ||
abstract getIndexes(table: string): Promise<Driver.Index[]>; | ||
abstract createIndex(table: string, index: Driver.Index): Promise<void>; | ||
abstract dropIndex(table: string, name: string): Promise<void>; | ||
database: Database<any, any, C>; | ||
@@ -190,2 +202,3 @@ logger: Logger; | ||
_ensureSession(): Promise<void>; | ||
prepareIndexes(table: string): Promise<void>; | ||
} | ||
@@ -310,2 +323,3 @@ export interface MigrationHooks { | ||
unique: MaybeArray<K>[]; | ||
indexes: (MaybeArray<K> | Driver.IndexDef<K>)[]; | ||
foreign: { | ||
@@ -321,2 +335,3 @@ [P in K]?: [string, string]; | ||
ctx?: Context; | ||
indexes: Driver.Index<FlatKeys<S>>[]; | ||
fields: Field.Config<S>; | ||
@@ -327,2 +342,3 @@ migrations: Map<Model.Migration<any>, string[]>; | ||
extend(fields: Field.Extension<S>, config?: Partial<Model.Config>): void; | ||
private parseIndex; | ||
private checkIndex; | ||
@@ -535,16 +551,16 @@ resolveValue(field: string | Field | Type, value: any): any; | ||
} | ||
type CreateMap<T, S> = { | ||
[K in keyof T]?: Create<T[K], S>; | ||
}; | ||
export type Create<T, S> = T extends Values<AtomicTypes> ? T : T extends (infer I extends Values<S>)[] ? CreateMap<I, S>[] | { | ||
type CreateUnit<T, S> = T extends Values<AtomicTypes> ? T : T extends (infer I extends Values<S>)[] ? Create<I, S>[] | { | ||
$literal?: DeepPartial<I>; | ||
$create?: MaybeArray<CreateMap<I, S>>; | ||
$upsert?: MaybeArray<CreateMap<I, S>>; | ||
$create?: MaybeArray<Create<I, S>>; | ||
$upsert?: MaybeArray<Create<I, S>>; | ||
$connect?: Query.Expr<Flatten<I>>; | ||
} : T extends Values<S> ? CreateMap<T, S> | { | ||
} : T extends Values<S> ? Create<T, S> | { | ||
$literal?: DeepPartial<T>; | ||
$create?: CreateMap<T, S>; | ||
$upsert?: CreateMap<T, S>; | ||
$create?: Create<T, S>; | ||
$upsert?: Create<T, S>; | ||
$connect?: Query.Expr<Flatten<T>>; | ||
} : T extends (infer U)[] ? DeepPartial<U>[] : T extends object ? CreateMap<T, S> : T; | ||
} : T extends (infer U)[] ? DeepPartial<U>[] : T extends object ? Create<T, S> : T; | ||
export type Create<T, S> = { | ||
[K in keyof T]?: CreateUnit<T[K], S>; | ||
}; | ||
export class Database<S = {}, N = {}, C extends Context = Context> extends Service<undefined, C> { | ||
@@ -551,0 +567,0 @@ static [Service.provide]: string; |
{ | ||
"name": "minato", | ||
"version": "3.4.3", | ||
"version": "3.5.0", | ||
"description": "Type Driven Database Framework", | ||
@@ -31,9 +31,9 @@ "type": "module", | ||
"type": "git", | ||
"url": "git+https://github.com/shigma/minato.git", | ||
"url": "git+https://github.com/cordiverse/minato.git", | ||
"directory": "packages/core" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/shigma/minato/issues" | ||
"url": "https://github.com/cordiverse/minato/issues" | ||
}, | ||
"homepage": "https://github.com/shigma/minato", | ||
"homepage": "https://github.com/cordiverse/minato", | ||
"keywords": [ | ||
@@ -65,4 +65,7 @@ "orm", | ||
}, | ||
"devDependencies": { | ||
"cordis": "^3.18.0" | ||
}, | ||
"peerDependencies": { | ||
"cordis": "^3.17.3" | ||
"cordis": "^3.18.0" | ||
}, | ||
@@ -69,0 +72,0 @@ "dependencies": { |
# minato | ||
[![Codecov](https://img.shields.io/codecov/c/github/shigma/minato?style=flat-square)](https://codecov.io/gh/shigma/minato) | ||
[![Codecov](https://img.shields.io/codecov/c/github/cordiverse/minato?style=flat-square)](https://codecov.io/gh/cordiverse/minato) | ||
[![downloads](https://img.shields.io/npm/dm/minato?style=flat-square)](https://www.npmjs.com/package/minato) | ||
[![npm](https://img.shields.io/npm/v/minato?style=flat-square)](https://www.npmjs.com/package/minato) | ||
[![GitHub](https://img.shields.io/github/license/shigma/minato?style=flat-square)](https://github.com/shigma/minato/blob/master/LICENSE) | ||
[![GitHub](https://img.shields.io/github/license/cordiverse/minato?style=flat-square)](https://github.com/cordiverse/minato/blob/master/LICENSE) | ||
@@ -22,7 +22,7 @@ Type Driven Database Framework. | ||
| ------ | ------ | ----- | | ||
| [Memory](https://github.com/shigma/minato/tree/master/packages/memory) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-memory?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-memory) | In-memory driver support | | ||
| [MongoDB](https://github.com/shigma/minato/tree/master/packages/mongo) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-mongo?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-mongo) | | | ||
| [MySQL](https://github.com/shigma/minato/tree/master/packages/mysql) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-mysql?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-mysql) | MySQL 5.7+, MariaDB 10.5 | | ||
| [PostgreSQL](https://github.com/shigma/minato/tree/master/packages/postgres) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-postgres?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-postgres) | PostgreSQL 14+ | | ||
| [SQLite](https://github.com/shigma/minato/tree/master/packages/sqlite) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-sqlite?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-sqlite) | | | ||
| [Memory](https://github.com/cordiverse/minato/tree/master/packages/memory) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-memory?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-memory) | In-memory driver support | | ||
| [MongoDB](https://github.com/cordiverse/minato/tree/master/packages/mongo) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-mongo?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-mongo) | | | ||
| [MySQL](https://github.com/cordiverse/minato/tree/master/packages/mysql) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-mysql?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-mysql) | MySQL 5.7+, MariaDB 10.5 | | ||
| [PostgreSQL](https://github.com/cordiverse/minato/tree/master/packages/postgres) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-postgres?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-postgres) | PostgreSQL 14+ | | ||
| [SQLite](https://github.com/cordiverse/minato/tree/master/packages/sqlite) | [![npm](https://img.shields.io/npm/v/@minatojs/driver-sqlite?style=flat-square)](https://www.npmjs.com/package/@minatojs/driver-sqlite) | | | ||
@@ -29,0 +29,0 @@ ## Basic Usage |
@@ -47,24 +47,24 @@ import { deduplicate, defineProperty, Dict, filterKeys, isNullable, makeArray, mapValues, MaybeArray, noop, omit, pick, remove } from 'cosmokit' | ||
type CreateMap<T, S> = { [K in keyof T]?: Create<T[K], S> } | ||
export type Create<T, S> = | ||
type CreateUnit<T, S> = | ||
| T extends Values<AtomicTypes> ? T | ||
: T extends (infer I extends Values<S>)[] ? CreateMap<I, S>[] | | ||
: T extends (infer I extends Values<S>)[] ? Create<I, S>[] | | ||
{ | ||
$literal?: DeepPartial<I> | ||
$create?: MaybeArray<CreateMap<I, S>> | ||
$upsert?: MaybeArray<CreateMap<I, S>> | ||
$create?: MaybeArray<Create<I, S>> | ||
$upsert?: MaybeArray<Create<I, S>> | ||
$connect?: Query.Expr<Flatten<I>> | ||
} | ||
: T extends Values<S> ? CreateMap<T, S> | | ||
: T extends Values<S> ? Create<T, S> | | ||
{ | ||
$literal?: DeepPartial<T> | ||
$create?: CreateMap<T, S> | ||
$upsert?: CreateMap<T, S> | ||
$create?: Create<T, S> | ||
$upsert?: Create<T, S> | ||
$connect?: Query.Expr<Flatten<T>> | ||
} | ||
: T extends (infer U)[] ? DeepPartial<U>[] | ||
: T extends object ? CreateMap<T, S> | ||
: T extends object ? Create<T, S> | ||
: T | ||
export type Create<T, S> = { [K in keyof T]?: CreateUnit<T[K], S> } | ||
function mergeQuery<T>(base: Query.FieldExpr<T>, query: Query.Expr<Flatten<T>> | ((row: Row<T>) => Query.Expr<Flatten<T>>)): Selection.Callback<T, boolean> { | ||
@@ -133,2 +133,3 @@ if (typeof query === 'function') { | ||
await driver.prepare(name) | ||
await driver.prepareIndexes(name) | ||
} | ||
@@ -194,5 +195,8 @@ | ||
// use relation field as primary | ||
if (Array.isArray(model.primary) && model.primary.every(key => model.fields[key]?.relation)) { | ||
model.primary = deduplicate(model.primary.map(key => model.fields[key]!.relation!.fields).flat()) | ||
if (Array.isArray(model.primary)) { | ||
model.primary = deduplicate(model.primary.map(key => model.fields[key]!.relation?.fields || key).flat()) | ||
} | ||
model.unique = model.unique.map(keys => typeof keys === 'string' ? model.fields[keys]!.relation?.fields || keys | ||
: keys.map(key => model.fields[key]!.relation?.fields || key).flat()) | ||
this.prepareTasks[name] = this.prepare(name) | ||
@@ -199,0 +203,0 @@ ;(this.ctx as Context).emit('model', name) |
@@ -1,2 +0,2 @@ | ||
import { Awaitable, defineProperty, Dict, mapValues, remove } from 'cosmokit' | ||
import { Awaitable, deepEqual, defineProperty, Dict, mapValues, remove } from 'cosmokit' | ||
import { Context, Logger, Service } from 'cordis' | ||
@@ -38,2 +38,11 @@ import { Eval, Update } from './eval.ts' | ||
export interface IndexDef<K extends string = string> { | ||
name?: string | ||
keys: { [P in K]?: 'asc' | 'desc' } | ||
} | ||
export interface Index<K extends string = string> extends IndexDef<K> { | ||
unique?: boolean | ||
} | ||
export interface Transformer<S = any, T = any> { | ||
@@ -66,2 +75,5 @@ types: Field.Type<S>[] | ||
abstract withTransaction(callback: (session?: any) => Promise<void>): Promise<void> | ||
abstract getIndexes(table: string): Promise<Driver.Index[]> | ||
abstract createIndex(table: string, index: Driver.Index): Promise<void> | ||
abstract dropIndex(table: string, name: string): Promise<void> | ||
@@ -156,2 +168,16 @@ public database: Database<any, any, C> | ||
async _ensureSession() {} | ||
async prepareIndexes(table: string) { | ||
const oldIndexes = await this.getIndexes(table) | ||
const { indexes } = this.model(table) | ||
for (const index of indexes) { | ||
const oldIndex = oldIndexes.find(info => info.name === index.name) | ||
if (!oldIndex) { | ||
await this.createIndex(table, index) | ||
} else if (!deepEqual(oldIndex, index)) { | ||
await this.dropIndex(table, index.name!) | ||
await this.createIndex(table, index) | ||
} | ||
} | ||
} | ||
} | ||
@@ -158,0 +184,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { clone, filterKeys, isNullable, makeArray, mapValues, MaybeArray } from 'cosmokit' | ||
import { clone, deepEqual, filterKeys, isNullable, makeArray, mapValues, MaybeArray } from 'cosmokit' | ||
import { Context } from 'cordis' | ||
@@ -74,4 +74,4 @@ import { Eval, Update } from './eval.ts' | ||
: def.shared | ||
const fields = def.fields ?? ((subprimary || model.name === relmodel.name || def.type === 'manyToOne' | ||
|| (def.type === 'oneToOne' && !makeArray(relmodel.primary).every(key => !relmodel.fields[key]?.nullable))) | ||
const fields = def.fields ?? ((subprimary || def.type === 'manyToOne' | ||
|| (def.type === 'oneToOne' && (model.name === relmodel.name || !makeArray(relmodel.primary).every(key => !relmodel.fields[key]?.nullable)))) | ||
? makeArray(relmodel.primary).map(x => `${key}.${x}`) : model.primary) | ||
@@ -251,2 +251,3 @@ const relation: Config = { | ||
unique: MaybeArray<K>[] | ||
indexes: (MaybeArray<K> | Driver.IndexDef<K>)[] | ||
foreign: { | ||
@@ -262,2 +263,3 @@ [P in K]?: [string, string] | ||
declare ctx?: Context | ||
declare indexes: Driver.Index<FlatKeys<S>>[] | ||
fields: Field.Config<S> = {} | ||
@@ -272,2 +274,3 @@ migrations = new Map<Model.Migration, string[]>() | ||
this.unique = [] | ||
this.indexes = [] | ||
this.foreign = {} | ||
@@ -278,3 +281,3 @@ } | ||
extend(fields = {}, config: Partial<Model.Config> = {}) { | ||
const { primary, autoInc, unique = [] as [], foreign, callback } = config | ||
const { primary, autoInc, unique = [], indexes = [], foreign, callback } = config | ||
@@ -284,2 +287,3 @@ this.primary = primary || this.primary | ||
unique.forEach(key => this.unique.includes(key) || this.unique.push(key)) | ||
indexes.map(x => this.parseIndex(x)).forEach(index => (this.indexes.some(ind => deepEqual(ind, index))) || this.indexes.push(index)) | ||
Object.assign(this.foreign, foreign) | ||
@@ -301,6 +305,23 @@ | ||
this.unique.forEach(index => this.checkIndex(index)) | ||
this.indexes.forEach(index => this.checkIndex(index)) | ||
} | ||
private checkIndex(index: MaybeArray<string>) { | ||
for (const key of makeArray(index)) { | ||
private parseIndex(index: MaybeArray<string> | Driver.Index): Driver.Index { | ||
if (typeof index === 'string' || Array.isArray(index)) { | ||
return { | ||
name: `index:${this.name}:` + makeArray(index).join('+'), | ||
unique: false, | ||
keys: Object.fromEntries(makeArray(index).map(key => [key, 'asc'])), | ||
} | ||
} else { | ||
return { | ||
name: index.name ?? `index:${this.name}:` + Object.keys(index.keys).join('+'), | ||
unique: index.unique ?? false, | ||
keys: index.keys, | ||
} | ||
} | ||
} | ||
private checkIndex(index: MaybeArray<string> | Driver.Index) { | ||
for (const key of typeof index === 'string' || Array.isArray(index) ? makeArray(index) : Object.keys(index.keys)) { | ||
if (!this.fields[key]) { | ||
@@ -307,0 +328,0 @@ throw new TypeError(`missing field definition for index key "${key}"`) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
483067
1
7297