@benjy2976/pmsg 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ * text=auto
package/CONTRIBUTING ADDED
File without changes
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Walther Aguirre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,247 @@
1
+ # pinia-model-store-generator pmsg
2
+ This is a powerful package to consume data from webservices and use it as a model, centralizing the control of routes and
3
+ making the call to data from the server much more friendly.
4
+
5
+ este es un paquete potente para consumir datos de webservices y utilizarlo como modelo, centralizado el control de las
6
+ rutas y haciendo mucha mas amable la llamada a los datos desde el servidor
7
+
8
+ It also provides a tool that creates a template with the main actions for state control with Pinia.
9
+
10
+ tambien provee de una herramienta que crea una plantilla con las principales acciones para el control de estados con Pinia
11
+
12
+ ## Installing
13
+
14
+ Using npm:
15
+
16
+ ```bash
17
+ $ npm install
18
+ ```
19
+
20
+
21
+ ## Example
22
+ NOTE: if you use a md5 validation and the store functionality you can download the resource from the server once,
23
+ an re download only if the data was changed.
24
+
25
+ you can create a core/product.js file and put the next code
26
+
27
+ ```js
28
+ export default {
29
+ alias : 'product' ,//alias utilizado para almacenar en el localstorage
30
+ route : '/api/auth/product',//ruta donde se encuentra el resource
31
+ hash : false,//la condicional si se va a validar el md5
32
+ store : false,//la condicional que define si se guardara en el localstorage
33
+ methods : null, //define los métodos adicionales utilizados por el modelo
34
+
35
+ /*config for storeDefault*/
36
+ key : 'id',//define el primary key que se usara para acceder al objeto
37
+ name : 'name',//nombre del atributo name en la base de datos
38
+ maxRelationsResolve: 1//la cantidad de veces que resolvera la relacion default 1
39
+ relations : [// Relaciones con otros models
40
+ {
41
+ attribute: 'brand_id',
42
+ alias: 'brand',//si no se define se asume le mismo nombre que attribute
43
+ module: 'brands',
44
+ hasMany: false// si no se define se asumen como falso
45
+ },
46
+ ],
47
+ selectable: false,//condicional para definir si el objeto es seleccionable
48
+ default : {
49
+ id:null,
50
+ brand_id:null,
51
+ name:null
52
+ },//valor del objeto por defecto,
53
+ params : {modeljs: true}//aquí se configuran parámetros adicionales a enviar en los request
54
+
55
+ }
56
+
57
+ ```
58
+
59
+ you can create a core/category.js file and put the next code
60
+
61
+ ```js
62
+ export default {
63
+ alias : 'brand' ,//alias utilizado para almacenar en el localstorage
64
+ route : '/api/auth/brand',//ruta donde se encuentra el resource
65
+ hash : false,//la condicional si se va a validar el md5
66
+ store : false,//la condicional que define si se guardara en el localstorage
67
+ methods : null, //define los métodos adicionales utilizados por el modelo
68
+
69
+ /*config for storeDefault*/
70
+ key : 'id',//define el primary key que se usara para acceder al objeto
71
+ name : 'name',//nombre del atributo name en la base de datos
72
+ maxRelationsResolve: 1//la cantidad de veces que resolvera la relacion default 1
73
+ relations : [// Relaciones con otros models
74
+ {
75
+ attribute : 'brand_id',
76
+ alias : 'products',
77
+ module : 'products',
78
+ hasMany : true//se pone false para que busque a traves del pivot
79
+ },
80
+ ],
81
+ selectable: false,//condicional para definir si el objeto es seleccionable
82
+ default : {
83
+ id:null,
84
+ name:null
85
+ },//valor del objeto por defecto,
86
+ params : {modeljs: true}//aquí se configuran parámetros adicionales a enviar en los request
87
+
88
+ }
89
+
90
+ ```
91
+ create core/index.js
92
+
93
+ ```js
94
+ import Model from '@benjy2976/pmsg'
95
+ import createApiService from '@/core/services/ApiService'
96
+ const Apiservice = createApiService(import.meta.env.VITE_API_URL || 'http://localhost:8083/api')
97
+
98
+ import configProduct from './product'
99
+ import configBrand from './brand'
100
+ export const Producto = new Model(configProduct, Apiservice)
101
+ export const Brand = new Model(configBrand, Apiservice)
102
+
103
+ ```
104
+
105
+ so where ever you are you can call the product Model
106
+
107
+ ```js
108
+ import {Producto} from './core'
109
+
110
+ Producto.show(1)
111
+ //this code create a request to the server an return a request to the object with the id Nr 1
112
+ ```
113
+
114
+ if you are using Pinia you can create the storeDefault
115
+ crating the next structure
116
+ ```js
117
+ /store
118
+ /store/modules
119
+ ```
120
+ into /store/modules you can create a products.js file
121
+ ```js
122
+ //import {Product} from '../../models' //import if necessary
123
+
124
+
125
+ const state = {
126
+ //here you can redefine or define new states
127
+ //by default its going to create the next stores
128
+ /
129
+ itemSelected:{},
130
+ items:Array[],
131
+ keysAsinc: [],
132
+ keysTemp: [],
133
+ key: config.key,
134
+ moduleAlias: config.moduleAlias,
135
+ maxRelationsResolve: config.maxRelationsResolve,
136
+ relations: config.relations,
137
+ syncStatus: config.sync,//here you define whether sync() or setItems() will be used
138
+ selectedStatus: false,
139
+ timeOutAsinc:null
140
+
141
+
142
+ //you do not need to define it, it is going to create automatically
143
+ }
144
+
145
+ const getters = {
146
+ //here you can redefine or define new getters
147
+ //by default its going to create the next getters
148
+
149
+ key: 'id',
150
+ // Getter para obtener el nombre del objeto seleccionado
151
+ name: (id) => {...},
152
+ // Getter para obtener el objeto seleccionado
153
+ find: (id) => {...},
154
+ // Getter para obtener la lista de objetos
155
+ list: [...],
156
+ // Getter para obtener la lista de objetos filtrados
157
+ filter: (filter) => [...],
158
+ // Getter para obtener el objeto seleccionado
159
+ selected: {...}
160
+ // Getter para resolver las relaciones
161
+ //** se debe de sobrecargar este metodo si se quiere poner funciones personalizadas***
162
+ resolve: {...}
163
+
164
+
165
+ // Getter para obtener el indice de la tabla
166
+ //you do not need to define it, it is going to create automatically
167
+ //also you can create other getters if you need
168
+ }
169
+
170
+ const actions = {
171
+ //here you can redefine or define new actions
172
+ //by default its going to create the next actions
173
+ /* esta accion almacena todos los keys que con los que se le invoca en un periodo de 100ms para realizar una peticion al servicor con los datos de todas esas keys */
174
+ checkAsinc ({ state, getters, dispatch, commit }, key )//this action stores all the keys with which it is invoked in a period of 100ms to make a request to the service with the data of all those keys
175
+ /* esta accion invoca a show del modelo y almacena la respuesta */
176
+ show ({ dispatch })//this action invoque at the show fron the model and store the response into the state.items
177
+ //*** esta acción invoca getAll(params) del modelo y almacena la respuesta en state.items. ***
178
+ get(params)//this action invoque at the getAll(params) from the model and store the response into a state.items
179
+ //*** esta acción se invoca después de que se envía el get, puede redefinirlo si lo necesita ***
180
+ afterGet()//this action is called after the get is dispatched, you yo can redefine it if you need
181
+ //*** esta acción crea un nuevo item, llama a create(item) desde el modelo y agrega la respuesta ***
182
+ create(item)//this action create a new item, call to the create(item) from the model and add the response
183
+ //at the state.items list
184
+ //*** esta acción modifica un item, llama a update(item) desde el modelo y agrega la respuesta ***
185
+ update(item)//this action update a item, call to the update(item) from the model and add the response
186
+ //at the state.items list
187
+ //*** esta acción elimina un nuevo elemento, llama a eliminar (elemento) del modelo y agrega la respuesta ***
188
+ delete(item)//this action delete a new item, call to the delete(item) from the model and add the response
189
+ //*** action para llamar SET_ITEMS mutacion, para reemplazar todo el state.items ***
190
+ setItems(items)//action to call SET_ITEMS mutation, to replace all the state.items
191
+ //*** esta accion setea state.syncStatus ****
192
+ setSyncStatus(syncStatus)//this action set the state.syncStatus
193
+ //*** action para determinar si se actualizara un objeto o varios de acuerdo al formato de llegada de la data ***
194
+ sync(item/items)//action to determine if one object or several is updated according to the data arrival format
195
+ //*** action para sincronizar objetos (items) con los objetos almacenado en el store ***
196
+ syncItems(items)//action to synchronize objects (items) with the objects stored in the store
197
+ //*** action para sincronizar un objeto (item) con un objeto almacenado en el store ***
198
+ syncItem(item)//action to synchronize an object (item) with an object stored in the store
199
+ //at the state.items list
200
+ //*** estas acciones seleccionan un elemento de la lista de elementos y ponen el valor en un estado. ***
201
+ selectItem(id)//this actions select one item from the list of items and put the value into a state.item
202
+ //*** esta acción se llama después de que se envía el artículo seleccionado, puede redefinirlo si lo necesita ***
203
+ afterSelect()//this action is called after the selectItem is dispatched, you yo can redefine it if you need
204
+ //*** esta accion de seleccioan el itemSelected ***
205
+ deselect()//this action deselect the itemSelected
206
+
207
+ //you do not need to define it, it is going to create automatically
208
+ //also you can create other getters if you need
209
+ }
210
+
211
+ export default {
212
+ state,
213
+ getters,
214
+ actions,
215
+ }
216
+
217
+
218
+ ```
219
+ you need to create a file index.js into a /store folder you have two ways to declare the state
220
+
221
+ ````js
222
+ import { defineStore } from "pinia";
223
+ import { Producto } from '@/core/models/index.js';
224
+
225
+ const {state,getters,actions} = Producto.getStore();
226
+ const useProductosStore = defineStore(Producto.alias, {
227
+ state : () => ({...state}),
228
+ getters : {...getters},
229
+ actions : {...actions},
230
+ }
231
+ )
232
+ export default useProductosStore;
233
+ ````
234
+ in your Component component.vue
235
+
236
+ in your app.js you can invoque like this
237
+ ````js
238
+
239
+
240
+ import useProductosStore from '@/stores/auth/ProcutosStore'
241
+ const productosStore = useProductosStore()
242
+
243
+ productosStore.get().then(()=>{
244
+ console.log(productosStore.list)
245
+ })
246
+
247
+ ````
@@ -0,0 +1,37 @@
1
+ // eslint.config.js (CommonJS)
2
+ import js from "@eslint/js";
3
+ export default [
4
+ js.configs.recommended,
5
+ {
6
+ files : ["**/*.js"],
7
+ languageOptions : {
8
+ ecmaVersion : "latest",
9
+ sourceType : "module",
10
+ globals : {
11
+ console : "readonly",
12
+ window : "readonly",
13
+ document : "readonly",
14
+ setTimeout : "readonly",
15
+ setInterval : "readonly",
16
+ clearInterval : "readonly",
17
+ localStorage : "readonly",
18
+ sessionStorage : "readonly",
19
+ hashMd5 : "readonly",
20
+ __dirname : "readonly",
21
+ URL : "readonly",
22
+ // Agrega aquí cualquier otra global que uses
23
+ }
24
+ },
25
+ plugins : { vue },
26
+ rules : {
27
+ "indent" : ["error", 2],
28
+ "key-spacing" : [
29
+ "error",
30
+ {
31
+ "singleLine" : { beforeColon: false, afterColon: true },
32
+ "multiLine" : { beforeColon: true, afterColon: true, align: "colon" }
33
+ }
34
+ ]
35
+ }
36
+ }
37
+ ];
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@benjy2976/pmsg",
3
+ "version": "0.1.0",
4
+ "description": "generator of models and store default for pinia",
5
+ "main": "src/Model.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/benjy2976/pmsg"
12
+ },
13
+ "keywords": [
14
+ "pinia",
15
+ "generator",
16
+ "model",
17
+ "store"
18
+ ],
19
+ "author": "Walther Raul II Benjamin Aguirre Tello",
20
+ "license": "MIT",
21
+ "bugs": {
22
+ "url": "https://github.com/benjy2976/pmsg/issues"
23
+ },
24
+ "homepage": "https://github.com/benjy2976/pmsg#readme",
25
+ "dependencies": {
26
+ "axios": "^1.0.0",
27
+ "js-md5": "^0.8.3"
28
+ },
29
+ "devDependencies": {
30
+ "eslint": "^9.25.1",
31
+ "eslint-plugin-import": "^2.27.5",
32
+ "eslint-plugin-n": "^15.6.1",
33
+ "eslint-plugin-promise": "^6.1.1"
34
+ }
35
+ }
package/src/Model.js ADDED
@@ -0,0 +1,217 @@
1
+ import { md5 } from 'js-md5'
2
+ import createModelStore from "./useModelStore"
3
+ import axios from 'axios'
4
+ export default class Model {
5
+
6
+ constructor(config, instance = null) {
7
+ this.instance = instance == null ? axios.create() : instance//axios instance
8
+ let defaultValues = {
9
+ alias : null,// Alias utilizado para almacenar en el localstorage
10
+ route : null,// Ruta donde se encuentra el resource
11
+ hash : false,// La condicional si se va a validar el md5
12
+ sync : false,// La condicional si se va sincronizar o reemplazar el state al hacer un nuevo request
13
+ store : false,// La condicional que define si se guardara en el localstorage
14
+ methods : null, // Define los métodos adicionales utilizados por el modelo
15
+ /*config for storeDefault*/
16
+ hasKey : true,// Define si la tabla tiene primaryKey
17
+ key : 'id',// Define el primary key que se usara para acceder al objeto
18
+ name : 'name',// Nombre del atributo name en la base de datos
19
+ maxRelationsResolve : 1,// Relaciones con otros models
20
+ relations : [],// Relaciones con otros models
21
+ selectable : false,// Condicional para definir si el objeto es seleccionable
22
+ default : {},// Valor del objeto por defecto,
23
+ params : { modeljs: true },// Aquí se configuran parámetros adicionales a enviar en los request excepto DELETE
24
+ modelGetters : {}// Aquí se configuran parámetros adicionales a enviar en los request excepto DELETE
25
+ }
26
+ //config.hasKey=config.hasKey!=undefined?config.hasKey:config.key!=undefined
27
+ defaultValues = Object.assign(defaultValues, config)
28
+ this.alias = defaultValues.alias
29
+ this.route = defaultValues.route
30
+ this.hash = defaultValues.hash
31
+ this.sync = defaultValues.sync
32
+ this.store = defaultValues.store
33
+ for (const prop in defaultValues.methods) {
34
+ this[prop] = defaultValues.methods[prop]
35
+ }
36
+ this.singular = defaultValues.singular
37
+ this.plural = defaultValues.plural
38
+ this.key = defaultValues.key
39
+ this.hasKey = defaultValues.hasKey
40
+ this.name = defaultValues.name
41
+ this.maxRelationsResolve = defaultValues.maxRelationsResolve
42
+ this.relations = defaultValues.relations
43
+ this.selectable = defaultValues.selectable
44
+ this.default = defaultValues.default
45
+ this.params = defaultValues.params
46
+ this.modelGetters = defaultValues.modelGetters
47
+ this.state = {}
48
+ this.getters = {}
49
+ this.actions = {}
50
+ }
51
+
52
+ get(url = '', params = {}) {
53
+ params = Object.assign(params, this.params)
54
+ url = this.route + '/' + url
55
+ return this.instance.get(url, {
56
+ params : params,
57
+ })
58
+ }
59
+
60
+ post(url = '', params = {}) {
61
+ params = Object.assign(params, this.params)
62
+ url = this.route + '/' + url
63
+ return this.instance.post(url, params)
64
+ }
65
+
66
+ // Función para obtener el listado de Objetos de la base de datos
67
+ getAll(params = {}) {
68
+ params = Object.assign(params, this.params)
69
+ return this.instance.get(this.route, {
70
+ params : params,
71
+ })
72
+ }
73
+
74
+ // Función para crear un objeto en la base de datos
75
+ create(d) {
76
+ d = Object.assign(d, this.params)
77
+ return this.instance.post(this.route, d)
78
+ }
79
+
80
+ // Función para mostrar un objeto de la base de datos
81
+ show(params) {
82
+ let id = null
83
+ let d = this.params
84
+
85
+ if (typeof params === 'object') {
86
+ id = params[this.key]
87
+ d = Object.assign(params, this.params)
88
+ } else {
89
+ id = params
90
+ }
91
+ return this.instance.get(this.route + '/' + id, {
92
+ params : d,
93
+ })
94
+ }
95
+
96
+ // Función para actualizar un objeto en la base de datos
97
+ update(d) {
98
+ d = Object.assign(d, this.params)
99
+ return this.instance.put(this.route + '/' + d[this.key], d)
100
+ }
101
+
102
+ // Función para eliminar un objeto de la base de datos
103
+ delete(d) {
104
+ return this.instance.delete(this.route + '/' + d[this.key], {
105
+ params : this.params,
106
+ })
107
+ }
108
+
109
+ // Función para verificar si la lista esta guardada en el local storage
110
+ async saved(params = {}) {
111
+ if (this.store) {
112
+ if (this.hash) {
113
+ await this.verificarHash(params)
114
+ }
115
+ return !!localStorage.getItem(this.alias)
116
+ } else
117
+ return this.store
118
+ }
119
+
120
+ // Función para almacenar la lista en el localstorage
121
+ save(p) {
122
+ if (this.store) {
123
+ localStorage.setItem(this.alias, JSON.stringify(p))
124
+ }
125
+ }
126
+
127
+ // Función para obtener lo almacenado en el localStorage
128
+ getFromLocalStorage() {
129
+ return JSON.parse(localStorage.getItem(this.alias))
130
+ }
131
+
132
+ // Función para eliminar lo almacenado en el localstorage
133
+ destroy() {
134
+ localStorage.removeItem(this.alias)
135
+ }
136
+
137
+ // Función para verificar si el hash coincide con el que viene en la vista
138
+ async verificarHash (params = {}) {
139
+ let hashMd5 = await this.getAll({...params, hash: true})
140
+ if (!!localStorage.getItem(this.alias) && hashMd5.data !== md5(localStorage.getItem(this.alias))) {
141
+ localStorage.removeItem(this.alias)
142
+ }
143
+ }
144
+
145
+ // Getter para obtener el store por defecto para el modelo
146
+ setStore({ state = null, getters = null, actions = null }) {
147
+ this.state = state === null ? this.state : state
148
+ this.getters = getters === null ? this.getters : getters
149
+ this.actions = actions === null ? this.actions : actions
150
+ return this
151
+ }
152
+ // Getter para obtener el store por defecto para el modelo
153
+ getStore(state = null, getters = null, actions = null) {
154
+ this.state = state === null ? this.state : state
155
+ this.getters = getters === null ? this.getters : getters
156
+ this.actions = actions === null ? this.actions : actions
157
+ return createModelStore(this, this.state, this.getters, this.actions)
158
+ }
159
+
160
+ // Getter para obtener todos los parámetros de configuración del modelo
161
+ getConfig() {
162
+ return {
163
+ sync : this.sync,
164
+ alias : this.alias,
165
+ route : this.route,
166
+ hash : this.hash,
167
+ store : this.store,
168
+ methods : this.methods,
169
+ singular : this.singular,
170
+ plural : this.plural,
171
+ key : this.key,
172
+ name : this.name,
173
+ selectable : this.selectable,
174
+ default : this.default
175
+ }
176
+ }
177
+
178
+ // Función para obtener los parámetros de configuración necesarios para el StoreDefault
179
+ getStoreConfig() {
180
+ return {
181
+ key : this.key,
182
+ hasKey : this.hasKey,
183
+ moduleAlias : this.alias,
184
+ maxRelationsResolve : this.maxRelationsResolve,
185
+ relations : this.relations.map(relation => {
186
+ return {
187
+ ...relation,
188
+ ['hasMany'] : (relation.hasMany === undefined) ? false : relation.hasMany,
189
+ ['alias'] : (relation.alias === undefined) ? relation.attribute : relation.alias,
190
+
191
+ }
192
+ }),
193
+ sync : this.sync
194
+ }
195
+ }
196
+
197
+ // Getter para saber si se puede seleccionar un objeto de la lista de objetos
198
+ isSelectable() {
199
+ return this.selectable === true
200
+ }
201
+
202
+ // Getter para obtener el valor por default de el objeto
203
+ getDefault() {
204
+ //return JSON.parse(JSON.stringify(this.default))
205
+ //return {...Object.assign({},this.default),...this.getModelGetters()}
206
+ return Object.assign({}, JSON.parse(JSON.stringify(this.default)))
207
+ }
208
+ // Getter para obtener el valor por default de el objeto modelGetters
209
+ getModelGetters() {
210
+ return Object.assign({}, JSON.parse(JSON.stringify(this.modelGetters)))
211
+ }
212
+
213
+ // Getter para obtener el nombre del atributo que hace referencia al nombre del Objeto
214
+ getNameAttribute() {
215
+ return this.name
216
+ }
217
+ }
package/src/helpers.js ADDED
@@ -0,0 +1,148 @@
1
+ // helpers.js
2
+ export function normalizeRelations(data, relations) {
3
+ return {
4
+ ...data,
5
+ ...relations.reduce(
6
+ (prev, relation) => ({
7
+ ...prev,
8
+ [relation.attribute] : Array.isArray(data[relation.attribute]) ?
9
+ data[relation.attribute].map(x => x.id) : data[relation.attribute].id
10
+ }), {}
11
+ )
12
+ };
13
+ }
14
+ export function resolveRelations(data, state, rootGetters, level=1) {
15
+ if(state.relations.length==0){
16
+ return data
17
+ }else{
18
+
19
+ return {
20
+ ...data,
21
+ ...state.relations.reduce(
22
+ (prev, relation) => {
23
+ let alias = relation.alias != undefined ? relation.alias : relation.attribute
24
+
25
+ if(state.maxRelationsResolve>=level){
26
+ return ({
27
+ ...prev,
28
+ [alias] : relationLinck(data, alias, relation, state.key, rootGetters, level+1)
29
+ })
30
+ }
31
+ else{
32
+ return ({
33
+ ...prev,
34
+ ['errorResolve'] : 'Max relation resolve exceded: resolved '+level+' times'
35
+ })
36
+ }
37
+
38
+ }, {}
39
+ )
40
+ };
41
+ }
42
+ }
43
+
44
+ function relationLinck(data, alias, relation, key, rootGetters, level) {
45
+ if (relation.hasMany === false) {
46
+ return Array.isArray(data[relation.alias]) ?
47
+ data[relation.alias].map(x => {return {...rootGetters[`${relation.module}/find`](x, level),pivot_id: x}}) :
48
+ {...rootGetters[`${relation.module}/find`](data[relation.attribute], level),pivot_id: data[relation.attribute]}
49
+ } else {
50
+ return rootGetters[`${relation.module}/filter`](d => d[relation.attribute] === data[key], level)
51
+ }
52
+ }
53
+
54
+ //esta funcion se usa para exportar las relaciones de un objeto
55
+ export function exportRelations(data, state, dispatch, rootGetters) {
56
+ if(data.pivot!==undefined){
57
+ delete data.pivot
58
+ }
59
+ if(state.relations.length==0){
60
+ return data
61
+ }else
62
+ return {
63
+ ...data,
64
+ ...state.relations.reduce(
65
+ (prev, relation) => {
66
+ let attr = data[relation.alias]
67
+ if (attr !== undefined&&attr !== null) {
68
+ if(Array.isArray(attr)){
69
+ prev[relation.alias]= attr.map(obj => obj[rootGetters[`${relation.module}/key`]])
70
+ dispatch(`${relation.module}/syncItems`, attr, { root: true })
71
+ }
72
+ else if (typeof attr == 'object' || attr instanceof Object){
73
+ delete prev[relation.attribute]
74
+ dispatch(`${relation.module}/syncItem`, attr, { root: true })
75
+ }
76
+ return ({
77
+ ...prev
78
+ })
79
+ }
80
+ else {
81
+ return { ...prev }
82
+ }
83
+ }, {}
84
+ )
85
+ };
86
+ }
87
+
88
+ //esta funcion se usa para exportar las relaciones de un arreglo de objetos
89
+ export function globalExportRelations(items, relations, dispatch, rootGetters) {
90
+ if(relations.length==0){
91
+ return items
92
+ }
93
+ relations=relations.map(d=>{return {...d,pivot: []}})
94
+ items=items.map(item => {
95
+ if(item.pivot!==undefined){
96
+ delete item.pivot
97
+ }
98
+ return {
99
+ ...item,
100
+ ...relations.reduce(
101
+ (prev, relation, currentIndex) => {
102
+ let attr = item[relation.alias]
103
+ if (attr !== undefined&&attr !== null) {
104
+ if(Array.isArray(attr)){
105
+ prev[relation.alias]= attr.map(obj => obj[rootGetters[`${relation.module}/key`]])
106
+ relations[currentIndex].pivot = relations[currentIndex].pivot.concat(attr)
107
+ }
108
+ else if (typeof attr == 'object' || attr instanceof Object){
109
+ delete prev[relation.attribute]
110
+ relations[currentIndex].pivot.push(attr)
111
+ }
112
+ return ({
113
+ ...prev
114
+ })
115
+ }
116
+ else {
117
+ return { ...prev }
118
+ }
119
+ }, {}
120
+ )
121
+ };
122
+ })
123
+ relations.forEach( (relation) =>{
124
+ if(relation.pivot.length>0){
125
+ dispatch(`${relation.module}/sync`, relation.pivot, { root: true })
126
+ }
127
+ })
128
+ return items
129
+ }
130
+
131
+
132
+ export function areObjEquals(foo, bar) {
133
+ let equal = true;
134
+
135
+ for (let [key, val] of Object.entries(foo)) {
136
+ if (Object.prototype.hasOwnProperty.call(bar, key)) {
137
+ if (bar[key] !== val) {
138
+ equal = false;
139
+ }
140
+ } else {
141
+ equal = false;
142
+ }
143
+
144
+ if (!equal) { break; }
145
+ }
146
+
147
+ return equal;
148
+ }
@@ -0,0 +1,325 @@
1
+ //import { resolveRelations, exportRelations, globalExportRelations, areObjEquals } from "./helpers"
2
+ import { areObjEquals } from "./helpers";
3
+ // import { reactive, computed } from 'vue';
4
+
5
+
6
+ export default function createModelStore (model, state = {}, getters = {}, actions = {}) {
7
+ const defData = {
8
+ key : 'id',
9
+ }
10
+ const config = Object.assign(defData, model.getStoreConfig())
11
+ let check =(d,data)=>{return d[config.key] === data[config.key]}
12
+ if ( config.hasKey){
13
+ if(Array.isArray(config.key)){
14
+ let check_str = config.key.reduce((a, key)=>a+` d['${key}'] === data['${key}'] &&`,'(d,data)=>{return')
15
+ check_str = check_str.substring(0, check_str.length-2)
16
+ check_str+='}'
17
+ check = eval(check_str)
18
+ }
19
+ }else{
20
+ console.warn(`El modulo ${config.moduleAlias} no tiene Keys, esto reducira el rendimiento` )
21
+ check=(d,data)=>{
22
+ return areObjEquals(d,data)
23
+ }
24
+ }
25
+ const resolveR = (item) => item
26
+ return {
27
+ state : {
28
+ itemSelected : { loading: false, ...model.getDefault() },
29
+ items : [],
30
+ keysAsinc : [],
31
+ keysTemp : [],
32
+ key : config.key,
33
+ moduleAlias : config.moduleAlias,
34
+ maxRelationsResolve : config.maxRelationsResolve,
35
+ relations : config.relations,
36
+ syncStatus : config.sync,
37
+ selectedStatus : false,
38
+ timeOutAsinc : null,
39
+ check : check,
40
+ ...state
41
+ },
42
+ getters : {
43
+ // Getter para obtener el indice de la tabla
44
+ //key : ({key}) => { return key },
45
+ // Getter para obtener el indice de la tabla
46
+ default : () => { return model.getDefault() },
47
+ // Getter para obtener el nombre del objeto seleccionado
48
+ name : ({ items, key }) => (id) => {
49
+ const item = items.find(d => d[key] === id)
50
+ return item ? item[model.getNameAttribute()] : null
51
+ },
52
+ // Getter para obtener el objeto seleccionado
53
+ find : ({ items, key }) => (id, level = 1) => {
54
+ const item = items.find(d => d[key] === id)
55
+ return item ? resolveR(item, level):model.getDefault()
56
+ },
57
+ // Getter para obtener la lista de objetos
58
+ list : ({items}) => {
59
+ return items.map(resolveR)
60
+ },
61
+ // Getter para obtener la lista de objetos filtrados
62
+ filter : ({items}) => (filter, level = 1) => {
63
+ return items.filter(filter).map(item => resolveR(item, level))
64
+ },
65
+ // Getter para obtener el objeto seleccionado o falso si no hay seleccion
66
+ selected : ({ itemSelected, selectedStatus }) => {
67
+ return selectedStatus ? resolveR(itemSelected) : selectedStatus
68
+ },
69
+ ...getters
70
+ },
71
+
72
+ actions : {
73
+
74
+ checkAsinc( key ){
75
+ return new Promise((resolve) => {
76
+ const fTime = () => {
77
+ let keys=[]
78
+ keys=keys.concat(this.keysTemp)
79
+ if (Array.isArray(keys)) {
80
+ this.keysAsinc = this.keysAsinc.concat(keys)
81
+ } else {
82
+ this.keysAsinc.push(keys)
83
+ }
84
+ this.keysTemp=[]
85
+ let params={}
86
+ params[this.key]=['IN'].concat(keys)
87
+ this.getSome(params)
88
+ this.timeOutAsinc = null
89
+ }
90
+ if (Array.isArray(key)) {
91
+ let keys=key
92
+ key.forEach((d,i)=>{
93
+ if((this.items.findIndex(d1=>(d1[this.key]==d))!=-1)||(this.keysAsinc.indexOf(d)!=-1)||(this.keysTemp.indexOf(d)!=-1))
94
+ {
95
+ keys.splice(i,1)
96
+ }
97
+ })
98
+ if(keys.length>0){
99
+ this.keysTemp=this.keysTemp.concat(keys)
100
+ }
101
+ if(this.timeOutAsinc == null){
102
+ this.timeOutAsinc = setTimeout(fTime, 100)
103
+ }
104
+ resolve( keys)
105
+ }
106
+ else{
107
+ const item = this.find(key)
108
+ if(item[this.key]==null){
109
+ if(!this.keysAsinc.find(d=>d==key)&&!this.keysTemp.find(d=>d==key)){
110
+ this.keysTemp.push(key)
111
+ }
112
+ if(this.timeOutAsinc == null){
113
+ this.timeOutAsinc = setTimeout(fTime, 100)
114
+ }
115
+ }
116
+ resolve(item)
117
+ }
118
+ })
119
+ },
120
+ // Action para obtener un registro por el (key) del servicor
121
+ show(id){
122
+ //var commit = store.commit
123
+ return new Promise((resolve, reject) => {
124
+ model.show(id).then(response => {
125
+ this.syncItem(response.data)
126
+ resolve(response);
127
+ }).catch(reject);
128
+ })
129
+ },
130
+ // Action para obtener la lista de objetos de el servidor
131
+ async get (params = {}) {
132
+ //var commit = store.commit
133
+ const action = this.syncStatus ? 'sync' : 'setItems';
134
+
135
+ if (!(await model.saved(params))) {
136
+ return new Promise((resolve, reject) => {
137
+ model.getAll(params).then(response => {
138
+ const data = response.data;
139
+ model.save(data.data);
140
+ this[action](data.data);
141
+ this.afterGet();
142
+ resolve(response);
143
+ }).catch(reject);
144
+ })
145
+ } else {
146
+ this[action](model.getFromLocalStorage());
147
+ this.afterGet();
148
+ }
149
+ },
150
+
151
+ // Action para obtener la lista de algunos objetos de el servidor sin consultar ni almacenar en el localstorage
152
+ getSome( params = {}){
153
+ //var commit = store.commit
154
+ return new Promise((resolve, reject) => {
155
+ model.getAll(params).then(response => {
156
+ this.sync(response.data);
157
+ this.afterGet();
158
+ resolve(response);
159
+ }).catch(reject);
160
+ })
161
+ },
162
+ // Action para limpiar el state y obtener la lista de algunos objetos de el servidor
163
+ clearAndGet(params = {}){
164
+ return new Promise((resolve, reject) => {
165
+ // se agrega esta linea "dispatch('setItems', [])" para que al momento de cargar los nuevos datos la reactividad sea mas veloz
166
+ // divide y vencceras
167
+ this.setItems([]);
168
+ model.getAll(params).then(response => {
169
+ this.setItems(response.data);
170
+ this.afterGet();
171
+ resolve(response);
172
+ }).catch(reject);
173
+ })
174
+ },
175
+ // Action que se ejecuta después de obtener la lista de objetos
176
+ afterGet(){
177
+ //
178
+ },
179
+
180
+ // Action para crear un objeto en la base de datos y en la lista de objetos
181
+ create( data){
182
+ return new Promise((resolve, reject) => {
183
+ model.create(data).then(response => {
184
+ this.syncItem(response.data.data);
185
+ resolve(response)
186
+ }).catch(error => {
187
+ reject(error)
188
+ })
189
+ })
190
+ },
191
+
192
+ // Action para actualizar un objeto en la base de datos y en la lista de objetos
193
+ update( data){
194
+ return new Promise((resolve, reject) => {
195
+ model.update(data).then(response => {
196
+ this.syncItem(response.data.data);
197
+ resolve(response)
198
+ }).catch(error => {
199
+ reject(error)
200
+ })
201
+ })
202
+ },
203
+
204
+ // Action para eliminar un objeto de la base de datos y de la lista de objetos
205
+ delete(data){
206
+ return new Promise((resolve, reject) => {
207
+ model.delete(data).then(response => {
208
+ let index = this.items.findIndex(d => this.check(d,data))
209
+ this.items.splice(index, 1)
210
+ resolve(response)
211
+ }).catch(error => {
212
+ reject(error)
213
+ })
214
+ })
215
+ },
216
+ /*
217
+ ***** action para setear objetos (items) en el store ***
218
+ */
219
+ setItems (items) {
220
+
221
+ /* if(state.relations.length>0&&items.length>0){
222
+ let relations = state.relations
223
+ relations = relations.filter(relation=>{
224
+ let alias = relation.alias != undefined ? relation.alias : relation.attribute
225
+ return items[0][alias]!=undefined
226
+ })
227
+ //items = globalExportRelations(items, relations, dispatch, rootGetters)
228
+ } */
229
+ this.items = items
230
+ },
231
+ /*
232
+ ***** action para setear el syncStatus ***
233
+ */
234
+ setSyncStatus( syncStatus){
235
+ this.syncStatus = syncStatus
236
+ },
237
+ /*
238
+ ***** action para determinar si se actualizara un objeto o varios de acuerdo al formato de llegada de la data ***
239
+ */
240
+ sync(data){
241
+ if (typeof data === 'object' && data !== null) {
242
+ if (Array.isArray(data)) {
243
+ this.syncItems(data);
244
+ } else {
245
+ this.syncItem(data);
246
+ }
247
+ }
248
+ },
249
+
250
+ addToRelation({relation, id, relations}){
251
+ if (this.relations.some(r=>r.alias==relation)) {
252
+ let index = this.items.findIndex(d => d[this.key] === id)
253
+ if(Array.isArray(relations)){
254
+ this.items[index][relation] = this.items[index][relation].cocat(relations)
255
+ }else{
256
+ this.items[index][relation].push(relations)
257
+ }
258
+ }
259
+ },
260
+ /*
261
+ ***** action para sincronizar objetos (items) con los objetos almacenado en el store ***
262
+ */
263
+ syncItems(items){
264
+ //este filter elimina los valores duplicados
265
+ items=items.filter((data, index, array)=>array.findIndex(d=>this.check(d,data)) === index)
266
+ /* if(this.state.relations.length>0&&items.length>0){
267
+ let relations = this.state.relations
268
+ relations = relations.filter(relation=>{
269
+ let alias = relation.alias != undefined ? relation.alias : relation.attribute
270
+ return items[0][alias]!=undefined
271
+ })
272
+ items = globalExportRelations(items, relations, dispatch, rootGetters)
273
+ } */
274
+ let insert = items.filter( (item) =>{
275
+ let i = this.items.findIndex(d=>this.check(d,item))
276
+ if (i > -1) {
277
+ this.items[i] = Object.assign(this.items[i], item)
278
+ return false
279
+ }else{
280
+ return true
281
+ }
282
+ });
283
+ this.items = this.items.concat(insert)
284
+ },
285
+ /*
286
+ ***** action para sincronizar un objeto (item) con un objeto almacenado en el store ***
287
+ */
288
+ syncItem(item){
289
+ // cambio this.state.items por this.items
290
+ //item = resolveRelations(item, this.state, dispatch, rootGetters));
291
+ if (this.find(item[this.key])[this.key] !== null && this.find(item[this.key])[this.key] !== undefined) {
292
+ //UPDATE
293
+ let index = this.items.findIndex(d => this.check(d,item))
294
+ this.items[index] = Object.assign(this.items[index], item)
295
+ } else {
296
+ //CREATE
297
+ this.items.push(item)
298
+ }
299
+ },
300
+
301
+ /********* MUTACIONES COMO ACTIONS */
302
+ // Mutation para setear el listado de objetos
303
+ SET_ITEMS( items ){
304
+ /* if(state.relations.length>0&&items.length>0){
305
+ let relations = state.relations
306
+ relations = relations.filter(relation=>{
307
+ let alias = relation.alias != undefined ? relation.alias : relation.attribute
308
+ return items[0][alias]!=undefined
309
+ })
310
+ items = globalExportRelations(items, relations, dispatch, rootGetters)
311
+ } */
312
+ this.items = items
313
+ },
314
+
315
+ ADD_ITEMS(items){
316
+ if (Array.isArray(items)) {
317
+ this.items = this.items.concat(items)
318
+ } else {
319
+ this.items.push(items)
320
+ }
321
+ },
322
+ ...actions
323
+ }
324
+ };
325
+ }