monkey-ldb 1.0.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,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ciberinuverse
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/MonkeyDB.js ADDED
@@ -0,0 +1,327 @@
1
+ const fs = require("fs/promises")
2
+ const monkey_document = require("./modules/native_documents.js")
3
+ const monkey_utils = require("./modules/utils.js")
4
+
5
+ async function read_document(name) {
6
+ let document_read = await fs.readFile(name)
7
+ return JSON.parse(document_read)
8
+ }
9
+
10
+ async function save_document(name, new_document_object) {
11
+ await fs.writeFile(name, JSON.stringify(new_document_object))
12
+ }
13
+
14
+ class MonkeyCli {
15
+
16
+ #document_cached = {
17
+ "time": 0,
18
+ "document": 0,
19
+ }
20
+
21
+ constructor(name, path_collections, use_cache = false) {
22
+ this.name = name
23
+
24
+ // Path collections es donde se almacenan todos los documentos
25
+ this.path_collections = monkey_utils.normalize_url(path_collections)
26
+ this.use_cache = use_cache
27
+
28
+ // Full path collection incluye el nombre de este documento con json
29
+ this.full_path_collection = this.path_collections + "/" + this.name + ".json"
30
+ }
31
+
32
+ async #cache_document() {
33
+
34
+ let files_list = await fs.readdir(this.path_collections + "/")
35
+
36
+ // Si no estamos en modo cache
37
+ if (!this.use_cache) {
38
+
39
+ // Se verifica que no exista el documento. Si no existe se retorna un false
40
+ if (!files_list.includes(this.name + ".json")) {
41
+ this.#document_cached["document"] = []
42
+ return false
43
+ }
44
+
45
+ // Si existe el documento, se lee y se retorna true
46
+ // guardando el contenido de el documento en una variable privada
47
+ this.#document_cached["document"] = await read_document(this.full_path_collection)
48
+ return true
49
+ }
50
+
51
+ let time_now = Date.now()
52
+
53
+ // Si el documento no existe dentro de la carpeta de la base de datos
54
+ if (!files_list.includes(this.name + ".json")) {
55
+
56
+ // Se almacena de manera global un array vacio como tambien la hora
57
+ this.#document_cached["time"] = time_now
58
+ this.#document_cached["document"] = []
59
+
60
+ // Se guarad el documento vacio para evitar que siga un siclo
61
+ await save_document(this.full_path_collection, [])
62
+
63
+ // Se retorna el array vacio indicando que no existe ningun documento asociado
64
+ return false
65
+ }
66
+
67
+ // Si el documento aun no esta cacheado se lee y se guarda y se retorna true
68
+ if (this.#document_cached["document"] === 0) {
69
+
70
+ this.#document_cached["time"] = time_now
71
+ this.#document_cached["document"] = await read_document(this.full_path_collection)
72
+
73
+ return true
74
+ }
75
+
76
+ // Se suman 5 minutos en ms al tiempo desde que se guardo el anterior estado
77
+ let time_cached = this.#document_cached["time"] + 3000
78
+
79
+ // Si se superan los 5 minutos se actualiza el cacheado y se guarda en el documento
80
+ if (time_cached < time_now) {
81
+ this.#document_cached["time"] = time_now
82
+ await save_document(this.full_path_collection, this.#document_cached["document"])
83
+ }
84
+
85
+ // Se retorna el documento cacheado
86
+ return true
87
+ }
88
+
89
+ async find_one(object_find, object_project = null) {
90
+
91
+ // Se verifica la existencia del archivo o si existe cache
92
+ let exist_doc = await this.#cache_document()
93
+ if (!exist_doc) {return {}}
94
+
95
+ return monkey_document.iter_document_array(
96
+ object_find,
97
+ object_project,
98
+ this.#document_cached["document"],
99
+ "find_one"
100
+ )
101
+
102
+ }
103
+
104
+ async find(object_find, object_project = null) {
105
+
106
+ // Se verifica la existencia del documento
107
+ let exist_doc = await this.#cache_document()
108
+ if (!exist_doc) {return []}
109
+
110
+ return monkey_document.iter_document_array(object_find, object_project, this.#document_cached["document"], "find")
111
+
112
+ }
113
+
114
+ async insert_one(object_insert) {
115
+ await this.#cache_document()
116
+
117
+ let _id = object_insert["_id"] || monkey_utils.gen_uuid()
118
+
119
+ object_insert["_id"] = _id
120
+
121
+ // Se verifica la existencia del documento
122
+ this.#document_cached["document"].push(object_insert)
123
+
124
+ // Si no se esta usando la forma de cache se guarda el documento
125
+ if (!this.use_cache) {
126
+ await save_document(this.full_path_collection, this.#document_cached["document"])
127
+ }
128
+
129
+ return monkey_utils.monkey_db_return({
130
+ "acknowledged": true,
131
+ "_id": _id,
132
+ "insertedCount": 1
133
+ })
134
+ }
135
+
136
+ async insert_many(array_insert) {
137
+ await this.#cache_document()
138
+
139
+ let insertedIds = []
140
+
141
+ for (let doc_one of array_insert) {
142
+
143
+ // Se genera un id para el objeto a insertar
144
+ let _id = doc_one["_id"] || monkey_utils.gen_uuid()
145
+
146
+ // Se le asigna el id
147
+ doc_one["_id"] = _id
148
+
149
+ // Se le asigna al buffer
150
+ this.#document_cached["document"].push(doc_one)
151
+ insertedIds.push(_id)
152
+
153
+ }
154
+
155
+ if (!insertedIds) {
156
+ return monkey_utils.monkey_db_return({
157
+ "acknowledged": false,
158
+ "insertedCount": 0,
159
+ "insertedIds": []
160
+ })
161
+ }
162
+
163
+
164
+ if (!this.use_cache) {
165
+ await save_document(this.full_path_collection, this.#document_cached["document"])
166
+ }
167
+
168
+ return monkey_utils.monkey_db_return({
169
+ "acknowledged": true,
170
+ "insertedCount": insertedIds.length,
171
+ "insertedIds": insertedIds
172
+ })
173
+ }
174
+
175
+ async delete_one(object_find) {
176
+ await this.#cache_document()
177
+
178
+ let acknowledged = false
179
+
180
+ let index_delete = monkey_document.iter_document_array(object_find, null, this.#document_cached["document"], "delete_one")
181
+ this.#document_cached["document"].splice(index_delete)
182
+
183
+ if (!this.use_cache) {
184
+ await save_document(this.full_path_collection, this.#document_cached["document"])
185
+ }
186
+
187
+ return monkey_utils.monkey_db_return({
188
+ "acknowledged": true,
189
+ "deletedCount": 1,
190
+ })
191
+ }
192
+
193
+ async delete_many(object_find) {
194
+ await this.#cache_document()
195
+
196
+ let array_of_index_delete = await monkey_document.iter_document_array(object_find, null, this.#document_cached["document"], "delete_many")
197
+
198
+ if (!array_of_index_delete) {
199
+ return monkey_utils.monkey_db_return({
200
+ "acknowledged": false,
201
+ "deletedCount": 0
202
+ })
203
+ }
204
+
205
+ for (let index_delete of array_of_index_delete) {
206
+ this.#document_cached["document"].splice(index_delete)
207
+ }
208
+
209
+
210
+ if (!this.use_cache) {
211
+ await save_document(this.full_path_collection, this.#document_cached["document"])
212
+ }
213
+
214
+ let deleted_account = array_of_index_delete.length
215
+ return monkey_utils.monkey_db_return({
216
+ "acknowledged": true,
217
+ "deletedCount": deleted_account
218
+ })
219
+
220
+ }
221
+
222
+ async update_one(object_find, mod_filter) {
223
+ await this.#cache_document()
224
+
225
+
226
+ let response = await monkey_document.iter_document_array(object_find, mod_filter, this.#document_cached["document"], "update_one")
227
+
228
+ let new_document = response[0]
229
+
230
+ if (!new_document) {return monkey_utils.monkey_db_return({
231
+ "acknowledged": false,
232
+ "matchedCount": 0,
233
+ "modifiedCount": 0
234
+ })}
235
+
236
+ let index_update = response[1]
237
+
238
+ this.#document_cached["document"][index_update] = new_document
239
+
240
+ if (!this.use_cache) {
241
+ await save_document(this.full_path_collection, this.#document_cached["document"])
242
+ }
243
+
244
+ return monkey_utils.monkey_db_return({
245
+ "acknowledged": true,
246
+ "matchedCount": 1,
247
+ "modifiedCount": 1
248
+ })
249
+
250
+ }
251
+
252
+ async update_many(object_find, mod_filter) {
253
+ await this.#cache_document()
254
+
255
+
256
+ let response = await monkey_document.iter_document_array(object_find, mod_filter, this.#document_cached["document"], "update_many")
257
+
258
+ for (let doc_updated of response) {
259
+
260
+ let new_document = doc_updated[0]
261
+ let index_update = doc_updated[1]
262
+
263
+ this.#document_cached["document"][index_update] = new_document
264
+
265
+ }
266
+
267
+ if (!this.use_cache) {
268
+ await save_document(this.full_path_collection, this.#document_cached["document"])
269
+ }
270
+
271
+ let mod_count = response.length
272
+ return monkey_utils.monkey_db_return({
273
+ "acknowledged": true,
274
+ "modifiedCount": mod_count,
275
+ "matchedCount": mod_count
276
+ })
277
+ }
278
+ }
279
+
280
+ class MonkeyDB {
281
+
282
+ #collections = []
283
+
284
+ constructor(name_db, path_db = ".", cache = false) {
285
+ this.name_db = name_db
286
+ this.path_db = monkey_utils.normalize_url(path_db)
287
+
288
+ this.cache = cache
289
+ this.uri = path_db + "/" + name_db
290
+ }
291
+
292
+ // Funcion privada encargada de verificar que la base de datos se encuentre en la carpeta
293
+ async #dir_db_exist() {
294
+
295
+ let db_dir = await fs.readdir(this.path_db)
296
+
297
+ // De no ser asi la crea
298
+ if (!db_dir.includes(this.name_db)) {
299
+ await fs.mkdir(this.name_db)
300
+ }
301
+
302
+ // Actualiza la lista de colecciones en la bd
303
+ this.#collections = await fs.readdir(this.uri + "/")
304
+ }
305
+
306
+ async create_collection(name_collection) {
307
+ // Verifica y crea la carpeta de la base de datos si es necesario
308
+ await this.#dir_db_exist()
309
+
310
+ return new MonkeyCli(name_collection, this.uri, this.cache)
311
+ }
312
+
313
+ async drop_collection(name_collection) {
314
+ await this.#dir_db_exist()
315
+
316
+ if (!this.#collections.includes(name_collection + ".json")) {
317
+ return false
318
+ }
319
+
320
+ await fs.rm(this.uri + "/" + name_collection + ".json")
321
+ return true
322
+ }
323
+
324
+ }
325
+
326
+ // Se exporta unicamente MonkeyDB encargado de crear la base de datos
327
+ module.exports = {MonkeyDB}
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # MonkeyDB
2
+
3
+ > Una base de datos NoSQL local para Node.js, inspirada en MongoDB y construida con pura curiosidad y ganas de aprender.
4
+
5
+ ![Si no estoy durmiendo, estoy programando](assets/monkeydb.png)
6
+ *Si no estoy durmiendo, estoy programando.*
7
+
8
+ MonkeyDB es una base de datos experimental que almacena datos en archivos JSON, diseñada para proyectos pequeños que necesitan una API familiar de MongoDB sin levantar un servidor externo. Nació como un ejercicio de aprendizaje y para cubrir una necesidad personal: quería una base de datos local y liviana que se sintiera como MongoDB, pero sin saber que ya existían varias alternativas consolidadas. Así que… ¿Por qué no construir la mía?
9
+
10
+ ## Características
11
+
12
+ - **API inspirada en MongoDB** – usa métodos como `find()`, `insert_one()`, `insert_many()`.
13
+ - **Almacenamiento local** – cada colección se guarda como un archivo JSON.
14
+ - **Proyecciones** – puedes elegir qué campos devolver en las consultas (`{ "_id": 0 }`).
15
+ - **Caché opcional** – mejora el rendimiento cuando trabajas con colecciones grandes.
16
+ - **Manejo asíncrono** – basado en `fs/promises` para no bloquear el event loop.
17
+ - **Multi‑colección** – agrupa tus datos en colecciones dentro de una misma base de datos.
18
+
19
+ ## Instalación
20
+
21
+ *(Pendiente de publicación en npm)*
22
+
23
+ ## Uso básico
24
+
25
+ ```javascript
26
+ const { MonkeyDB } = require('monkeydb');
27
+
28
+ (async () => {
29
+ // Crear o abrir una base de datos
30
+ const db = new MonkeyDB('mi_app', './data', false);
31
+
32
+ // Crear una colección (automáticamente crea la carpeta si no existe)
33
+ const users = await db.create_collection('users');
34
+
35
+ // Insertar un documento
36
+ const result = await users.insert_one({ name: 'Ana', age: 28 });
37
+ console.log(result); // { acknowledged: true, _id: '...' }
38
+
39
+ // Insertar varios documentos
40
+ await users.insert_many([
41
+ { name: 'Luis', age: 34 },
42
+ { name: 'Elena', age: 25 }
43
+ ]);
44
+
45
+ // Buscar documentos con filtro y proyección
46
+ const ana = await users.find_one({ name: 'Ana' }, { _id: 0 });
47
+ console.log(ana); // { name: 'Ana', age: 28 }
48
+
49
+ const mayores = await users.find({ age: { $gt: 30 } }); // pronto operadores
50
+ console.log(mayores); // []
51
+ })();
52
+ ```
53
+
54
+ ## API
55
+
56
+ ### `MonkeyDB(name_db, path_db, options)`
57
+ - `name_db` – nombre de la base de datos (se usará como carpeta).
58
+ - `path_db` – ruta donde se almacenará la carpeta de la base de datos (por defecto `"."`).
59
+ - `cache` – habilita el sistema de caché experimental (por defecto `false`).
60
+
61
+ ### `db.create_collection(name_collection)`
62
+ Crea una nueva colección (si no existe) y devuelve una instancia de `MonkeyCli`.
63
+
64
+ ### `collection.insert_one(document)`
65
+ Inserta un documento y devuelve un objeto con `acknowledged` y el `_id` generado.
66
+
67
+ ### `collection.insert_many(array)`
68
+ Inserta un array de documentos y devuelve `acknowledged`, `insertedCount` e `insertedIds`.
69
+
70
+ ### `collection.find(filter, projection)`
71
+ Devuelve un array con todos los documentos que coinciden con el filtro.
72
+ `projection` permite excluir campos con `{ campo: 0 }`.
73
+
74
+ ### `collection.find_one(filter, projection)`
75
+ Devuelve el primer documento que coincide con el filtro, o `{}` si no hay resultados.
76
+
77
+ ## Estado actual y roadmap
78
+
79
+ MonkeyDB está en una fase **experimental**. Lo que ya funciona:
80
+
81
+ - `create_collection`
82
+ - `insert_one` / `insert_many`
83
+ - `find` / `find_one` con proyecciones básicas (solo exclusión)
84
+ - Operadores de consulta: `$gt`, `$lt`, `$in`, `$regex`, etc.
85
+ - Actualizaciones: `update_one`, `update_many`
86
+ - Eliminaciones: `delete_one`, `delete_many`
87
+ - Caché funcional (actualmente en pruebas)
88
+ - Uso asíncrono con `fs/promises`
89
+ - Rutas configurables
90
+ - Tests manuales
91
+
92
+ Próximas mejoras (¡contribuciones bienvenidas!):
93
+
94
+ - 🔄 Índices para mejorar búsquedas
95
+ - 🔄 Migración hacia/desde otras bases de datos (MongoDB, SQLite, etc.)
96
+ - 🔄 Tests unitarios y de integración
97
+
98
+ ## Módulos
99
+
100
+ MonkeyDB está organizado en tres módulos internos que mantienen el código limpio y extensible:
101
+
102
+ | Módulo | Archivo | Propósito |
103
+ |--------|---------|-----------|
104
+ | **Operadores de actualización** | `operators_update.js` | Contiene todas las funciones y utilidades para acciones de update: `$set`, `$unset`, `$rename`, `$max`, `$min`, `$currentDate`, `$push`, `$pull`, etc. Exporta como única utilidad la función `operators_update`. |
105
+ | **Operadores de búsqueda** | `operators.js` | Implementa los operadores de consulta: `$ne`, `$nin`, `$in`, `$eq`, `$lt`, `$gt`, etc. Exporta como única función `operators_find`. |
106
+ | **Utilidades** | `utils.js` | Funciones de mantenimiento y ayuda, como las respuestas uniformes de MonkeyDB (consistencia en los formatos de salida). |
107
+
108
+ Estos módulos se integran en el archivo principal y permiten añadir nuevos operadores sin modificar la lógica central.
109
+
110
+ ## Agradecimientos
111
+
112
+ Este proyecto está fuertemente inspirado en **MongitaDB**, una base de datos local que a su vez emula MongoDB. ¡Gracias a su creador por allanar el camino y sacarme de varios apuros mientras desarrollaba otros proyectos!
Binary file
@@ -0,0 +1,98 @@
1
+ const monkey_operators = require("./operators.js")
2
+ const monkey_operators_update = require("./operators_update.js")
3
+
4
+ let iters_with_index = ["delete_many", "delete_one", "update_one", "update_many"]
5
+ function iter_document_array(object_find, object_project = null, array_document, type_r = "find") {
6
+
7
+ let return_doc = []
8
+ let index_list = 0 // Variable que se usara para todo lo que requiera indice de listas
9
+
10
+
11
+ // Se establece el numero de coincidencias desde el objeto a buscar
12
+ let check = Object.values(object_find).length
13
+
14
+
15
+
16
+ // Por cada documento encontrado se revisara que cumpla con el filtro enviado
17
+ for (let one_doc of array_document) {
18
+
19
+ // Contador de coincidencias por usuario
20
+ let passed_check = 0
21
+
22
+ // Se setean las variables para usarle dentro del for
23
+ let key, value
24
+
25
+ for ([key, value] of Object.entries(object_find)) {
26
+ if (monkey_operators.operators_find(one_doc, key, value)) {passed_check += 1}
27
+ }
28
+
29
+ /* Seccion unicamente para resultados unicos que no requieren mayor iteracion */
30
+ // Se usan else if al ser mas rapidos
31
+ if (type_r === "delete_one" && passed_check === check) {
32
+ return index_list
33
+ }
34
+
35
+ // Se retorna la primera coincidencia con la proyeccion si es que se esta pidiendo uno solo
36
+ else if (type_r === "find_one" && passed_check === check) {
37
+ return project(one_doc, object_project)
38
+ }
39
+
40
+ else if (type_r === "update_one" && passed_check === check) {
41
+ return [monkey_operators_update.operators_update(one_doc, object_project), index_list]
42
+ }
43
+
44
+ /* ===================================================================== */
45
+
46
+ /* Seccion operacion listado
47
+
48
+ Todo lo que esta aqui debajo hasta lo limitado son las operaciones que requieren de una iteracion
49
+ completa del documento. Tales como find, delete_many
50
+
51
+ */
52
+
53
+ // Si se cumple con el filtro se agrega a la lista y se continua
54
+ else if (type_r === "find" && passed_check === check) {
55
+ return_doc.push(project(one_doc, object_project))
56
+ continue
57
+ }
58
+
59
+ // Zonas que requieren indices
60
+ else if (type_r === "delete_many" && passed_check === check) {
61
+ return_doc.push(index_list)
62
+ }
63
+
64
+ else if (type_r === "update_many" && passed_check === check) {
65
+ return_doc.push([monkey_operators_update.operators_update(one_doc, object_project), index_list])
66
+ }
67
+
68
+ if (iters_with_index.includes(type_r)) {index_list += 1}
69
+
70
+ }
71
+
72
+ // Se retornan todos los documentos en la lista
73
+ return return_doc
74
+
75
+ }
76
+
77
+ function project(object_return, object_project = null) {
78
+
79
+ // Si es que no se trae ninguna proyeccion se retorna el objeto intacto
80
+ if (object_project === null) {return object_return}
81
+
82
+ let key, value
83
+ for ([key, value] of Object.entries(object_project)) {
84
+
85
+ // Si se le asigno un false o un 0 se elimina esa key del object
86
+ if (!value) {
87
+ delete object_return[key]
88
+ }
89
+
90
+ }
91
+
92
+ // Se retorna el nuevo object
93
+ return object_return
94
+ }
95
+
96
+ module.exports = {
97
+ iter_document_array
98
+ }
@@ -0,0 +1,73 @@
1
+ function eq(one_doc_value, value_find) {return one_doc_value === value_find}
2
+ function ne(one_doc_value, value_find) {return one_doc_value !== value_find}
3
+ function gt(one_doc_value, value_find) {return one_doc_value > value_find}
4
+ function gte(one_doc_value, value_find) {return one_doc_value >= value_find}
5
+ function lt(one_doc_value, value_find) {return one_doc_value < value_find}
6
+ function lte(one_doc_value, value_find) {return one_doc_value <= value_find}
7
+ function in_d(one_doc_value, value_find) {return value_find.includes(one_doc_value)}
8
+ function nin_d(one_doc_value, value_find) {return !value_find.includes(one_doc_value)}
9
+
10
+ let operators = {
11
+ "$eq": eq,
12
+ "$ne": ne,
13
+ "$gt": gt,
14
+ "$gte": gte,
15
+ "$lt": lt,
16
+ "$lte": lte,
17
+ "$in": in_d,
18
+ "$nin": nin_d
19
+ }
20
+
21
+
22
+ function operators_find(one_doc, key_find, value_find) {
23
+
24
+ // Si se encuentra la coincidencia directa se retorna true
25
+ if (one_doc[key_find] === value_find) {return true}
26
+
27
+ // Si no es un objeto el que se envio es porque no contiene operadores por ende es falso
28
+ if (typeof value_find !== 'object') {return false}
29
+
30
+ // Se obtiene la lista de operadores a trabajar
31
+ let operators_list_find = Object.keys(value_find)
32
+
33
+ // Se verifica si es mas de uno. En caso de serlo se itera por cada operador enviando los resultados a un array
34
+ if (operators_list_find.length > 1) {
35
+
36
+ let result_filter = []
37
+ for (let key_operator of operators_list_find) {
38
+
39
+ operator_function_execute = operators[key_operator]
40
+ if (!operator_function_execute) {
41
+ return false
42
+ }
43
+
44
+ result_filter.push(operator_function_execute(one_doc[key_find], value_find[key_operator]))
45
+ }
46
+
47
+ // Cuando se termina la iteracion, se verifica que el array contenga todas las respuestas como true.
48
+ return result_filter.every(x => x === true)
49
+
50
+ }
51
+
52
+ // Value find es esto: {"$ne": "ola"}
53
+ let operator = operators_list_find[0] // Esto se transforma en $ne
54
+ let operator_value = value_find[operator] // Esto se transforma en 'ola'
55
+
56
+ let operator_in = operators[operator] // Operator in obtiene la funcion almacenada en el diccionario
57
+
58
+ // Si no existe un operador valido o no existe una funcion asociada, se retorna falso
59
+ if (!operator || !operator_in) {
60
+ return false
61
+ }
62
+
63
+ // One doc value es el valor del documento tiene para comparar
64
+ let one_doc_value = one_doc[key_find]
65
+
66
+ // Se pasan los dos parametros a comparar dependiendo del operador
67
+ return operator_in(one_doc_value, operator_value)
68
+
69
+ }
70
+
71
+ module.exports = {
72
+ operators_find
73
+ }
@@ -0,0 +1,227 @@
1
+ function set(document_object, list_modifications) {
2
+
3
+ let mods_list = Object.keys(list_modifications)
4
+
5
+ for (let key_dict_on_document of mods_list) {
6
+ document_object[key_dict_on_document] = list_modifications[key_dict_on_document]
7
+ }
8
+
9
+ return document_object
10
+
11
+ }
12
+ function unset(document_object, list_modifications) {
13
+
14
+ let mods_list = Object.keys(list_modifications)
15
+
16
+ for (let key_dict_on_document of mods_list) {
17
+ delete document_object[key_dict_on_document]
18
+ }
19
+
20
+ return document_object
21
+
22
+ }
23
+
24
+ function rename(document_object, list_modifications) {
25
+ let mods_list = Object.keys(list_modifications)
26
+
27
+
28
+ for (let key_dict_on_document of mods_list) {
29
+
30
+ let buff_doc, is_json
31
+
32
+ // Se intenta copiar el contenido dentro del nombre de la variable
33
+ try {
34
+ buff_doc = JSON.stringify(document_object[key_dict_on_document])
35
+ is_json = true
36
+ }
37
+ catch {
38
+ buff_doc = document_object[key_dict_on_document]
39
+ }
40
+
41
+ // Se borra del diccionario original
42
+ delete document_object[key_dict_on_document]
43
+
44
+ // Se verifica que la funcion fue marcada como json
45
+ if (is_json === true) {
46
+ buff_doc = JSON.parse(buff_doc)
47
+ }
48
+
49
+ // Y se crea un nuevo objeto con el nombre ya cambiado con el mismo contenido
50
+ document_object[list_modifications[key_dict_on_document]] = buff_doc
51
+
52
+ }
53
+
54
+ return document_object
55
+ }
56
+
57
+ function inc(document_object, list_modifications) {
58
+
59
+ let mods_list = Object.keys(list_modifications)
60
+
61
+ for (let key_dict_on_document of mods_list) {
62
+ document_object[key_dict_on_document] += list_modifications[key_dict_on_document]
63
+ }
64
+
65
+ return document_object
66
+
67
+ }
68
+
69
+ function mul(document_object, list_modifications) {
70
+ let mods_list = Object.keys(list_modifications)
71
+
72
+ for (let key_dict_on_document of mods_list) {
73
+ document_object[key_dict_on_document] = document_object[key_dict_on_document] * list_modifications[key_dict_on_document]
74
+ }
75
+
76
+ return document_object
77
+ }
78
+
79
+ function currentDate(document_object, list_modifications) {
80
+ let mods_list = Object.keys(list_modifications)
81
+
82
+ for (let key_dict_on_document of mods_list) {
83
+ document_object[key_dict_on_document] = Date.now()
84
+ }
85
+
86
+ return document_object
87
+ }
88
+
89
+ function push_d(document_object, list_modifications) {
90
+ let mods_list = Object.keys(list_modifications)
91
+
92
+ for (let key_dict_on_document of mods_list) {
93
+
94
+ let list_in_doc = document_object[key_dict_on_document]
95
+ if (!list_in_doc) {
96
+ document_object[key_dict_on_document] = [list_modifications[key_dict_on_document]]
97
+ continue
98
+ }
99
+
100
+ document_object[key_dict_on_document].push(list_modifications[key_dict_on_document])
101
+
102
+ }
103
+
104
+ return document_object
105
+ }
106
+
107
+ function pull_d(document_object, list_modifications) {
108
+
109
+ let mods_list = Object.keys(list_modifications)
110
+
111
+ for (let key_dict_on_document of mods_list) {
112
+
113
+ let list_in_doc = document_object[key_dict_on_document]
114
+ if (!list_in_doc) {
115
+ continue
116
+ }
117
+
118
+ document_object[key_dict_on_document] = document_object[key_dict_on_document].filter(x => x !== list_modifications[key_dict_on_document])
119
+
120
+ }
121
+
122
+ return document_object
123
+
124
+ }
125
+
126
+ function max(document_object, list_modifications) {
127
+ let mods_list = Object.keys(list_modifications)
128
+
129
+ for (let key_dict_on_document of mods_list) {
130
+
131
+ if (list_modifications[key_dict_on_document] > document_object[key_dict_on_document]) {
132
+ document_object[key_dict_on_document] = list_modifications[key_dict_on_document]
133
+ }
134
+ }
135
+
136
+ return document_object
137
+ }
138
+
139
+ function min(document_object, list_modifications) {
140
+ let mods_list = Object.keys(list_modifications)
141
+
142
+ for (let key_dict_on_document of mods_list) {
143
+
144
+ if (list_modifications[key_dict_on_document] < document_object[key_dict_on_document]) {
145
+ document_object[key_dict_on_document] = list_modifications[key_dict_on_document]
146
+ }
147
+ }
148
+
149
+ return document_object
150
+ }
151
+
152
+ function pop_d(document_object, list_modifications) {
153
+ let mods_list = Object.keys(list_modifications)
154
+
155
+ for (let key_dict_on_document of mods_list) {
156
+
157
+ if (!document_object[key_dict_on_document]) {continue}
158
+
159
+ let idx_max = document_object[key_dict_on_document].length
160
+
161
+ // Si la lista solo contiene un elemento, se evita el slice y se retorna directamente vacio
162
+ if (idx_max === 1) {
163
+ document_object[key_dict_on_document] = []
164
+ continue
165
+ }
166
+
167
+ // Si se desea borrar unicamente el ultimo valor, se borra xd
168
+ if (list_modifications[key_dict_on_document] === 1) {
169
+ document_object[key_dict_on_document].splice(idx_max - 1)
170
+ continue
171
+ }
172
+
173
+ // Splice 0, 1 se usa porque quiero eliminar el indice 0 y especifico unicamente un elemento
174
+ // a eliminar, o splice toma todo el array completo.
175
+ document_object[key_dict_on_document].splice(0, 1)
176
+
177
+ }
178
+
179
+ return document_object
180
+ }
181
+
182
+ let operators_update_dict = {
183
+ "$set": set,
184
+ "$unset": unset,
185
+ "$rename": rename,
186
+ "$inc": inc,
187
+ "$mul": mul,
188
+ "$max": max,
189
+ "$min": min,
190
+ "$currentDate": currentDate,
191
+
192
+ "$push": push_d,
193
+ "$pop": pop_d,
194
+ "$pull": pull_d,
195
+ }
196
+
197
+ function operators_update(one_doc, operators_project) {
198
+
199
+ let operators_updates = Object.keys(operators_project)
200
+
201
+
202
+ if (operators_updates.length > 1) {
203
+
204
+ for (let key_update of operators_updates) {
205
+ let function_execute = operators_update_dict[key_update]
206
+
207
+ if (!function_execute) {continue}
208
+
209
+ one_doc = function_execute(one_doc, operators_project[key_update])
210
+ }
211
+
212
+ return one_doc
213
+ }
214
+
215
+ let function_execute = operators_update_dict[operators_updates[0]]
216
+
217
+ if (!function_execute) {return one_doc}
218
+
219
+ one_doc = function_execute(one_doc, operators_project[operators_updates[0]])
220
+
221
+ return one_doc
222
+
223
+ }
224
+
225
+ module.exports = {
226
+ operators_update
227
+ }
@@ -0,0 +1,39 @@
1
+ const crypto = require("crypto")
2
+
3
+ function monkey_db_return({acknowledged, _id = null, insertedCount = null, insertedIds = null, matchedCount = null, modifiedCount = null, deletedCount = null}) {
4
+
5
+ let return_vars = {
6
+ "acknowledged": acknowledged,
7
+ "_id": _id,
8
+ "insertedCount": insertedCount,
9
+
10
+ "matchedCount": matchedCount,
11
+ "modifiedCount": modifiedCount,
12
+ "insertedIds": insertedIds,
13
+ "deletedCount": deletedCount
14
+ }
15
+
16
+ // Se itera cada clave valor de el diccionario y se eliminan los vacios
17
+ let key, value
18
+ for ([key, value] of Object.entries(return_vars)) {
19
+ if (value === null) {
20
+ delete return_vars[key]
21
+ }
22
+ }
23
+ console.log(return_vars)
24
+ return return_vars
25
+ }
26
+
27
+ function normalize_url(url = "") {
28
+ if (url.endsWith("/")) {return url.slice(0, -1)}
29
+ return url
30
+ }
31
+
32
+ function gen_uuid() {
33
+ let uuid = String(Date.now())
34
+ return crypto.createHash("md5").update(uuid).digest("hex")
35
+ }
36
+
37
+ module.exports = {
38
+ monkey_db_return, normalize_url, gen_uuid
39
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "monkey-ldb",
3
+ "version": "1.0.0",
4
+ "description": "> Una base de datos NoSQL local para Node.js, inspirada en MongoDB y construida con pura curiosidad y ganas de aprender.",
5
+ "main": "MonkeyDB.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ciberuniverse/MonkeyDB.git"
12
+ },
13
+ "keywords": [],
14
+ "author": "Hernan Miranda",
15
+ "license": "MIT",
16
+ "type": "commonjs",
17
+ "bugs": {
18
+ "url": "https://github.com/ciberuniverse/MonkeyDB/issues"
19
+ },
20
+ "homepage": "https://github.com/ciberuniverse/MonkeyDB#readme"
21
+ }