1.4.32 • Published 9 months ago

@mee4dy/crud v1.4.32

Weekly downloads
-
License
ISC
Repository
github
Last release
9 months ago

Intro

Create a backend and frontend in 5 minutes! With our powerful full stack crud system, customize it to suit you.

Installation

npm install @mee4dy/crud

Running migrations

npm --prefix ./node_modules/@mee4dy/crud run migrate

Package structure

  • Common interfaces, enums, decorators
  • Vuex Store, Vuex ORM Mode (new)
  • Vuex Forms
  • NestJS (Controller, Service, Decorators)
  • Vue Crud Table (Bootstrap VUE) Release soon

Features

  • Vuex CRUD - includes storage, requests to the backend: receiving, creating, deleting, updating
  • Vuex CRUD (ORM mode) - allows you to work with data in the store in ORM style
  • Vuex Forms - creation/editing modes. Compatible with CRUD backend
  • CRUD Controller and CRUD Service for NestJS, with controller-level scoping support
  • (Beta) Support for entity relationships. Ability to connect entities to each other
  • Full compatibility of front-end components and back-end components of the CRUD system
  • Convenient examples, versatility of use, customizable

Vuex Store

Params

ParamTypeDefaultDescription
endpointsObject-An object that defines the API endpoints for the CRUD operations. You can customize these endpoints by providing your own values.
pkString'id'The name of the primary key field in your data. This is used to uniquely identify each item.
filtersArray<String\|Object>'pk'An array of default filter options. These filters will be applied by default when making API calls.
groupsArray<String\|Object>'pk'An array of default group options. These options will be used for grouping the data.
ordersArray<String>'pk'An array of default sorting options. These options will be used for sorting the data.
fieldsArray<Object>[]An array of fields to be fetched from the API. Only these fields will be stored in the state.
defaultFiltersObject{}Object of default filters. (Example: { post_id: 1 }`)
defaultOrdersObject{}Object of default orders. (Example: { pk: 'desc' })
defaultGroupsArray<String>[]An array of default grouping options. These options will be selected by default when grouping the data.

Getters

getState(path)
getCtx
getPK
getItems
getItemsORM
getIncludes
getFields
getLoading
getSelectedFilters
getSelectedGroups
getSelectedOrders
getDefaultFilters
getDefaultGroups
getDefaultOrders
getParams
getEndpoint
getFilters
getGroups
getOrders

Mutations

setState(path, value)
setCtx(ctx)
setFields(fields)
setItems(items)
pushItem(item)
setLoading(status)
setQuery(query)
update({ pk, data, level? })
delete({ pk, level? })
setSelectedFilters(value)
setSelectedGroups(value)
setSelectedOrders(value)

Actions

setCtx()
setQuery(query)
setQuerySelectedFilters(query)
setQuerySelectedGroups(query)
setQuerySelectedOrders(query)
syncSelectedToQuery()
setItems(items)
fetch({ applyQuery?, filters?, groups?, orders? })
create({ data })
update({ pk, data, level? })
delete({ pk, level? })

Example store

import { CrudStore } from '@mee4dy/crud';

const crud = new CrudStore({
  pk: 'post_id',
  endpoints: {
    fetch: '/posts',
    delete: '/posts/delete',
    update: '/posts/update',
  },
  filters: [
    { label: 'ID', key: 'pk' },
    { label: 'ID Category', key: 'category_id' },
    { label: 'Title', key: 'title', type: 'text' },
  ],
  fields: [
    {
      key: 'pk',
      label: 'ID',
      sortable: true,
      centered: true,
    },
    {
      key: 'title',
      label: 'Title',
      sortable: true,
    },
    {
      key: 'status',
      label: 'Status',
      sortable: true,
      type: 'boolean',
    },
    {
      key: 'created_at',
      label: 'Created date',
      sortable: true,
      type: 'datetime',
    },
    {
      key: 'updated_at',
      label: 'Updated date',
      sortable: true,
      type: 'datetime',
    },
    {
      key: 'actions',
      label: 'Actions',
      sortable: true,
    },
  ],
});

const state = {
  ...crud.state,
};

const getters = {
  ...crud.getters,
};

const actions = {
  ...crud.actions,
};

const mutations = {
  ...crud.mutations,
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters,
};

Example usage

<template>
  <ui-table :items="items" :fields="fields" :busy="loading"></ui-table>
</template>

<script>
  import { mapActions, mapMutations, mapGetters } from 'vuex';

  export default {
    name: 'PostsTable',
    data() {
      return {};
    },
    computed: {
      ...mapGetters({
        items: 'posts/getItems',
        fields: 'posts/getFields',
        loading: 'posts/getLoading',
      }),
    },
    watch: {
      '$route.query': {
        immediate: true,
        handler(query) {
          this.setQuery(query);
          this.fetch();
        },
      },
    },
    methods: {
      ...mapActions({
        fetch: 'posts/fetch',
        setQuery: 'posts/setQuery',
      }),
    },
  };
</script>

VUEX ORM

VUEX ORM provides a convenient tool for editing objects in the VUEX CRUD Store using the ORM approach.
Use the "save", "commit", "delete" methods to work with store objects.

VUE Component

<template>
  <div id="posts">
    <div v-if="loading" class="loader">Loading...</div>
    <div v-else v-for="item of items">
      <h1>{{ item.title }}</h1>
      <div>{{ item.text }}</div>
      <button @click="modifyTitle(item)">Modify title</button>
      <button @click="modifyTitleLocal(item)">Modify title (without save)</button>
      <button @click="deletePost(item)">Delete post</button>
    </div>
  </div>
</template>

<script>
  import { mapGetters, mapActions } from 'vuex';

  export default {
    data() {
      return {};
    },
    computed: {
      ...mapGetters({
        fields: 'posts/getFields',
        items: 'posts/getItemsORM',
        loading: 'posts/getLoading',
      }),
    },
    mounted() {
      this.fetch();
    },
    methods: {
      ...mapActions({
        fetch: 'posts/fetch',
      }),

      modifyTitle(item) {
        item.title = 'New Title!';
        await item.save();
      },
      modifyTitleLocal(item) {
        item.title = 'New Title! (local)';
        item.commit();
      },
      deletePost(item) {
        await item.delete();
      }
    },
  };
</script>

Custom usage ORM

const items = [
  { id: 1, child_id: 11, name: 'test' },
  { id: 2, child_id: 12, name: 'test2' },
];

const itemsORM = new ORM(items)
  .setActions({
    update: '...',
    delete: '...',
  })
  .setIncludes(['childs']);

const item = itemsORM[0];

// Update item
item.name = 'test-new';
await item.save();

// OR Commit changes without save
item.commit();

// Delete item
await item.delete();

const itemChild = item.childs[0];

// Update child item
itemChild.name = 'child-name-new';
await itemChild.save();

// OR Commit changes without save
item.commit();

// Delete child
await itemChild.delete();

VUEX FORM

Store

import { CrudStoreForm } from '@mee4dy/crud';

const crud = new CrudStoreForm({
  endpoints: {
    fetch: '/posts/:pk',
    create: '/posts/create',
    update: '/posts/update',
  },
});

export default crud;

VUE component

<template>
  <div id="form">
    <b-form @submit.prevent="onSubmit">
      <b-form-group id="input-group-1" label="Title:" label-for="input-1">
        {{ formData }}
        <b-form-input id="input-1" v-model="formData.title" type="text" required></b-form-input>
      </b-form-group>
      <b-btn type="submit" icon="mdi-plus" variant="primary">Submit</b-btn>
    </b-form>
  </div>
</template>

<script>
import { mapActions, mapGetters } from 'vuex';
import { mapFormData } from '@mee4dy/crud';

export default {
  computed: {
    formData: mapFormData('posts/form'), // Form state mapping (for changes with mutations)

    ...mapGetters({
      fields: 'posts/form/getFields',
      data: 'posts/form/getData',
      dataDefault: 'posts/form/getDataDefault',
    }),
  },
  methods: {
    ...mapActions({
      init: 'posts/form/init',
      fetch: 'posts/form/fetch',
      submit: 'posts/form/submit',
      reset: 'posts/form/reset',
    }),

    onSubmit() {
      this.submit();
    },

    onReset() {
      this.reset();
    },
  },
  mounted() {
    this.fetch(this.id);
  },
};
</script>

NestJS (Examples)

CRUD Controller

Сontroller routes:
/       - get all items
/:pk    - get item by pk (primary key)
/create - create item
/update - update item
/delete - delete item

Controller

import { CrudController } from '@mee4dy/crud/nestjs';

@Controller('/posts')
export class PostsController extends CrudController {
  constructor(private readonly postsService: postsService) {
    super(postsService);
  }
}

Scope

import { CrudController, UseCrudScope } from '@mee4dy/crud/nestjs';

@UseCrudScope((req) => {
  return {
    where: {
      user_id: req.user.id, // Adds a filter by user for all database queries
    },
  };
})
@Controller('/posts')
export class PostsController extends CrudController {
  constructor(private readonly postsService: postsService) {
    super(postsService);
  }
}

Context object

import { CrudController, CrudCtx, UseCrudCtx } from '@mee4dy/crud/nestjs';

@UseGuards(AuthGuard('jwt'))
@UseCrudCtx((req: any) => {
  const user = req.user;

  return {
    user: user,
    // Any other data
  };
})
@Controller('/posts')
export class PostsController extends CrudController {
  constructor(private readonly postsService: postsService) {
    super(postsService);
  }

  @Post('/create')
  async create(@CrudCtx() ctx, @Body('data') data: CreateDto) {
    const user = ctx.user; // User object was passed with UseCrudCtx

    try {
      // ...

      return {
        status: true,
      };
    } catch (e) {
      return {
        status: false,
        error: {
          message: e.message,
          // ...
        },
      };
    }
  }
}

Custom method

import { CrudController } from '@mee4dy/crud/nestjs';

@Controller('/posts')
export class PostsController extends CrudController {
  constructor(private readonly postsService: postsService) {
    super(postsService);
  }

  @Get('/refresh')
  async refresh(@Query('post_id') postID) {
    try {
      const post = await this.postsService.findOne({
        where: {
          post_id: postID,
        },
      });

      if (post) {
        // ...
      }
    } catch (e) {
      console.error(e);
    }
  }
}

CRUD Service

Service

import { CrudService } from '@mee4dy/crud/nestjs';

@Injectable()
export class PostsService extends CrudService {
  constructor(
    @InjectModel(Posts)
    private postsModel: typeof Posts
  ) {
    super();
  }

  protected pk = 'post_id';
  protected repository = this.postsModel;
}

Modify repository

import { CrudService } from '@mee4dy/crud/nestjs';

@Injectable()
export class PostsService extends CrudService {
  constructor(
    @InjectModel(Posts)
    private postsModel: typeof Posts
  ) {
    super();

    this.repository = this.postsModel.scope(['withStatitstic']);
  }

  protected pk = 'post_id';
  protected repository;
}

Development mode

npm install @mee4dy/crud
npm run dev

// Mount docker volume
volumes:
  - ...
  - ../crud:/app/node_modules/@mee4dy/crud

// NPM Link (inside crud folder)
npm link
1.4.31

9 months ago

1.4.30

10 months ago

1.4.32

9 months ago

1.4.22

12 months ago

1.4.21

12 months ago

1.4.24

12 months ago

1.4.23

12 months ago

1.4.26

12 months ago

1.4.25

12 months ago

1.4.28

12 months ago

1.4.27

12 months ago

1.4.29

11 months ago

1.4.13

1 year ago

1.4.15

12 months ago

1.4.14

1 year ago

1.4.17

12 months ago

1.4.16

12 months ago

1.4.19

12 months ago

1.4.18

12 months ago

1.4.12

1 year ago

1.4.9

1 year ago

1.4.11

1 year ago

1.4.10

1 year ago

1.4.7

1 year ago

1.4.6

1 year ago

1.4.5

1 year ago

1.4.3

1 year ago

1.4.2

1 year ago

1.4.1

1 year ago

1.3.7

1 year ago

1.3.6

1 year ago

1.3.5

1 year ago

1.3.4

1 year ago

1.3.3

1 year ago

1.3.2

1 year ago

1.3.1

1 year ago

1.3.0

1 year ago

1.2.3

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.6

1 year ago

1.1.5

1 year ago

1.1.1

1 year ago

1.1.4

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago