nexabase-console 2.0.2 → 2.0.3
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/README.md +34 -0
- package/dist/firestore/Query.d.ts +9 -1
- package/dist/firestore/Query.js +62 -1
- package/dist/types/index.d.ts +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,6 +142,40 @@ const listenLiveChats = () => {
|
|
|
142
142
|
};
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
#### Agregasi Data & Hitung Dokumen (`getCountFromServer` / `getAggregateFromServer`)
|
|
146
|
+
Mendukung fungsi agregasi server 1:1 seperti Firebase SDK: `getCountFromServer()`, `getAggregateFromServer()`, `count()`, `sum()`, dan `average()`.
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
import {
|
|
150
|
+
collection,
|
|
151
|
+
query,
|
|
152
|
+
where,
|
|
153
|
+
getCountFromServer,
|
|
154
|
+
getAggregateFromServer,
|
|
155
|
+
count,
|
|
156
|
+
sum,
|
|
157
|
+
average
|
|
158
|
+
} from 'nexabase-console';
|
|
159
|
+
|
|
160
|
+
// 1. Menghitung total dokumen (getCountFromServer)
|
|
161
|
+
const productsRef = collection(db, 'products');
|
|
162
|
+
const qAvailable = query(productsRef, where('status', '==', 'active'));
|
|
163
|
+
|
|
164
|
+
const countSnapshot = await getCountFromServer(qAvailable);
|
|
165
|
+
console.log("Total produk aktif:", countSnapshot.data().count);
|
|
166
|
+
|
|
167
|
+
// 2. Agregasi multi-field (getAggregateFromServer)
|
|
168
|
+
const orderStats = await getAggregateFromServer(collection(db, 'orders'), {
|
|
169
|
+
totalOrders: count(),
|
|
170
|
+
totalRevenue: sum('totalAmount'),
|
|
171
|
+
avgOrderValue: average('totalAmount')
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
console.log("Jumlah order:", orderStats.data().totalOrders);
|
|
175
|
+
console.log("Total pendapatan:", orderStats.data().totalRevenue);
|
|
176
|
+
console.log("Rata-rata transaksi:", orderStats.data().avgOrderValue);
|
|
177
|
+
```
|
|
178
|
+
|
|
145
179
|
#### Menggunakan Atomic Write Batch (Untuk Upload File / Excel Massal)
|
|
146
180
|
Jika Anda mengunggah data sekaligus dalam jumlah besar dari file (misal: import 500 resi dari Excel), hindari memanggil `setDoc` satu per satu di dalam _looping_. Gunakan fitur `writeBatch` yang membundel seluruh operasi Anda dalam satu pengiriman jaringan (hingga 500 operasi per eksekusi).
|
|
147
181
|
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FieldPath } from './FieldPath';
|
|
2
|
+
import { CollectionReference, Query, QueryConstraint, QuerySnapshot, AggregateField, AggregateSpec, AggregateSpecData, AggregateQuerySnapshot } from '../types/index';
|
|
2
3
|
export declare const query: <T = any>(queryObject: Query<T> | CollectionReference<T>, ...queryConstraints: QueryConstraint[]) => Query<T>;
|
|
3
4
|
export declare const getCachedDocs: <T = any>(queryOrCollection: Query<T> | CollectionReference<T>) => QuerySnapshot<T>;
|
|
4
5
|
export declare const getDocs: <T = any>(queryOrCollection: Query<T> | CollectionReference<T>) => Promise<QuerySnapshot<T>>;
|
|
6
|
+
export declare const count: () => AggregateField<number>;
|
|
7
|
+
export declare const sum: (field: string | FieldPath) => AggregateField<number>;
|
|
8
|
+
export declare const average: (field: string | FieldPath) => AggregateField<number | null>;
|
|
9
|
+
export declare const getAggregateFromServer: <T extends AggregateSpec>(queryOrCollection: Query<any> | CollectionReference<any>, aggregateSpec: T) => Promise<AggregateQuerySnapshot<AggregateSpecData<T>>>;
|
|
10
|
+
export declare const getCountFromServer: <T = any>(queryOrCollection: Query<T> | CollectionReference<T>) => Promise<AggregateQuerySnapshot<{
|
|
11
|
+
count: number;
|
|
12
|
+
}>>;
|
package/dist/firestore/Query.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDocs = exports.getCachedDocs = exports.query = void 0;
|
|
3
|
+
exports.getCountFromServer = exports.getAggregateFromServer = exports.average = exports.sum = exports.count = exports.getDocs = exports.getCachedDocs = exports.query = void 0;
|
|
4
4
|
const SnapshotManager_1 = require("./SnapshotManager");
|
|
5
5
|
const DocumentReference_1 = require("./DocumentReference");
|
|
6
6
|
const NexaError_1 = require("../errors/NexaError");
|
|
@@ -174,3 +174,64 @@ const getDocs = async (queryOrCollection) => {
|
|
|
174
174
|
}
|
|
175
175
|
};
|
|
176
176
|
exports.getDocs = getDocs;
|
|
177
|
+
const count = () => {
|
|
178
|
+
return { type: 'count' };
|
|
179
|
+
};
|
|
180
|
+
exports.count = count;
|
|
181
|
+
const sum = (field) => {
|
|
182
|
+
return { type: 'sum', fieldPath: field };
|
|
183
|
+
};
|
|
184
|
+
exports.sum = sum;
|
|
185
|
+
const average = (field) => {
|
|
186
|
+
return { type: 'average', fieldPath: field };
|
|
187
|
+
};
|
|
188
|
+
exports.average = average;
|
|
189
|
+
const getAggregateFromServer = async (queryOrCollection, aggregateSpec) => {
|
|
190
|
+
const querySnapshot = await (0, exports.getDocs)(queryOrCollection);
|
|
191
|
+
const docs = querySnapshot.docs;
|
|
192
|
+
const resultData = {};
|
|
193
|
+
for (const [key, spec] of Object.entries(aggregateSpec)) {
|
|
194
|
+
if (spec.type === 'count') {
|
|
195
|
+
resultData[key] = docs.length;
|
|
196
|
+
}
|
|
197
|
+
else if (spec.type === 'sum') {
|
|
198
|
+
const field = spec.fieldPath || '';
|
|
199
|
+
let sumVal = 0;
|
|
200
|
+
for (const d of docs) {
|
|
201
|
+
const val = (0, helpers_1.getNestedValue)(d.data(), field, d.id);
|
|
202
|
+
if (typeof val === 'number' && !isNaN(val)) {
|
|
203
|
+
sumVal += val;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
resultData[key] = sumVal;
|
|
207
|
+
}
|
|
208
|
+
else if (spec.type === 'average') {
|
|
209
|
+
const field = spec.fieldPath || '';
|
|
210
|
+
let sumVal = 0;
|
|
211
|
+
let countVal = 0;
|
|
212
|
+
for (const d of docs) {
|
|
213
|
+
const val = (0, helpers_1.getNestedValue)(d.data(), field, d.id);
|
|
214
|
+
if (typeof val === 'number' && !isNaN(val)) {
|
|
215
|
+
sumVal += val;
|
|
216
|
+
countVal++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
resultData[key] = countVal > 0 ? sumVal / countVal : null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
type: 'AggregateQuerySnapshot',
|
|
224
|
+
query: queryOrCollection,
|
|
225
|
+
data: () => resultData
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
exports.getAggregateFromServer = getAggregateFromServer;
|
|
229
|
+
const getCountFromServer = async (queryOrCollection) => {
|
|
230
|
+
const querySnapshot = await (0, exports.getDocs)(queryOrCollection);
|
|
231
|
+
return {
|
|
232
|
+
type: 'AggregateQuerySnapshot',
|
|
233
|
+
query: queryOrCollection,
|
|
234
|
+
data: () => ({ count: querySnapshot.docs.length })
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
exports.getCountFromServer = getCountFromServer;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -77,6 +77,22 @@ export interface QuerySnapshot<T = any> {
|
|
|
77
77
|
metadata: SnapshotMetadata;
|
|
78
78
|
docChanges: () => DocumentChange<T>[];
|
|
79
79
|
}
|
|
80
|
+
export interface AggregateField<T = number> {
|
|
81
|
+
type: 'count' | 'sum' | 'average';
|
|
82
|
+
fieldPath?: string | FieldPath;
|
|
83
|
+
_returnType?: T;
|
|
84
|
+
}
|
|
85
|
+
export type AggregateSpec = Record<string, AggregateField<any>>;
|
|
86
|
+
export type AggregateSpecData<T extends AggregateSpec> = {
|
|
87
|
+
[K in keyof T]: T[K] extends AggregateField<infer R> ? R : number;
|
|
88
|
+
};
|
|
89
|
+
export interface AggregateQuerySnapshot<T extends Record<string, any> = {
|
|
90
|
+
count: number;
|
|
91
|
+
}> {
|
|
92
|
+
type: 'AggregateQuerySnapshot';
|
|
93
|
+
query: Query<any> | CollectionReference<any>;
|
|
94
|
+
data: () => T;
|
|
95
|
+
}
|
|
80
96
|
export interface DatabaseReference {
|
|
81
97
|
path: string;
|
|
82
98
|
get: () => Promise<any>;
|
package/package.json
CHANGED