# Python Templates
Templates:
    # Syntax
    EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >
        (lhs, op, rhs) => {
            if (op.includes('!')) {
                return `${lhs} != ${rhs}`;
            }
            else {
                return `${lhs} == ${rhs}`;
            }
        }
    EosTemplate: &EosSyntaxTemplate null
    EofTemplate: &EofSyntaxTemplate null
    # BSON Object Type templates
    CodeTypeTemplate: &CodeTypeTemplate null
    StringTypeTemplate: &StringTypeTemplate !!js/function >
        (str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `'${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}'`;
        }
    RegexTypeTemplate: &RegexTypeTemplate !!js/function >
        (pattern, flags) => {
            flags = flags === '' ? '' : `(?${flags})`;
            const escaped = pattern.replace(/\\(?!\/)/, '\\\\');

            // Double-quote stringify
            const str = escaped + flags;
            let newStr = str;
            if (
                (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                    newStr = str.substr(1, str.length - 2);
            }
            return `re.compile(r"${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}")`;
        }
    BoolTypeTemplate: &BoolTypeTemplate !!js/function >
        (str) => {
          return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
        }
    IntegerTypeTemplate: &IntegerTypeTemplate null
    DecimalTypeTemplate: &DecimalTypeTemplate null
    LongBasicTypeTemplate: &LongBasicTypeTemplate null
    HexTypeTemplate: &HexTypeTemplate null
    OctalTypeTemplate: &OctalTypeTemplate !!js/function >
        (literal) => {
            let offset = 0;

            if (
                literal.charAt(0) === '0' &&
                (literal.charAt(1) === '0' || literal.charAt(1) === 'o' || literal.charAt(1) === 'O')
            ) {
                offset = 2;
            } else if (literal.charAt(0) === '0') {
                offset = 1;
            }

            literal = `0o${literal.substr(offset, literal.length - 1)}`;

            return literal;
        }
    NumericTypeTemplate: &NumericTypeTemplate null
    ArrayTypeTemplate: &ArrayTypeTemplate !!js/function >
        (literal, depth) => {
            if (literal === '') {
                return '[]'
            }
            const indent = '\n' + '    '.repeat(depth);
            const closingIndent = '\n' + '    '.repeat(depth - 1);

            return `[${indent}${literal}${closingIndent}]`;
        }
    ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null
    NullTypeTemplate: &NullTypeTemplate !!js/function >
        () => {
            return 'None';
        }
    UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >
        () => {
            return 'None';
        }
    ObjectTypeTemplate: &ObjectTypeTemplate !!js/function >
        (literal, depth) => {
            if (literal === '') {
                return '{}';
            }
            return literal;
        }
    ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate !!js/function >
        (args, depth) => {
            const indent = '\n' + '    '.repeat(depth);
            const closingIndent = '\n' + '    '.repeat(depth - 1);
            const singleStringify = (str) => {
                let newStr = str;
                if (
                  (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                  (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                    newStr = str.substr(1, str.length - 2);
                }
                return `'${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}'`;
            }

            const pairs = args.map((arg) => {
                return `${indent}${singleStringify(arg[0])}: ${arg[1]}`;
            }).join(', ');

            return `{${pairs}${closingIndent}}`;
        }
    # BSON Object Method templates
    CodeCodeTemplate: &CodeCodeTemplate !!js/function >
        (lhs) => {
            return `str(${lhs})`;
        }
    CodeCodeArgsTemplate: &CodeCodeArgsTemplate null
    CodeScopeTemplate: &CodeScopeTemplate null
    CodeScopeArgsTemplate: &CodeScopeArgsTemplate null
    ObjectIdToStringTemplate: &ObjectIdToStringTemplate !!js/function >
        () => {
            return 'str';
        }
    ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} ==`;
        }
    ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate !!js/function >
        (lhs) => {
            return `${lhs}.generation_time`;
        }
    ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate !!js/function >
        () => {
            return '';
        }
    BinaryValueTemplate: &BinaryValueTemplate !!js/function >
        () => {
            return '';
        }
    BinaryValueArgsTemplate: &BinaryValueArgsTemplate !!js/function >
        (lhs) => {
            return `str(${lhs})`;
        }
    BinaryLengthTemplate: &BinaryLengthTemplate !!js/function >
        () => {
            return '';
        }
    BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate !!js/function >
        (lhs) => {
            return `len(${lhs})`;
        }
    BinaryToStringTemplate: &BinaryToStringTemplate !!js/function >
        () => {
            return '';
        }
    BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate !!js/function >
        (lhs) => {
            return `str(${lhs})`;
        }
    BinarySubtypeTemplate: &BinarySubtypeTemplate !!js/function >
        (lhs) => {
            return `${lhs}.subtype`;
        }
    BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate null
    DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >
        (lhs) => {
            return `${lhs}.database`;
        }
    DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >
        (lhs) => {
            return `${lhs}.collection`;
        }
    DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >
        (lhs) => {
            return `${lhs}.id`;
        }
    DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function
        () => {
            return '';
        }
    DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >
        () => {
            return '';
        }
    DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function
        () => {
            return '';
        }
    DBRefToStringTemplate: &DBRefToStringTemplate !!js/function >
        () => {
            return `str`;
        }
    DBRefToStringArgsTemplate: &DBRefToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    DoubleValueOfTemplate: &DoubleValueOfTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    DoubleValueOfArgsTemplate: &DoubleValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    Int32ValueOfTemplate: &Int32ValueOfTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    Int32ValueOfArgsTemplate: &Int32ValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    Int32ToStringTemplate: &Int32ToStringTemplate !!js/function >
        () => {
            return 'str';
        }
    Int32ToStringArgsTemplate: &Int32ToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    LongEqualsTemplate: &LongEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} ==`;
        }
    LongEqualsArgsTemplate: &LongEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongToIntTemplate: &LongToIntTemplate !!js/function >
        (lhs) => {
            return `int(${lhs})`;
        }
    LongToIntArgsTemplate: &LongToIntArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongToStringTemplate: &LongToStringTemplate !!js/function > # Also has emit method
        () => {
            return 'str';
        }
    LongToStringArgsTemplate: &LongToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    LongValueOfTemplate: &LongValueOfTemplate !!js/function >
        (lhs) => {
            return `long(${lhs})`;
        }
    LongValueOfArgsTemplate: &LongValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongToNumberTemplate: &LongToNumberTemplate !!js/function >
        (lhs) => {
            return `float(${lhs})`;
        }
    LongToNumberArgsTemplate: &LongToNumberArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongAddTemplate: &LongAddTemplate !!js/function >
        (lhs) => {
            return `${lhs} +`;
        }
    LongAddArgsTemplate: &LongAddArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongSubtractTemplate: &LongSubtractTemplate !!js/function >
        (arg) => {
            return `${arg} -`;
        }
    LongSubtractArgsTemplate: &LongSubtractArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongMultiplyTemplate: &LongMultiplyTemplate !!js/function >
        (arg) => {
            return `${arg} *`;
        }
    LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongDivTemplate: &LongDivTemplate !!js/function >
        (lhs) => {
            return `${lhs} /`;
        }
    LongDivArgsTemplate: &LongDivArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongModuloTemplate: &LongModuloTemplate !!js/function >
        (lhs) => {
            return `${lhs} %`;
        }
    LongModuloArgsTemplate: &LongModuloArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongAndTemplate: &LongAndTemplate !!js/function >
        (lhs) => {
            return `${lhs} &`;
        }
    LongAndArgsTemplate: &LongAndArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongOrTemplate: &LongOrTemplate !!js/function >
        (lhs) => {
            return `${lhs} |`;
        }
    LongOrArgsTemplate: &LongOrArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongXorTemplate: &LongXorTemplate !!js/function >
        (lhs) => {
            return `${lhs} ^`;
        }
    LongXorArgsTemplate: &LongXorArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongShiftLeftTemplate: &LongShiftLeftTemplate !!js/function >
        (lhs) => {
            return `${lhs} <<`;
        }
    LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongShiftRightTemplate: &LongShiftRightTemplate !!js/function >
        (lhs) => {
            return `${lhs} >>`;
        }
    LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongCompareTemplate: &LongCompareTemplate !!js/function >
        (lhs) => {
            return `${lhs} -`;
        }
    LongCompareArgsTemplate: &LongCompareArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongIsOddTemplate: &LongIsOddTemplate !!js/function >
        (lhs) => {
            return `(${lhs} % 2) == 1`;
        }
    LongIsOddArgsTemplate: &LongIsOddArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongIsZeroTemplate: &LongIsZeroTemplate !!js/function >
        (lhs) => {
            return `${lhs} == 0`;
        }
    LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongIsNegativeTemplate: &LongIsNegativeTemplate !!js/function >
        (lhs) => {
            return `${lhs} < 0`;
        }
    LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate !!js/function >
        () => {
            return '';
        }
    LongNegateTemplate: &LongNegateTemplate !!js/function >
        () => {
            return '-';
        }
    LongNegateArgsTemplate: &LongNegateArgsTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    LongNotTemplate: &LongNotTemplate !!js/function >
        () => {
            return '~';
        }
    LongNotArgsTemplate: &LongNotArgsTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    LongNotEqualsTemplate: &LongNotEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} !=`;
        }
    LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongGreaterThanTemplate: &LongGreaterThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} >`;
        }
    LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} >=`;
        }
    LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongLessThanTemplate: &LongLessThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} <`;
        }
    LongLessThanArgsTemplate: &LongLessThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} <=`;
        }
    LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >
        (lhs) => {
            return `float(${lhs})`;
        }
    LongTopTemplate: &LongTopTemplate !!js/function >
        (lhs) => {
            return `${lhs} >> 32`;
        }
    LongBottomTemplate: &LongBottomTemplate !!js/function >
        (lhs) => {
            return `${lhs} & 0x0000ffff`;
        }
    TimestampToStringTemplate: &TimestampToStringTemplate !!js/function >
        () => {
            return 'str';
        }
    TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    TimestampEqualsTemplate: &TimestampEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} ==`;
        }
    TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.time`;
        }
    TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate !!js/function >
        () => {
            return '';
        }
    TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >
        (lhs) => {
            return `${lhs}.inc`;
        }
    TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate !!js/function >
        () => {
            return '';
        }
    TimestampTTemplate: &TimestampTTemplate !!js/function >
        (lhs) => {
            return `${lhs}.time`;
        }
    TimestampITemplate: &TimestampITemplate !!js/function >
        (lhs) => {
            return `${lhs}.inc`;
        }
    TimestampCompareTemplate: &TimestampCompareTemplate !!js/function >
        (lhs) => {
            return `(${lhs}.as_datetime() - `;
        }
    TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate !!js/function >
        (lhs, arg) => {
            return `${arg}.as_datetime()).total_seconds()`;
        }
    TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate !!js/function >
        (lhs) => {
            return `${lhs} !=`;
        }
    TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} >`;
        }
    TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} >=`;
        }
    TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    TimestampLessThanTemplate: &TimestampLessThanTemplate !!js/function >
        (lhs) => {
            return `${lhs} <`;
        }
    TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate !!js/function >
        (lhs) => {
            return `${lhs} <=`;
        }
    TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate !!js/function >
        (lhs, arg) => {
            return ` ${arg}`;
        }
    SymbolValueOfTemplate: &SymbolValueOfTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate !!js/function >
        () => {
            return '';
        }
    SymbolInspectTemplate: &SymbolInspectTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate !!js/function >
        () => {
            return '';
        }
    SymbolToStringTemplate: &SymbolToStringTemplate !!js/function >
        (lhs) => {
            return lhs;
        }
    SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate !!js/function >
        () => {
            return '';
        }
    # Symbol Templates
    CodeSymbolTemplate: &CodeSymbolTemplate !!js/function > # Also has process method
        () => {
            return 'Code';
        }
    CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate !!js/function > # Also has process method
        (lhs, code, scope) => {
          // Single quote stringify
          const scopestr = scope === undefined ? '' : `, ${scope}`;
          let newStr = code === undefined ? '' : code;
          const str = newStr;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          code = `'${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}'`;
          return `(${code}${scopestr})`;
        }
    ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null
    ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate !!js/function >
        (lhs, str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `('${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}')`;
        }
    BinarySymbolTemplate: &BinarySymbolTemplate null
    BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate !!js/function >
        (lhs, bytes, type) => {
            const str = bytes;
            let newStr = str;
            if (
              (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
              (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                newStr = str.substr(1, str.length - 2);
            }
            bytes = `'${newStr.replace(/\\([\s\S])|(')/g, '\\$1$2')}'`;

            if (type === null) {
                return `(b${bytes})`;
            }
            return `(b${bytes}, ${type})`;
        }
    BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate !!js/function >
        () => {
            return 'binary.BINARY_SUBTYPE';
        }
    BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate !!js/function >
        () => {
            return 'binary.FUNCTION_SUBTYPE';
        }
    BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate !!js/function >
        () => {
            return 'binary.BINARY_SUBTYPE';
        }
    BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate !!js/function >
        () => {
            return 'binary.OLD_UUID_SUBTYPE';
        }
    BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate !!js/function >
        () => {
            return 'binary.UUID_SUBTYPE';
        }
    BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template !!js/function >
        () => {
            return 'binary.MD5_SUBTYPE';
        }
    BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate !!js/function >
        () => {
            return 'binary.USER_DEFINED_SUBTYPE';
        }
    DBRefSymbolTemplate: &DBRefSymbolTemplate null
    DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null
    DoubleSymbolTemplate: &DoubleSymbolTemplate !!js/function >
        () => {
            return 'float';
        }
    DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null
    Int32SymbolTemplate: &Int32SymbolTemplate !!js/function >
        () => {
            return 'int';
        }
    Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            arg = arg === undefined ? 0 : arg;
            const str = arg.toString();
            let newStr = str;
            if (
                (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                newStr = str.substr(1, str.length - 2);
                return `('${newStr}')`;
            } else {
                return `(${newStr})`;
            }
        }
    LongSymbolTemplate: &LongSymbolTemplate !!js/function >
        () => {
            return 'Int64';
        }
    LongSymbolArgsTemplate: &LongSymbolArgsTemplate null
    LongSymbolMaxTemplate: &LongSymbolMaxTemplate !!js/function >
        () => {
            return 'sys.maxsize';
        }
    LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null
    LongSymbolMinTemplate: &LongSymbolMinTemplate !!js/function >
        () => {
            return '-sys.maxsize -1';
        }
    LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null
    LongSymbolZeroTemplate: &LongSymbolZeroTemplate !!js/function >
        () => {
            return 'Int64(0)';
        }
    LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null
    LongSymbolOneTemplate: &LongSymbolOneTemplate !!js/function >
        () => {
            return 'Int64(1)';
        }
    LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null
    LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate !!js/function >
        () => {
            return 'Int64(-1)';
        }
    LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null
    LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate !!js/function > # Also has process method
        () => {
            return 'Int64';
        }
    LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null
    LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate !!js/function >
        () => {
            return 'Int64';
        }
    LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null
    LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate !!js/function >
        () => {
            return 'Int64';
        }
    LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null
    LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate !!js/function >
        (lhs, arg) => {
            return 'Int64';
        }
    LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(int(${arg}))`;
        }
    MinKeySymbolTemplate: &MinKeySymbolTemplate null
    MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null
    MaxKeySymbolTemplate: &MaxKeySymbolTemplate null
    MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null
    TimestampSymbolTemplate: &TimestampSymbolTemplate !!js/function >
        () => {
            return 'Timestamp';
        }
    TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate !!js/function >
        (lhs, arg1, arg2) => {
            return `(${arg1 === undefined ? 0 : arg1}, ${arg2 === undefined ? 0 : arg2})`;
        }
    SymbolSymbolTemplate: &SymbolSymbolTemplate !!js/function >
        () => {
            return '';
        }
    SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            return arg;
        }
    BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate !!js/function >
        () => {
            return 'Regex';
        }
    BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate !!js/function >
        (lhs, pattern, flags) => {
            return `(${pattern}${flags ? ', ' + flags : ''})`;
        }
    Decimal128SymbolTemplate: &Decimal128SymbolTemplate !!js/function >
        () => {
            return 'Decimal128';
        }
    Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate !!js/function >
        (lhs, str) => {
          let newStr = str;
          if (
            (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
            (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
            newStr = str.substr(1, str.length - 2);
          }
          return `('${newStr.replace(/\\([\s\S])|(")/g, '\\$1$2')}')`;
        }
    Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate !!js/function >
        () => {
            return 'Decimal128';
        }
    Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg})`;
        }
    Decimal128ToStringTemplate: &Decimal128ToStringTemplate !!js/function >
        () => {
            return 'str';
        }
    Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate !!js/function >
        (lhs) => {
            return `(${lhs})`;
        }
    # BSON Util Templates
    ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate !!js/function >
        () => {
            return 'ObjectId';
        }
    ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg})`;
        }
    ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function > # Also has emit method
        () => {
            return `ObjectId.from_datetime`;
        }
    ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate !!js/function >
        (lhs, arg) => {
            return `(${arg})`;
        }
    ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate !!js/function >
        (lhs) => {
            return `${lhs}.is_valid`;
        }
    ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null
    # JS Symbol Templates
    ObjectSymbolTemplate: &ObjectSymbolTemplate null
    ObjectSymbolArgsTemplate: &ObjectSymbolArgsTemplate null
    ObjectSymbolCreateTemplate: &ObjectSymbolCreateTemplate !!js/function >
        () => {
            return '';
        }
    ObjectSymbolCreateArgsTemplate: &ObjectSymbolCreateArgsTemplate !!js/function >
        (lhs, arg) => {
            return arg;
        }
    NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >
        () => {
            return '';
        }
    NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate !!js/function >
        (lhs, arg) => {
            arg = arg === undefined ? 0 : arg;
            const str = arg.toString();
            let newStr = str;
            if (
                (str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') ||
                (str.charAt(0) === '"' && str.charAt(str.length - 1) === '"')) {
                newStr = str.substr(1, str.length - 2);
                return `float('${newStr}')`;
            } else {
                return `${newStr}`;
            }
        }
    DateSymbolTemplate: &DateSymbolTemplate !!js/function > # Also has emit method
        () => {
            return 'datetime.datetime';
        }
    DateSymbolArgsTemplate: &DateSymbolArgsTemplate null
    DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >
        () => {
            return 'datetime.datetime.utcnow';
        }
    DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null
    RegExpSymbolTemplate: &RegExpSymbolTemplate !!js/function > # Also has process method
        () => {
            return 're';
        }
    RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null
    ImportTemplate: &ImportTemplate !!js/function >
        (args) => {
            const bson = [];
            const other = [];
            Object.keys(args).map(
                (m) => {
                    if (m > 99 && m < 200) {
                        bson.push(args[m]);
                    } else {
                        other.push(args[m]);
                    }
                }
            );
            if (bson.length) {
                other.push(`from bson import ${bson.join(', ')}`);
            }
            return other.join('\n');
        }
    0ImportTemplate: &0ImportTemplate null
    1ImportTemplate: &1ImportTemplate null
    2ImportTemplate: &2ImportTemplate null
    3ImportTemplate: &3ImportTemplate null
    4ImportTemplate: &4ImportTemplate null
    5ImportTemplate: &5ImportTemplate null
    6ImportTemplate: &6ImportTemplate null
    7ImportTemplate: &7ImportTemplate null
    8ImportTemplate: &8ImportTemplate null
    9ImportTemplate: &9ImportTemplate null
    10ImportTemplate: &10ImportTemplate null
    11ImportTemplate: &11ImportTemplate null
    12ImportTemplate: &12ImportTemplate null
    100ImportTemplate: &100ImportTemplate !!js/function >
        () => {
            return 'Code';
        }
    101ImportTemplate: &101ImportTemplate !!js/function >
        () => {
            return 'ObjectId';
        }
    102ImportTemplate: &102ImportTemplate !!js/function >
        () => {
            return 'Binary';
        }
    103ImportTemplate: &103ImportTemplate !!js/function >
        () => {
            return 'DBRef';
        }
    104ImportTemplate: &104ImportTemplate null
    105ImportTemplate: &105ImportTemplate null
    106ImportTemplate: &106ImportTemplate !!js/function >
        () => {
            return 'Int64';
        }
    107ImportTemplate: &107ImportTemplate !!js/function >
        () => {
            return 'MinKey';
        }
    108ImportTemplate: &108ImportTemplate !!js/function >
        () => {
            return 'MaxKey';
        }
    109ImportTemplate: &109ImportTemplate null
    110ImportTemplate: &110ImportTemplate !!js/function >
        () => {
            return 'Timestamp';
        }
    111ImportTemplate: &111ImportTemplate null
    112ImportTemplate: &112ImportTemplate !!js/function >
        () => {
            return 'Decimal128';
        }
    113ImportTemplate: &113ImportTemplate null
    114ImportTemplate: &114ImportTemplate null
    200ImportTemplate: &200ImportTemplate !!js/function >
        () => {
            return 'import datetime';
        }
    201ImportTemplate: &201ImportTemplate null
    300ImportTemplate: &300ImportTemplate null
    301ImportTemplate: &301ImportTemplate null
    302ImportTemplate: &302ImportTemplate null
    303ImportTemplate: &303ImportTemplate null
    304ImportTemplate: &304ImportTemplate null
    305ImportTemplate: &305ImportTemplate null
    306ImportTemplate: &306ImportTemplate null
