Comparing version 3.5.1 to 3.6.0
@@ -130,2 +130,5 @@ import { Extract, Dict, Awaitable, MaybeArray, Intersect } from 'cosmokit'; | ||
} | ||
export namespace Selection { | ||
function is(sel: any): sel is Selection; | ||
} | ||
export function executeSort(data: any[], modifier: Modifier, name: string): any[]; | ||
@@ -360,2 +363,3 @@ export namespace Driver { | ||
export const kType: unique symbol; | ||
export const Any: Type; | ||
export const Boolean: Type<boolean>; | ||
@@ -374,3 +378,3 @@ export const Number: Type<number>; | ||
export function isType(value: any): value is Type; | ||
export function isArray(type: Type): boolean | undefined; | ||
export function isArray(type?: Type): boolean | undefined; | ||
export function getInner(type?: Type, key?: string): Type | undefined; | ||
@@ -469,2 +473,4 @@ export function transform(value: any, type: Type, callback: (value: any, type?: Type) => any): any; | ||
array<T>(value: Expr<T, false>): Expr<T[], true>; | ||
get<T extends object, K extends keyof T, A extends boolean>(x: Term<T, A>, key: K): Expr<T[K], A>; | ||
get<T extends any, A extends boolean>(x: Array<T, A>, index: Term<number, A>): Expr<T, A>; | ||
} | ||
@@ -564,4 +570,2 @@ } | ||
export class Database<S = {}, N = {}, C extends Context = Context> extends Service<undefined, C> { | ||
static [Service.provide]: string; | ||
static [Service.immediate]: boolean; | ||
static readonly transact: unique symbol; | ||
@@ -576,2 +580,3 @@ static readonly migrate: unique symbol; | ||
migrateTasks: Dict<Promise<void>>; | ||
constructor(ctx?: C); | ||
connect<T = undefined>(driver: Driver.Constructor<T>, ...args: Spread<T>): Promise<void>; | ||
@@ -578,0 +583,0 @@ refresh(): void; |
{ | ||
"name": "minato", | ||
"version": "3.5.1", | ||
"version": "3.6.0", | ||
"description": "Type Driven Database Framework", | ||
@@ -65,6 +65,6 @@ "type": "module", | ||
"devDependencies": { | ||
"cordis": "^3.18.0" | ||
"cordis": "^3.18.1" | ||
}, | ||
"peerDependencies": { | ||
"cordis": "^3.18.0" | ||
"cordis": "^3.18.1" | ||
}, | ||
@@ -71,0 +71,0 @@ "dependencies": { |
@@ -81,5 +81,2 @@ import { deduplicate, defineProperty, Dict, filterKeys, isNullable, makeArray, mapValues, MaybeArray, noop, omit, pick, remove } from 'cosmokit' | ||
export class Database<S = {}, N = {}, C extends Context = Context> extends Service<undefined, C> { | ||
static [Service.provide] = 'model' | ||
static [Service.immediate] = true | ||
static readonly transact = Symbol('minato.transact') | ||
@@ -97,2 +94,7 @@ static readonly migrate = Symbol('minato.migrate') | ||
constructor(ctx?: C) { | ||
ctx ||= new Context() as C | ||
super(ctx, 'model', true) | ||
} | ||
async connect<T = undefined>(driver: Driver.Constructor<T>, ...args: Spread<T>) { | ||
@@ -115,3 +117,3 @@ this.ctx.plugin(driver, args[0] as any) | ||
private getDriver(table: string | Selection): Driver<any, C> { | ||
if (table instanceof Selection) return table.driver as any | ||
if (Selection.is(table)) return table.driver as any | ||
const model: Model = this.tables[table] | ||
@@ -156,6 +158,7 @@ if (!model) throw new Error(`cannot resolve table "${table}"`) | ||
const [relation, inverse] = Relation.parse(def, key, model, this.tables[def.table ?? key], subprimary) | ||
if (!this.tables[relation.table]) throw new Error(`relation table ${relation.table} does not exist`) | ||
const relmodel = this.tables[relation.table] | ||
if (!relmodel) throw new Error(`relation table ${relation.table} does not exist`) | ||
;(model.fields[key] = Field.parse('expr')).relation = relation | ||
if (def.target) { | ||
(this.tables[relation.table].fields[def.target] ??= Field.parse('expr')).relation = inverse | ||
(relmodel.fields[def.target] ??= Field.parse('expr')).relation = inverse | ||
} | ||
@@ -165,3 +168,3 @@ | ||
relation.fields.forEach((x, i) => { | ||
model.fields[x] ??= { ...this.tables[relation.table].fields[relation.references[i]] } as any | ||
model.fields[x] ??= { ...relmodel.fields[relation.references[i]] } as any | ||
if (!relation.required) { | ||
@@ -177,3 +180,3 @@ model.fields[x]!.nullable = true | ||
const fields = relation.fields.map(x => [Relation.buildAssociationKey(x, name), model.fields[x]!.deftype] as const) | ||
const references = relation.references.map((x, i) => [Relation.buildAssociationKey(x, relation.table), fields[i][1]] as const) | ||
const references = relation.references.map(x => [Relation.buildAssociationKey(x, relation.table), relmodel.fields[x]?.deftype] as const) | ||
this.extend(assocTable as any, { | ||
@@ -199,4 +202,4 @@ ...Object.fromEntries([...shared, ...fields, ...references]), | ||
// use relation field as primary | ||
if (Array.isArray(model.primary)) { | ||
model.primary = deduplicate(model.primary.map(key => model.fields[key]!.relation?.fields || key).flat()) | ||
if (Array.isArray(model.primary) || model.fields[model.primary]!.relation) { | ||
model.primary = deduplicate(makeArray(model.primary).map(key => model.fields[key]!.relation?.fields || key).flat()) | ||
} | ||
@@ -213,7 +216,7 @@ model.unique = model.unique.map(keys => typeof keys === 'string' ? model.fields[keys]!.relation?.fields || keys | ||
setInitial?.({}) | ||
setField?.({ type: 'json', initial: {} }) | ||
setField?.({ initial: {}, deftype: 'json', type: Type.Object() }) | ||
return Type.Object() | ||
} else if (field === 'array') { | ||
setInitial?.([]) | ||
setField?.({ type: 'json', initial: [] }) | ||
setField?.({ initial: [], deftype: 'json', type: Type.Array() }) | ||
return Type.Array() | ||
@@ -220,0 +223,0 @@ } else if (typeof field === 'string' && this.types[field]) { |
@@ -114,4 +114,4 @@ import { Awaitable, deepEqual, defineProperty, Dict, mapValues, remove } from 'cosmokit' | ||
if (table instanceof Selection) { | ||
if (!table.args[0].fields && (typeof table.table === 'string' || table.table instanceof Selection)) { | ||
if (Selection.is(table)) { | ||
if (!table.args[0].fields && (typeof table.table === 'string' || Selection.is(table.table))) { | ||
return table.model | ||
@@ -118,0 +118,0 @@ } |
@@ -152,2 +152,5 @@ import { defineProperty, isNullable, mapValues } from 'cosmokit' | ||
array<T>(value: Expr<T, false>): Expr<T[], true> | ||
get<T extends object, K extends keyof T, A extends boolean>(x: Term<T, A>, key: K): Expr<T[K], A> | ||
get<T extends any, A extends boolean>(x: Array<T, A>, index: Term<number, A>): Expr<T, A> | ||
} | ||
@@ -196,5 +199,7 @@ } | ||
Eval.ignoreNull = (expr) => (expr[Type.kType]!.ignoreNull = true, expr) | ||
// special forms | ||
Eval.ignoreNull = (expr) => (expr['$ignoreNull'] = true, expr[Type.kType]!.ignoreNull = true, expr) | ||
Eval.select = multary('select', (args, table) => args.map(arg => executeEval(table, arg)), Type.Array()) | ||
Eval.query = (row, query, expr = true) => ({ $expr: expr, ...query }) as any | ||
Eval.exec = unary('exec', (expr, data) => (expr.driver as any).executeSelection(expr, data), (expr) => Type.fromTerm(expr.args[0])) | ||
@@ -332,3 +337,3 @@ // univeral | ||
Eval.exec = unary('exec', (expr, data) => (expr.driver as any).executeSelection(expr, data), (expr) => Type.fromTerm(expr.args[0])) | ||
Eval.get = multary('get', ([x, key], data) => executeEval(data, x)?.[executeEval(data, key)], (x, key) => Type.getInner(Type.fromTerm(x), key) ?? Type.Any) | ||
@@ -335,0 +340,0 @@ export { Eval as $ } |
@@ -1,2 +0,2 @@ | ||
import { clone, deepEqual, filterKeys, isNullable, makeArray, mapValues, MaybeArray } from 'cosmokit' | ||
import { clone, deepEqual, defineProperty, filterKeys, isNullable, makeArray, mapValues, MaybeArray } from 'cosmokit' | ||
import { Context } from 'cordis' | ||
@@ -265,3 +265,3 @@ import { Eval, Update } from './eval.ts' | ||
private type: Type<S> | undefined | ||
declare private type: Type<S> | undefined | ||
@@ -446,5 +446,5 @@ constructor(public name: string) { | ||
getType(key?: string): Type | undefined { | ||
this.type ??= Type.Object(mapValues(this.fields!, field => Type.fromField(field!))) as any | ||
if (!this.type) defineProperty(this, 'type', Type.Object(mapValues(this.fields, field => Type.fromField(field!))) as any) | ||
return key ? Type.getInner(this.type, key) : this.type | ||
} | ||
} |
@@ -41,3 +41,3 @@ import { defineProperty, Dict, filterKeys, mapValues } from 'cosmokit' | ||
const createRow = (ref: string, expr = {}, prefix = '', model?: Model) => new Proxy(expr, { | ||
const createRow = (ref: string, expr = {}, prefix = '', model?: Model, intermediate?: Eval.Expr) => new Proxy(expr, { | ||
get(target, key) { | ||
@@ -48,5 +48,17 @@ if (key === '$prefix') return prefix | ||
if (intermediate) { | ||
if (Type.isArray(expr?.[Type.kType]) && Number.isInteger(+key)) { | ||
return createRow(ref, Eval.get(expr as any, +key), '', model, Eval.get(expr as any, +key)) | ||
} else { | ||
return createRow(ref, Eval.get(intermediate as any, `${prefix}${key}`), `${prefix}${key}.`, model, intermediate) | ||
} | ||
} | ||
let type: Type | ||
const field = model?.fields[prefix + key as string] | ||
if (Type.getInner(expr?.[Type.kType], key)) { | ||
if (Type.isArray(expr?.[Type.kType]) && Number.isInteger(+key)) { | ||
// indexing array | ||
type = Type.getInner(expr?.[Type.kType]) ?? Type.fromField('expr') | ||
return createRow(ref, Eval.get(expr as any, +key), '', model, Eval.get(expr as any, +key)) | ||
} else if (Type.getInner(expr?.[Type.kType], key)) { | ||
// type may conatins object layout | ||
@@ -322,2 +334,8 @@ type = Type.getInner(expr?.[Type.kType], key)! | ||
export namespace Selection { | ||
export function is(sel: any): sel is Selection { | ||
return sel && !!sel.tables as any | ||
} | ||
} | ||
export function executeSort(data: any[], modifier: Modifier, name: string) { | ||
@@ -324,0 +342,0 @@ const { limit, offset, sort } = modifier |
@@ -20,5 +20,6 @@ import { Binary, defineProperty, isNullable, mapValues } from 'cosmokit' | ||
export const Boolean: Type<boolean> = defineProperty({ type: 'boolean' }, kType, true) as any | ||
export const Number: Type<number> = defineProperty({ type: 'double' }, kType, true) | ||
export const String: Type<string> = defineProperty({ type: 'string' }, kType, true) | ||
export const Any: Type = fromField('expr') | ||
export const Boolean: Type<boolean> = fromField('boolean') | ||
export const Number: Type<number> = fromField('double') | ||
export const String: Type<string> = fromField('string') | ||
@@ -80,4 +81,4 @@ type Extract<T> = | ||
export function isArray(type: Type) { | ||
return (type.type === 'json') && type.array | ||
export function isArray(type?: Type) { | ||
return (type?.type === 'json') && type?.array | ||
} | ||
@@ -87,10 +88,10 @@ | ||
if (!type?.inner) return | ||
if (isArray(type) && isNullable(key)) return type.inner | ||
if (isArray(type)) return type.inner | ||
if (isNullable(key)) return | ||
if (type.inner[key]) return type.inner[key] | ||
if (key.includes('.')) return key.split('.').reduce((t, k) => getInner(t, k), type) | ||
return Object(globalThis.Object.fromEntries(globalThis.Object.entries(type.inner) | ||
const fields = globalThis.Object.entries(type.inner) | ||
.filter(([k]) => k.startsWith(`${key}.`)) | ||
.map(([k, v]) => [k.slice(key.length + 1), v]), | ||
)) | ||
.map(([k, v]) => [k.slice(key.length + 1), v]) | ||
return fields.length ? Object(globalThis.Object.fromEntries(fields)) : undefined | ||
} | ||
@@ -97,0 +98,0 @@ |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
491941
7384