Skip to main content
Module

x/dynamodb/util.ts

deno <3 dynamodb
Latest
File
const ANY_BUT_DIGITS: RegExp = /[^\d]/g;const ANY_BUT_DIGITS_T: RegExp = /[^\dT]/g;
/** Generic document. */export interface Doc { [key: string]: any;}
/** noop. */export function noop(..._: any[]): void {}
/** camelCase */export function camelCase(text: string): string { return `${text[0].toLowerCase()}${text.slice(1)}`;}
/** Defines a property. */export function property( obj: any, name: string, value: any, enumerable?: boolean, isValue?: boolean,): void { const opts: Doc = { configurable: true, enumerable: typeof enumerable === "boolean" ? enumerable : true, };
if (typeof value === "function" && !isValue) { opts.get = value; } else { opts.value = value; opts.writable = true; }
Object.defineProperty(obj, name, opts);}
/** Defines a memoized property. */export function memoizedProperty( obj: any, name: string, get: () => any, enumerable?: boolean,): void { let cachedValue: any = null;
// build enumerable attribute for each value with lazy accessor. property( obj, name, (): void => { if (cachedValue === null) { cachedValue = get(); }
return cachedValue; }, enumerable, );}
/** aws typeof impl. */export function typeOf(data: any): string { if (data === null && typeof data === "object") { return "null"; } else if (data !== undefined && isBinary(data)) { return "Binary"; } else if (data !== undefined && data.constructor) { return data.wrapperName || data.constructor.name; } else if (data !== undefined && typeof data === "object") { // this object is the result of Object.create(null), hence the absence of a // defined constructor return "Object"; } else { return "undefined"; }}
/** Is given value a binary type? */function isBinary(data: any): boolean { const types: string[] = [ "Buffer", "File", "Blob", "ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array", "Int32Array", "Uint32Array", "Float32Array", "Float64Array", ];
// if (util.isNode()) { // var Stream = util.stream.Stream; // if (util.Buffer.isBuffer(data) || data instanceof Stream) { // return true; // } // }
// var isType = (obj, type) => Object.prototype.toString.call(obj) === '[object ' + type + ']';
if (data !== undefined && data.constructor) { // console.error(">>>>>>>>>> isBinary data", data) // for (let i: number = 0; i < types.length; i++) { // // // if (util.isType(data, types[i])) return true; // if (data.constructor.name === types[i]) { // // console.error(">>>> isBinary TRUE", data) // return true; // } // // if(isType(data, types[i])) { // // return true // // } // // } return types.some( (type: string): boolean => data.constructor.name === type, ); }
return false;}
/** Mapping member to set type. */const memberTypeToSetType: Doc = { String: "String", Number: "Number", NumberValue: "Number", Binary: "Binary",};
/** DynamoDB set type. */export class DynamoDBSet { readonly wrappername: string = "Set"; readonly values: any[] = []; readonly type: string = "";
/** Creates a dynamodb set. */ constructor(list: any[] = [], options: Doc = {}) { Array.prototype.push.apply(this.values, list);
this.type = memberTypeToSetType[typeOf(this.values[0])];
if (!this.type) { throw new Error( "DynamoDB sets can only contain string, number, or binary values", ); }
if (options.validate) { for (const value of this.values) { if (memberTypeToSetType[typeOf(value)] !== this.type) { throw new Error(`${this.type} Set contains ${typeOf(value)} value`); } } } }
/** Renders the underlying values only when converting to JSON. */ toJSON(): any[] { return this.values; }}
/** * An object recognizable as a numeric value that stores the underlying number * as a string. * * Intended to be a deserialization target for the DynamoDB Doc Client when * the `wrapNumbers` flag is set. This allows for numeric values that lose * precision when converted to JavaScript's `number` type. */export class DynamoDBNumberValue { readonly wrapperName: string = "NumberValue"; readonly value: string;
/** Creates a dynamodb number value. */ constructor(value: number | string) { this.value = value.toString(); }
/** Renders the underlying value as a number when converting to JSON. */ toJSON(): number { return this.toNumber(); }
/** Converts the underlying value to a JavaScript number. */ toNumber(): number { return Number(this.value); }
/** Returns a decimal string representing the number value. */ toString(): string { return this.value; }}
/** Date format helpers. */export const date: Doc = { /** Date stamp format as expected by awsSignatureV4KDF. */ DATE_STAMP_REGEX: /^\d{8}$/, amz(date: Date): string { return `${ date .toISOString() .slice(0, 19) .replace(ANY_BUT_DIGITS_T, "") }Z`; }, dateStamp(date: Date): string { return date .toISOString() .slice(0, 10) .replace(ANY_BUT_DIGITS, ""); }, from(date: number | string | Date): Date { if (typeof date === "number") { return new Date(date * 1000); // unix timestamp } else { return new Date(date as any); } }, iso8601(date: Date = new Date()): string { return date.toISOString().replace(/\.\d{3}Z$/, "Z"); }, rfc822(date: Date = new Date()): string { return date.toUTCString(); }, unixTimestamp(date: Date = new Date()): number { return date.getTime() / 1000; }, /** Valid formats are: iso8601, rfc822, unixTimestamp, dateStamp, amz. */ format(date: Date, formatter: string = "iso8601"): number | string { return this[formatter](this.from(date)); }, parseTimestamp(value: number | string): Date { if (typeof value === "number") { // unix timestamp (number) return new Date(value * 1000); } else if (value.match(/^\d+$/)) { // unix timestamp return new Date(Number(value) * 1000); } else if (value.match(/^\d{4}/)) { // iso8601 return new Date(value); } else if (value.match(/^\w{3},/)) { // rfc822 return new Date(value); } else { throw new Error(`unhandled timestamp format: ${value}`); } },};