npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mee4dy/crud

v1.4.34

Published

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

Downloads

166

Readme

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

| Param | Type | Default | Description | | -------------- | ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- | | endpoints | Object | - | An object that defines the API endpoints for the CRUD operations. You can customize these endpoints by providing your own values. | | pk | String | 'id' | The name of the primary key field in your data. This is used to uniquely identify each item. | | filters | Array<String\|Object> | ['pk'] | An array of default filter options. These filters will be applied by default when making API calls. | | groups | Array<String\|Object> | ['pk'] | An array of default group options. These options will be used for grouping the data. | | orders | Array<String> | ['pk'] | An array of default sorting options. These options will be used for sorting the data. | | fields | Array<Object> | [] | An array of fields to be fetched from the API. Only these fields will be stored in the state. | | defaultFilters | Object | {} | Object of default filters. (Example: { post_id: 1 }) | | defaultOrders | Object | {} | Object of default orders. (Example:{ pk: 'desc' }) | | defaultGroups | Array` | [] | 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