devcode-canavar-pro 3.3.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.
@@ -0,0 +1,295 @@
1
+ const path = require('path');
2
+ const crypto = require('crypto');
3
+ const EventEmitter = require('events');
4
+ const Journal = require('./Journal');
5
+ const QueryParser = require('./QueryParser');
6
+ const UpdateParser = require('./UpdateParser');
7
+ const Index = require('./Index');
8
+ const Middleware = require('./Middleware');
9
+ const Cache = require('./Cache');
10
+ const Storage = require('./Storage');
11
+
12
+ /**
13
+ * Collection Class
14
+ * Veri ekleme, silme, güncelleme ve sorgulama işlemlerini yönetir.
15
+ */
16
+ class Collection extends EventEmitter {
17
+ constructor(name, dbPath) {
18
+ super();
19
+ this.name = name;
20
+ this.dbPath = dbPath;
21
+ this.filePath = path.join(dbPath, `${name}.devcode`);
22
+ this.journal = new Journal(dbPath);
23
+ this.middleware = new Middleware();
24
+ this.cache = new Cache(5000); // 5000 dökümanlık hızlı bellek
25
+ this.schema = null;
26
+ this.indexes = new Map();
27
+ this.queryStats = new Map(); // Auto-indexing için istatistikler
28
+ this.data = [];
29
+ this.transactionData = null;
30
+ this._load();
31
+ }
32
+
33
+ /**
34
+ * Koleksiyon için şema belirler.
35
+ */
36
+ setSchema(schemaInstance) {
37
+ this.schema = schemaInstance;
38
+ }
39
+
40
+ /**
41
+ * Middleware kancası ekler.
42
+ */
43
+ pre(action, fn) { this.middleware.pre(action, fn); }
44
+ post(action, fn) { this.middleware.post(action, fn); }
45
+
46
+ /**
47
+ * Belirli bir alan için indeks oluşturur.
48
+ */
49
+ createIndex(field) {
50
+ const index = new Index(this.name, field, this.dbPath);
51
+ this.indexes.set(field, index);
52
+
53
+ // Mevcut verileri indeksle
54
+ this.data.forEach(doc => {
55
+ if (doc[field]) index.add(doc[field], doc._id);
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Veriyi diskten yükler.
61
+ * @private
62
+ */
63
+ _load() {
64
+ try {
65
+ this.data = Storage.load(this.filePath);
66
+ // Cache'e at
67
+ this.data.forEach(doc => this.cache.set(doc._id, doc));
68
+ } catch (err) {
69
+ console.error(`Koleksiyon yükleme hatası (${this.name}):`, err);
70
+ this.data = [];
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Veriyi diske kaydeder.
76
+ * @private
77
+ */
78
+ _save() {
79
+ Storage.save(this.filePath, this.data);
80
+ }
81
+
82
+ /**
83
+ * Döküman ekler.
84
+ * @param {Object} doc
85
+ */
86
+ async insert(doc) {
87
+ // 1. Şema Doğrulama
88
+ if (this.schema) this.schema.validate(doc);
89
+
90
+ // 2. Pre-Insert Middleware
91
+ await this.middleware.runPre('insert', doc);
92
+
93
+ this.journal.lock();
94
+ try {
95
+ const newDoc = {
96
+ _id: crypto.randomBytes(12).toString('hex'),
97
+ ...doc,
98
+ createdAt: new Date()
99
+ };
100
+
101
+ // Günlüğe kaydet
102
+ await this.journal.record(this.name, 'INSERT', newDoc);
103
+
104
+ // Veriyi ekle (Transaction varsa oraya, yoksa ana veriye)
105
+ const target = this.transactionData || this.data;
106
+ target.push(newDoc);
107
+
108
+ // İndeksleri güncelle (Sadece transaction yoksa veya commit edilince)
109
+ if (!this.transactionData) {
110
+ this._save();
111
+ this.indexes.forEach((idx, field) => {
112
+ if (newDoc[field]) idx.add(newDoc[field], newDoc._id);
113
+ });
114
+ }
115
+
116
+ // 3. Olay Yayınla (Real-time)
117
+ this.emit('insert', newDoc);
118
+ this.emit('change', { type: 'INSERT', data: newDoc });
119
+
120
+ // 4. Post-Insert Middleware
121
+ await this.middleware.runPost('insert', newDoc);
122
+
123
+ return newDoc;
124
+ } finally {
125
+ this.journal.unlock();
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Toplu döküman ekler (Ultra Hızlı).
131
+ * @param {Object[]} docs
132
+ */
133
+ async insertMany(docs) {
134
+ if (!Array.isArray(docs)) throw new Error('Dizi gönderilmelidir.');
135
+
136
+ this.journal.lock();
137
+ try {
138
+ const added = [];
139
+ for (let doc of docs) {
140
+ if (this.schema) this.schema.validate(doc);
141
+ const newDoc = {
142
+ _id: crypto.randomBytes(12).toString('hex'),
143
+ ...doc,
144
+ createdAt: new Date()
145
+ };
146
+ added.push(newDoc);
147
+
148
+ // Toplu işlemde cache ve data güncelle
149
+ this.data.push(newDoc);
150
+ this.cache.set(newDoc._id, newDoc);
151
+
152
+ this.indexes.forEach((idx, field) => {
153
+ if (newDoc[field]) idx.add(newDoc[field], newDoc._id);
154
+ });
155
+ }
156
+
157
+ await this.journal.record(this.name, 'INSERT_MANY', { count: docs.length });
158
+ this._save();
159
+ this.emit('insertMany', added);
160
+ return added;
161
+ } finally {
162
+ this.journal.unlock();
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Gelişmiş sorgu motorunu kullanarak arama yapar.
168
+ * (Eğer indeks varsa indeks üzerinden hızlandırır)
169
+ */
170
+ find(query = {}) {
171
+ // 1. İndeks Kullanımı (Eğer tek bir alan üzerinden basit eşitlik aranıyorsa)
172
+ const queryFields = Object.keys(query);
173
+
174
+ // Eğer tek bir basit sorgu varsa ve indeksi varsa kullan
175
+ if (queryFields.length === 1 && typeof query[queryFields[0]] !== 'object') {
176
+ const field = queryFields[0];
177
+ const val = query[field];
178
+
179
+ if (this.indexes.has(field)) {
180
+ const ids = this.indexes.get(field).get(val);
181
+ return this.data.filter(item => ids.includes(item._id));
182
+ }
183
+
184
+ // İstatistik tut (Eğer çok sorgulanıyorsa otomatik indeksle)
185
+ this.queryStats.set(field, (this.queryStats.get(field) || 0) + 1);
186
+ if (this.queryStats.get(field) > 100) { // 100 sorguda bir indeks oluştur
187
+ console.log(`🚀 [Auto-Index] '${field}' alanı çok sorgulanıyor, indeksleniyor...`);
188
+ this.createIndex(field);
189
+ this.queryStats.set(field, -999999); // Tekrar tetiklenme
190
+ }
191
+ }
192
+
193
+ return this.data.filter(item => QueryParser.matches(item, query));
194
+ }
195
+
196
+ /**
197
+ * Tek bir döküman bulur.
198
+ */
199
+ findOne(query = {}) {
200
+ const results = this.find(query);
201
+ return results.length > 0 ? results[0] : null;
202
+ }
203
+
204
+ /**
205
+ * Dökümanları günceller ($set, $inc, $push vb. destekler).
206
+ * @param {Object} query Filtreleme sorgusu
207
+ * @param {Object} updateQuery Güncelleme operatörleri
208
+ */
209
+ async update(query, updateQuery) {
210
+ const targets = this.find(query);
211
+ if (targets.length === 0) return 0;
212
+
213
+ await this.middleware.runPre('update', { query, updateQuery });
214
+
215
+ targets.forEach(doc => {
216
+ UpdateParser.parse(doc, updateQuery);
217
+ doc.updatedAt = new Date();
218
+ this.cache.set(doc._id, doc);
219
+ });
220
+
221
+ this._save();
222
+ await this.journal.record(this.name, 'UPDATE', { query, count: targets.length });
223
+
224
+ await this.middleware.runPost('update', targets);
225
+ this.emit('update', targets);
226
+ return targets.length;
227
+ }
228
+
229
+ /**
230
+ * Tek bir dökümanı günceller.
231
+ */
232
+ async updateOne(query, updateQuery) {
233
+ const doc = this.findOne(query);
234
+ if (!doc) return false;
235
+
236
+ UpdateParser.parse(doc, updateQuery);
237
+ doc.updatedAt = new Date();
238
+ this.cache.set(doc._id, doc);
239
+
240
+ this._save();
241
+ await this.journal.record(this.name, 'UPDATE_ONE', { id: doc._id });
242
+ return true;
243
+ }
244
+
245
+ /**
246
+ * Verileri siler.
247
+ */
248
+ async remove(query = {}) {
249
+ const initialLength = this.data.length;
250
+ const toDeleteIDs = this.data
251
+ .filter(item => QueryParser.matches(item, query))
252
+ .map(item => item._id);
253
+
254
+ if (toDeleteIDs.length === 0) return 0;
255
+
256
+ await this.middleware.runPre('remove', query);
257
+
258
+ this.data = this.data.filter(item => !toDeleteIDs.includes(item._id));
259
+ toDeleteIDs.forEach(id => this.cache.del(id));
260
+
261
+ this._save();
262
+ await this.journal.record(this.name, 'REMOVE', { query, count: toDeleteIDs.length });
263
+
264
+ await this.middleware.runPost('remove', toDeleteIDs);
265
+ this.emit('remove', toDeleteIDs);
266
+ return toDeleteIDs.length;
267
+ }
268
+
269
+ // --- TRANSACTION DESTEĞİ ---
270
+
271
+ startTransaction() {
272
+ this.transactionData = JSON.parse(JSON.stringify(this.data));
273
+ }
274
+
275
+ commitTransaction() {
276
+ if (this.transactionData) {
277
+ this.data = this.transactionData;
278
+ this.transactionData = null;
279
+ this._save();
280
+ // İndeksleri sıfırla ve yeniden oluştur
281
+ this.indexes.forEach((idx, field) => {
282
+ idx.clear();
283
+ this.data.forEach(doc => {
284
+ if (doc[field]) idx.add(doc[field], doc._id);
285
+ });
286
+ });
287
+ }
288
+ }
289
+
290
+ abortTransaction() {
291
+ this.transactionData = null;
292
+ }
293
+ }
294
+
295
+ module.exports = Collection;
package/lib/Core.js ADDED
@@ -0,0 +1,164 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const Database = require('./Database');
4
+ const Dashboard = require('./Dashboard');
5
+ const CLI = require('./CLI');
6
+ const BackupService = require('./BackupService');
7
+ const Server = require('./Server');
8
+
9
+ /**
10
+ * DevCode Core Manager
11
+ * Veritabanı yönetiminden sorumlu ana sınıf.
12
+ */
13
+ class DevCode {
14
+ constructor(options = {}) {
15
+ this.dataPath = options.dataPath || path.join(process.cwd(), 'data');
16
+ this.databases = new Map();
17
+ this._backup = null;
18
+
19
+ // Veri klasörünü oluştur
20
+ if (!fs.existsSync(this.dataPath)) {
21
+ fs.mkdirSync(this.dataPath, { recursive: true });
22
+ }
23
+
24
+ // Otomatik Güncelleme Kontrolü
25
+ this.checkUpdate();
26
+
27
+ // Otomatik Yedekleme (VDS için önerilir)
28
+ if (options.backup) {
29
+ const backupOpts = typeof options.backup === 'object' ? options.backup : {};
30
+ this._backup = new BackupService(this.dataPath, backupOpts);
31
+ this._backup.start();
32
+ }
33
+
34
+ // Otomatik Dashboard Başlatma
35
+ if (options.dashboard) {
36
+ this.startDashboard(options.port || 3000);
37
+ } else {
38
+ console.log(`\x1b[32m[DevCode]\x1b[0m Monster v2.0 aktif. Görsel panel için: \x1b[4m{ dashboard: true }\x1b[0m`);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * NPM üzerinden sürüm kontrolü yapar.
44
+ */
45
+ async checkUpdate() {
46
+ try {
47
+ const https = require('https');
48
+ const pkg = require('../package.json');
49
+
50
+ https.get(`https://registry.npmjs.org/${pkg.name}/latest`, (res) => {
51
+ let data = '';
52
+ res.on('data', chunk => data += chunk);
53
+ res.on('end', () => {
54
+ try {
55
+ const latest = JSON.parse(data).version;
56
+ if (latest !== pkg.version) {
57
+ console.log(`\n\x1b[33m[!] YENİ GÜNCELLEME SİNYALİ:\x1b[0m v${pkg.version} -> \x1b[32mv${latest}\x1b[0m`);
58
+ console.log(`\x1b[33m[!] Güncellemek için:\x1b[0m npm i ${pkg.name}@latest\n`);
59
+ }
60
+ } catch (e) { }
61
+ });
62
+ }).on('error', () => { });
63
+ } catch (e) { }
64
+ }
65
+
66
+ /**
67
+ * Bir veritabanına bağlanır veya yoksa oluşturur.
68
+ * @param {string} dbName Veritabanı adı
69
+ * @param {string} namespace İsteğe bağlı namespace (VDS Multi-tenancy için)
70
+ * @returns {Database} Veritabanı örneği
71
+ */
72
+ use(dbName, namespace = null) {
73
+ if (!dbName || typeof dbName !== 'string') {
74
+ throw new Error('Geçersiz veritabanı adı.');
75
+ }
76
+
77
+ const fullDbName = namespace ? `${namespace}/${dbName}` : dbName;
78
+
79
+ if (this.databases.has(fullDbName)) {
80
+ return this.databases.get(fullDbName);
81
+ }
82
+
83
+ const dbPath = path.join(this.dataPath, fullDbName);
84
+ const db = new Database(dbName, dbPath);
85
+ this.databases.set(fullDbName, db);
86
+
87
+ return db;
88
+ }
89
+
90
+ /**
91
+ * Mevcut veritabanlarını listeler.
92
+ * @param {string} namespace - Opsiyonel, sadece bu namespace içindeki DB'leri listeler.
93
+ * @returns {string[]} Veritabanı isimleri
94
+ */
95
+ listDatabases(namespace = null) {
96
+ const searchPath = namespace ? path.join(this.dataPath, namespace) : this.dataPath;
97
+ if (!fs.existsSync(searchPath)) return [];
98
+ return fs.readdirSync(searchPath)
99
+ .filter(file => {
100
+ try {
101
+ return fs.statSync(path.join(searchPath, file)).isDirectory();
102
+ } catch (e) {
103
+ return false;
104
+ }
105
+ });
106
+ }
107
+
108
+ /**
109
+ * Bir veritabanını tamamen siler.
110
+ * @param {string} dbName Silinecek veritabanı adı
111
+ */
112
+ dropDatabase(dbName) {
113
+ const dbPath = path.join(this.dataPath, dbName);
114
+ if (fs.existsSync(dbPath)) {
115
+ fs.rmSync(dbPath, { recursive: true, force: true });
116
+ this.databases.delete(dbName);
117
+ return true;
118
+ }
119
+ return false;
120
+ }
121
+
122
+ /**
123
+ * BackupService örneğine erişim sağlar.
124
+ * @returns {BackupService}
125
+ */
126
+ get backup() {
127
+ if (!this._backup) {
128
+ throw new Error("Yedekleme servisi aktif değil. DevCode()'u { backup: true } ile başlatın.");
129
+ }
130
+ return this._backup;
131
+ }
132
+
133
+ /**
134
+ * Uzak bağlantı sunucusunu başlatır (VDS için).
135
+ * Kullanıcılar RemoteClient ile bu sunucuya bağlanabilir.
136
+ * @param {object} options
137
+ * @param {number} options.port - Port numarası (varsayılan: 4242)
138
+ * @param {string} options.secret - Güvenlik anahtarı
139
+ * @returns {Server}
140
+ */
141
+ startServer(options = {}) {
142
+ const server = new Server(this, options);
143
+ server.start();
144
+ return server;
145
+ }
146
+
147
+ /**
148
+ * Görsel Dashboard'u başlatır.
149
+ */
150
+ startDashboard(port = 3000) {
151
+ const dash = new Dashboard(this, port);
152
+ dash.start();
153
+ }
154
+
155
+ /**
156
+ * İnteraktif Shell'i (CLI) başlatır.
157
+ */
158
+ startShell() {
159
+ const shell = new CLI(this);
160
+ shell.start();
161
+ }
162
+ }
163
+
164
+ module.exports = DevCode;