refactor(database): model toJSON without the hidden fields
This commit is contained in:
parent
e140227798
commit
872ee79146
@ -1,9 +1,10 @@
|
||||
import merge from 'deepmerge';
|
||||
import { EventEmitter } from 'events';
|
||||
import { default as lodash, default as _ } from 'lodash';
|
||||
import { Model, ModelCtor, ModelOptions, SyncOptions } from 'sequelize';
|
||||
import { ModelCtor, ModelOptions, SyncOptions } from 'sequelize';
|
||||
import { Database } from './database';
|
||||
import { Field, FieldOptions } from './fields';
|
||||
import { Model } from './model';
|
||||
import { Repository } from './repository';
|
||||
|
||||
export type RepositoryType = typeof Repository;
|
||||
@ -41,7 +42,7 @@ export class Collection<
|
||||
context: CollectionContext;
|
||||
isThrough?: boolean;
|
||||
fields: Map<string, any> = new Map<string, any>();
|
||||
model: ModelCtor<Model<TModelAttributes, TCreationAttributes>>;
|
||||
model: ModelCtor<Model>;
|
||||
repository: Repository<TModelAttributes, TCreationAttributes>;
|
||||
|
||||
get filterTargetKey() {
|
||||
@ -81,12 +82,16 @@ export class Collection<
|
||||
return;
|
||||
}
|
||||
const { name, model, autoGenId = true } = this.options;
|
||||
let M = Model;
|
||||
let M: ModelCtor<Model> = Model;
|
||||
if (this.context.database.sequelize.isDefined(name)) {
|
||||
const m = this.context.database.sequelize.model(name);
|
||||
if ((m as any).isThrough) {
|
||||
// @ts-ignore
|
||||
this.model = m;
|
||||
Object.defineProperty(this.model, 'database', { value: this.context.database });
|
||||
// @ts-ignore
|
||||
this.model.database = this.context.database;
|
||||
// @ts-ignore
|
||||
this.model.collection = this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -95,6 +100,7 @@ export class Collection<
|
||||
} else if (model) {
|
||||
M = model;
|
||||
}
|
||||
// @ts-ignore
|
||||
this.model = class extends M {};
|
||||
this.model.init(null, this.sequelizeModelOptions());
|
||||
|
||||
@ -102,7 +108,10 @@ export class Collection<
|
||||
this.model.removeAttribute('id');
|
||||
}
|
||||
|
||||
Object.defineProperty(this.model, 'database', { value: this.context.database });
|
||||
// @ts-ignore
|
||||
this.model.database = this.context.database;
|
||||
// @ts-ignore
|
||||
this.model.collection = this;
|
||||
}
|
||||
|
||||
setRepository(repository?: RepositoryType | string) {
|
||||
|
@ -2,7 +2,6 @@ import { applyMixins, AsyncEmitter } from '@nocobase/utils';
|
||||
import merge from 'deepmerge';
|
||||
import { EventEmitter } from 'events';
|
||||
import {
|
||||
Model,
|
||||
ModelCtor,
|
||||
Op,
|
||||
Options,
|
||||
@ -15,6 +14,7 @@ import { Collection, CollectionOptions, RepositoryType } from './collection';
|
||||
import { ImporterReader, ImportFileExtension } from './collection-importer';
|
||||
import * as FieldTypes from './fields';
|
||||
import { Field, FieldContext, RelationField } from './fields';
|
||||
import { Model } from './model';
|
||||
import { ModelHook } from './model-hook';
|
||||
import extendOperators from './operators';
|
||||
import { RelationRepository } from './relation-repository/relation-repository';
|
||||
@ -53,7 +53,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
|
||||
sequelize: Sequelize;
|
||||
fieldTypes = new Map();
|
||||
options: IDatabaseOptions;
|
||||
models = new Map<string, ModelCtor<any>>();
|
||||
models = new Map<string, ModelCtor<Model>>();
|
||||
repositories = new Map<string, RepositoryType>();
|
||||
operators = new Map();
|
||||
collections = new Map<string, Collection>();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { lodash } from '@umijs/utils';
|
||||
import { DataTypes, Model } from 'sequelize';
|
||||
import { DataTypes } from 'sequelize';
|
||||
import { Model } from '../model';
|
||||
import { BaseColumnFieldOptions, Field } from './field';
|
||||
|
||||
export class ContextField extends Field {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Model, ModelCtor } from 'sequelize';
|
||||
import _ from 'lodash';
|
||||
import { flatten, unflatten } from 'flat';
|
||||
import { Database } from './database';
|
||||
import lodash from 'lodash';
|
||||
import { flatten } from 'flat';
|
||||
import { default as lodash, default as _ } from 'lodash';
|
||||
import { ModelCtor } from 'sequelize';
|
||||
import { Collection } from './collection';
|
||||
import { Database } from './database';
|
||||
import { Model } from './model';
|
||||
|
||||
const debug = require('debug')('noco-database');
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
export { Model, ModelCtor, SyncOptions } from 'sequelize';
|
||||
export { ModelCtor, SyncOptions } from 'sequelize';
|
||||
export * from './collection';
|
||||
export * from './database';
|
||||
export { Database as default } from './database';
|
||||
export * from './fields';
|
||||
export * from './magic-attribute-model';
|
||||
export * from './mock-database';
|
||||
export * from './model';
|
||||
export * from './relation-repository/belongs-to-many-repository';
|
||||
export * from './relation-repository/belongs-to-repository';
|
||||
export * from './relation-repository/hasmany-repository';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Model } from 'sequelize';
|
||||
import { merge } from '@nocobase/utils';
|
||||
import _ from 'lodash';
|
||||
import Database from './database';
|
||||
import { Model } from './model';
|
||||
|
||||
export class MagicAttributeModel extends Model {
|
||||
get magicAttribute() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import lodash from 'lodash';
|
||||
import { Model } from 'sequelize';
|
||||
import type { SequelizeHooks } from 'sequelize/types/lib/hooks';
|
||||
import Database from './database';
|
||||
import { Model } from './model';
|
||||
|
||||
const { hooks } = require('sequelize/lib/hooks');
|
||||
|
||||
|
59
packages/database/src/model.ts
Normal file
59
packages/database/src/model.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { Model as SequelizeModel } from 'sequelize';
|
||||
import { Collection } from './collection';
|
||||
import { Database } from './database';
|
||||
|
||||
interface IModel {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export class Model<TModelAttributes extends {} = any, TCreationAttributes extends {} = TModelAttributes>
|
||||
extends SequelizeModel<TModelAttributes, TCreationAttributes>
|
||||
implements IModel
|
||||
{
|
||||
public static database: Database;
|
||||
public static collection: Collection;
|
||||
// [key: string]: any;
|
||||
|
||||
private toJsonWithoutHiddenFields(data, { model, collection }): any {
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
const db = (this.constructor as any).database as Database;
|
||||
const hidden = [];
|
||||
collection.forEachField((field) => {
|
||||
if (field.options.hidden) {
|
||||
hidden.push(field.options.name);
|
||||
}
|
||||
});
|
||||
const json = {};
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (hidden.includes(key)) {
|
||||
return;
|
||||
}
|
||||
if (model.hasAlias(key)) {
|
||||
const association = model.associations[key];
|
||||
const opts = {
|
||||
model: association.target,
|
||||
collection: db.getCollection(association.target.name),
|
||||
};
|
||||
if (['HasMany', 'BelongsToMany'].includes(association.associationType)) {
|
||||
if (Array.isArray(data[key])) {
|
||||
json[key] = data[key].map((item) => this.toJsonWithoutHiddenFields(item, opts));
|
||||
}
|
||||
} else {
|
||||
json[key] = this.toJsonWithoutHiddenFields(data[key], opts);
|
||||
}
|
||||
} else {
|
||||
json[key] = data[key];
|
||||
}
|
||||
});
|
||||
return json;
|
||||
}
|
||||
|
||||
public toJSON<T extends TModelAttributes>(): T {
|
||||
return this.toJsonWithoutHiddenFields(super.toJSON(), {
|
||||
model: this.constructor,
|
||||
collection: (this.constructor as any).collection,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
import { BelongsToMany, Model, Op, Transaction } from 'sequelize';
|
||||
import lodash from 'lodash';
|
||||
import { BelongsToMany, Op, Transaction } from 'sequelize';
|
||||
import { Model } from '../model';
|
||||
import { CreateOptions, DestroyOptions, FindOptions, TargetKey, UpdateOptions } from '../repository';
|
||||
import { updateThroughTableValue } from '../update-associations';
|
||||
import { FindAndCountOptions, FindOneOptions, MultipleRelationRepository } from './multiple-relation-repository';
|
||||
import { CreateOptions, DestroyOptions, FindOptions, TargetKey, UpdateOptions } from '../repository';
|
||||
import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types';
|
||||
import lodash from 'lodash';
|
||||
import { transaction } from './relation-repository';
|
||||
import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types';
|
||||
|
||||
type CreateBelongsToManyOptions = CreateOptions;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Model } from 'sequelize';
|
||||
|
||||
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
||||
import { Model } from '../model';
|
||||
import { CreateOptions, UpdateOptions } from '../repository';
|
||||
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
||||
|
||||
interface BelongsToFindOptions extends SingleRelationFindOption {}
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { BelongsToMany, HasMany, Model, Op, Sequelize } from 'sequelize';
|
||||
|
||||
import { omit } from 'lodash';
|
||||
import { HasMany, Op } from 'sequelize';
|
||||
import { Model } from '../model';
|
||||
import { CreateOptions, DestroyOptions, FindOptions, TargetKey, TK, UpdateOptions } from '../repository';
|
||||
import {
|
||||
AssociatedOptions,
|
||||
FindAndCountOptions,
|
||||
FindOneOptions,
|
||||
MultipleRelationRepository,
|
||||
MultipleRelationRepository
|
||||
} from './multiple-relation-repository';
|
||||
import { CreateOptions, DestroyOptions, FindOptions, TK, TargetKey, UpdateOptions } from '../repository';
|
||||
import { transaction } from './relation-repository';
|
||||
import lodash, { omit } from 'lodash';
|
||||
|
||||
interface IHasManyRepository<M extends Model> {
|
||||
find(options?: FindOptions): Promise<M>;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Model } from 'sequelize';
|
||||
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
||||
import { Model } from '../model';
|
||||
import { CreateOptions } from '../repository';
|
||||
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
|
||||
|
||||
interface HasOneFindOptions extends SingleRelationFindOption {}
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
import { Association, BelongsTo, BelongsToMany, HasMany, HasOne, Model, ModelCtor, Transaction } from 'sequelize';
|
||||
import { OptionsParser } from '../options-parser';
|
||||
import { Collection } from '../collection';
|
||||
import { CreateOptions, Filter, FindOptions } from '../repository';
|
||||
import FilterParser from '../filter-parser';
|
||||
import { UpdateGuard } from '../update-guard';
|
||||
import { updateAssociations } from '../update-associations';
|
||||
import lodash from 'lodash';
|
||||
import { transactionWrapperBuilder } from '../transaction-decorator';
|
||||
import { RelationField } from '../fields/relation-field';
|
||||
import { Association, BelongsTo, BelongsToMany, HasMany, HasOne, ModelCtor, Transaction } from 'sequelize';
|
||||
import { Collection } from '../collection';
|
||||
import Database from '../database';
|
||||
import { RelationField } from '../fields/relation-field';
|
||||
import FilterParser from '../filter-parser';
|
||||
import { Model } from '../model';
|
||||
import { OptionsParser } from '../options-parser';
|
||||
import { CreateOptions, Filter, FindOptions } from '../repository';
|
||||
import { transactionWrapperBuilder } from '../transaction-decorator';
|
||||
import { updateAssociations } from '../update-associations';
|
||||
import { UpdateGuard } from '../update-guard';
|
||||
|
||||
export const transaction = transactionWrapperBuilder(function () {
|
||||
return this.sourceCollection.model.sequelize.transaction();
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { RelationRepository, transaction } from './relation-repository';
|
||||
import { Model, SingleAssociationAccessors } from 'sequelize';
|
||||
import { updateModelByValues } from '../update-associations';
|
||||
import lodash from 'lodash';
|
||||
import { SingleAssociationAccessors } from 'sequelize';
|
||||
import { Model } from '../model';
|
||||
import { Appends, Except, Fields, Filter, TargetKey, TransactionAble, UpdateOptions } from '../repository';
|
||||
import { updateModelByValues } from '../update-associations';
|
||||
import { RelationRepository, transaction } from './relation-repository';
|
||||
|
||||
export interface SingleRelationFindOption extends TransactionAble {
|
||||
fields?: Fields;
|
||||
|
@ -6,16 +6,16 @@ import {
|
||||
DestroyOptions as SequelizeDestroyOptions,
|
||||
FindAndCountOptions as SequelizeAndCountOptions,
|
||||
FindOptions as SequelizeFindOptions,
|
||||
Model,
|
||||
ModelCtor,
|
||||
Op,
|
||||
Transaction,
|
||||
UpdateOptions as SequelizeUpdateOptions,
|
||||
UpdateOptions as SequelizeUpdateOptions
|
||||
} from 'sequelize';
|
||||
import { Collection } from './collection';
|
||||
import { Database } from './database';
|
||||
import { RelationField } from './fields';
|
||||
import FilterParser from './filter-parser';
|
||||
import { Model } from './model';
|
||||
import { OptionsParser } from './options-parser';
|
||||
import { BelongsToManyRepository } from './relation-repository/belongs-to-many-repository';
|
||||
import { BelongsToRepository } from './relation-repository/belongs-to-repository';
|
||||
|
@ -5,10 +5,10 @@ import {
|
||||
HasMany,
|
||||
HasOne,
|
||||
Hookable,
|
||||
Model,
|
||||
ModelCtor,
|
||||
Transactionable,
|
||||
Transactionable
|
||||
} from 'sequelize';
|
||||
import { Model } from './model';
|
||||
import { TransactionAble } from './repository';
|
||||
import { UpdateGuard } from './update-guard';
|
||||
|
||||
@ -257,11 +257,11 @@ export async function updateSingleAssociation(
|
||||
let dataKey: string;
|
||||
let M: ModelCtor<Model>;
|
||||
if (association.associationType === 'BelongsTo') {
|
||||
M = association.target;
|
||||
M = association.target as ModelCtor<Model>;
|
||||
// @ts-ignore
|
||||
dataKey = association.targetKey;
|
||||
} else {
|
||||
M = association.source;
|
||||
M = association.source as ModelCtor<Model>;
|
||||
dataKey = M.primaryKeyAttribute;
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ export async function updateMultipleAssociation(
|
||||
list3.push(instance);
|
||||
} else {
|
||||
// set & update record
|
||||
const instance = await association.target.findByPk(item[pk], {
|
||||
const instance = await association.target.findByPk<any>(item[pk], {
|
||||
transaction,
|
||||
});
|
||||
const addAccessor = association.accessors.add;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import lodash from 'lodash';
|
||||
import { Model, ModelCtor } from 'sequelize';
|
||||
import { ModelCtor } from 'sequelize';
|
||||
import { Model } from './model';
|
||||
import { AssociationKeysToBeUpdate, BlackList, WhiteList } from './repository';
|
||||
|
||||
|
||||
type UpdateValueItem = string | number | UpdateValues;
|
||||
|
||||
type UpdateValues = {
|
||||
|
@ -19,7 +19,7 @@ export async function signin(ctx: Context, next: Next) {
|
||||
ctx.throw(401, '请填写邮箱账号');
|
||||
}
|
||||
const User = ctx.db.getCollection('users');
|
||||
const user = await User.model.scope('withPassword').findOne<any>({
|
||||
const user = await User.model.findOne<any>({
|
||||
where: {
|
||||
[uniqueField]: values[uniqueField],
|
||||
},
|
||||
@ -36,8 +36,10 @@ export async function signin(ctx: Context, next: Next) {
|
||||
user.token = crypto.randomBytes(20).toString('hex');
|
||||
await user.save();
|
||||
}
|
||||
ctx.body = user.toJSON();
|
||||
delete ctx.body.password;
|
||||
ctx.body = {
|
||||
...user.toJSON(),
|
||||
token: user.get('token'),
|
||||
};
|
||||
await next();
|
||||
}
|
||||
|
||||
@ -47,10 +49,10 @@ export async function signout(ctx: Context, next: Next) {
|
||||
}
|
||||
|
||||
export async function signup(ctx: Context, next: Next) {
|
||||
const User = ctx.db.getCollection('users');
|
||||
const User = ctx.db.getRepository('users');
|
||||
const { values } = ctx.action.params;
|
||||
try {
|
||||
const user = await User.model.create(values);
|
||||
const user = await User.create({ values });
|
||||
ctx.body = user;
|
||||
} catch (error) {
|
||||
if (error.errors) {
|
||||
@ -139,7 +141,7 @@ export async function changePassword(ctx: Context, next: Next) {
|
||||
ctx.throw(401, 'Unauthorized');
|
||||
}
|
||||
const User = ctx.db.getCollection('users');
|
||||
const user = await User.model.scope('withPassword').findOne<any>({
|
||||
const user = await User.model.findOne<any>({
|
||||
where: {
|
||||
email: ctx.state.currentUser.email,
|
||||
},
|
||||
|
@ -4,14 +4,6 @@ export default {
|
||||
name: 'users',
|
||||
title: '{{t("Users")}}',
|
||||
sortable: 'sort',
|
||||
scopes: {
|
||||
withPassword: {
|
||||
attributes: { include: ['password'] },
|
||||
},
|
||||
},
|
||||
defaultScope: {
|
||||
attributes: { exclude: ['password'] },
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
interface: 'string',
|
||||
@ -39,6 +31,7 @@ export default {
|
||||
interface: 'password',
|
||||
type: 'password',
|
||||
name: 'password',
|
||||
hidden: true,
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
title: '{{t("Password")}}',
|
||||
|
@ -1,10 +1,10 @@
|
||||
import glob from 'glob';
|
||||
import compose from 'koa-compose';
|
||||
import _ from 'lodash';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import Action, { ActionName } from './action';
|
||||
import Resource, { ResourceOptions } from './resource';
|
||||
import { parseRequest, getNameByParams, ParsedParams, requireModule, parseQuery } from './utils';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import _ from 'lodash';
|
||||
import { getNameByParams, ParsedParams, parseQuery, parseRequest, requireModule } from './utils';
|
||||
|
||||
export interface ResourcerContext {
|
||||
resourcer?: Resourcer;
|
||||
|
Loading…
Reference in New Issue
Block a user