in src/providers/firestore.ts [150:246]
export function objectToValueProto(data: object) {
const encodeHelper = (val) => {
if (typeof val === 'string') {
return {
stringValue: val,
};
}
if (typeof val === 'boolean') {
return {
booleanValue: val,
};
}
if (typeof val === 'number') {
if (val % 1 === 0) {
return {
integerValue: val,
};
}
return {
doubleValue: val,
};
}
if (val instanceof Date) {
return {
timestampValue: val.toISOString(),
};
}
if (val instanceof Array) {
let encodedElements = [];
for (const elem of val) {
const enc = encodeHelper(elem);
if (enc) {
encodedElements.push(enc);
}
}
return {
arrayValue: {
values: encodedElements,
},
};
}
if (val === null) {
// TODO: Look this up. This is a google.protobuf.NulLValue,
// and everything in google.protobuf has a customized JSON encoder.
// OTOH, Firestore's generated .d.ts files don't take this into
// account and have the default proto layout.
return {
nullValue: 'NULL_VALUE',
};
}
if (val instanceof Buffer || val instanceof Uint8Array) {
return {
bytesValue: val,
};
}
if (val instanceof firestore.DocumentReference) {
const projectId: string = get(val, '_referencePath.projectId');
const database: string = get(val, '_referencePath.databaseId');
const referenceValue: string = [
'projects',
projectId,
'databases',
database,
val.path,
].join('/');
return { referenceValue };
}
if (val instanceof firestore.Timestamp) {
return {
timestampValue: val.toDate().toISOString(),
};
}
if (val instanceof firestore.GeoPoint) {
return {
geoPointValue: {
latitude: val.latitude,
longitude: val.longitude,
},
};
}
if (isPlainObject(val)) {
return {
mapValue: {
fields: objectToValueProto(val),
},
};
}
throw new Error(
'Cannot encode ' +
val +
'to a Firestore Value.' +
` Local testing does not yet support objects of type ${val?.constructor?.name}.`
);
};
return mapValues(data, encodeHelper);
}