@dataql/firebase-adapter
Version:
Firebase adapter for DataQL with zero API changes
293 lines • 9.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initializeApp = initializeApp;
exports.getFirestore = getFirestore;
const core_1 = require("@dataql/core");
// Implementation classes
class DataQLDocumentSnapshot {
constructor(id, _data, exists) {
this.id = id;
this._data = _data;
this.exists = exists;
}
data() {
return this._data || undefined;
}
get(field) {
return this._data && typeof this._data === "object"
? this._data[field]
: undefined;
}
}
class DataQLQueryDocumentSnapshot {
constructor(id, _data) {
this.id = id;
this._data = _data;
}
data() {
return this._data;
}
get(field) {
return typeof this._data === "object"
? this._data[field]
: undefined;
}
}
class DataQLQuerySnapshot {
constructor(documents) {
this.docs = documents.map((doc) => new DataQLQueryDocumentSnapshot(doc.id, doc.data));
this.empty = documents.length === 0;
this.size = documents.length;
}
forEach(callback) {
this.docs.forEach(callback);
}
}
class DataQLDocumentReference {
constructor(id, path, _data, _collectionName) {
this.id = id;
this.path = path;
this._data = _data;
this._collectionName = _collectionName;
}
get _collection() {
return this._data.collection(this._collectionName, this._getDefaultSchema());
}
_getDefaultSchema() {
return {
id: { type: "ID", required: true },
createdAt: { type: "Date", default: "now" },
updatedAt: { type: "Date", default: "now" },
};
}
async get() {
try {
const results = await this._collection.find({ id: this.id });
const result = results[0] || null;
return new DataQLDocumentSnapshot(this.id, result, !!result);
}
catch (error) {
return new DataQLDocumentSnapshot(this.id, null, false);
}
}
async set(data, options) {
try {
if (options?.merge) {
await this._collection.upsert({ id: this.id, ...data });
}
else {
await this._collection.create({ id: this.id, ...data });
}
return { writeTime: new Date().toISOString() };
}
catch (error) {
throw new Error(`Failed to set document: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
async update(data) {
try {
await this._collection.update({ id: this.id }, data);
return { writeTime: new Date().toISOString() };
}
catch (error) {
throw new Error(`Failed to update document: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
async delete() {
try {
await this._collection.delete({ id: this.id });
return { writeTime: new Date().toISOString() };
}
catch (error) {
throw new Error(`Failed to delete document: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
onSnapshot(onNext, onError) {
console.log(`Subscribed to document ${this.path}`);
return () => {
console.log(`Unsubscribed from document ${this.path}`);
};
}
}
class DataQLQuery {
constructor(_data, _collectionName) {
this._data = _data;
this._collectionName = _collectionName;
this._filters = [];
}
get _collection() {
return this._data.collection(this._collectionName, this._getDefaultSchema());
}
_getDefaultSchema() {
return {
id: { type: "ID", required: true },
createdAt: { type: "Date", default: "now" },
updatedAt: { type: "Date", default: "now" },
};
}
where(fieldPath, opStr, value) {
const newQuery = new DataQLQuery(this._data, this._collectionName);
newQuery._filters = [
...this._filters,
{ field: fieldPath, operator: opStr, value },
];
newQuery._orderBy = this._orderBy;
newQuery._limit = this._limit;
return newQuery;
}
orderBy(fieldPath, directionStr) {
const newQuery = new DataQLQuery(this._data, this._collectionName);
newQuery._filters = [...this._filters];
newQuery._orderBy = { field: fieldPath, direction: directionStr || "asc" };
newQuery._limit = this._limit;
return newQuery;
}
limit(limit) {
const newQuery = new DataQLQuery(this._data, this._collectionName);
newQuery._filters = [...this._filters];
newQuery._orderBy = this._orderBy;
newQuery._limit = limit;
return newQuery;
}
_buildDataQLFilter() {
const filter = {};
for (const filterItem of this._filters) {
const { field, operator, value } = filterItem;
switch (operator) {
case "==":
filter[field] = value;
break;
case "!=":
filter[field] = { $ne: value };
break;
case "<":
filter[field] = { $lt: value };
break;
case "<=":
filter[field] = { $lte: value };
break;
case ">":
filter[field] = { $gt: value };
break;
case ">=":
filter[field] = { $gte: value };
break;
case "array-contains":
filter[field] = { $in: [value] };
break;
case "in":
filter[field] = { $in: value };
break;
case "array-contains-any":
filter[field] = { $in: value };
break;
default:
filter[field] = value;
}
}
return filter;
}
_applySort(results) {
if (!this._orderBy)
return results;
const { field, direction } = this._orderBy;
return results.sort((a, b) => {
const aVal = a[field];
const bVal = b[field];
let comparison = 0;
if (aVal < bVal)
comparison = -1;
else if (aVal > bVal)
comparison = 1;
return direction === "desc" ? -comparison : comparison;
});
}
async get() {
try {
const filter = this._buildDataQLFilter();
let results = await this._collection.find(filter);
results = this._applySort(results);
if (this._limit) {
results = results.slice(0, this._limit);
}
const documents = results.map((item) => ({
id: item.id || Math.random().toString(36).substr(2, 9),
data: item,
}));
return new DataQLQuerySnapshot(documents);
}
catch (error) {
throw new Error(`Query failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
onSnapshot(onNext, onError) {
console.log(`Subscribed to collection ${this._collectionName} query`);
return () => {
console.log(`Unsubscribed from collection ${this._collectionName} query`);
};
}
}
class DataQLCollectionReference extends DataQLQuery {
constructor(id, path, data) {
super(data, id);
this.id = id;
this.path = path;
}
doc(documentPath) {
const docId = documentPath || Math.random().toString(36).substr(2, 9);
return new DataQLDocumentReference(docId, `${this.path}/${docId}`, this._data, this.id);
}
async add(data) {
const docId = Math.random().toString(36).substr(2, 9);
const docRef = this.doc(docId);
await docRef.set(data);
return docRef;
}
}
class DataQLFirestore {
constructor(_data) {
this._data = _data;
}
collection(collectionPath) {
return new DataQLCollectionReference(collectionPath, collectionPath, this._data);
}
doc(documentPath) {
const pathParts = documentPath.split("/");
const collectionName = pathParts[0];
const docId = pathParts[1];
return new DataQLDocumentReference(docId, documentPath, this._data, collectionName);
}
}
class DataQLFirebaseApp {
constructor(name, options, _data) {
this.name = name;
this.options = options;
this._data = _data;
this.firestore = new DataQLFirestore(_data);
}
}
// Main Firebase functions
function initializeApp(config, options) {
// Ensure proper DataQL infrastructure routing (Client → Worker → Lambda → Database)
const dataqlOptions = {
appToken: options?.appToken || "default", // Required for DataQL routing
env: options?.env || "prod", // Routes to production infrastructure
devPrefix: options?.devPrefix || "dev_", // Optional prefix for dev environments
dbName: options?.dbName, // Database isolation per client
customConnection: options?.customConnection, // Optional custom connection
};
const data = new core_1.Data(dataqlOptions);
return new DataQLFirebaseApp("default", config, data);
}
function getFirestore(app) {
if (!app) {
throw new Error("Firebase app not initialized");
}
return app.firestore;
}
// Default export
exports.default = {
initializeApp,
getFirestore,
};
//# sourceMappingURL=index.js.map