declare namespace JSX {

	type LibraryManagedAttributes<C, P> = C extends { defaultProps: infer D } ? Pick<P, Exclude<keyof P, keyof D>> & Partial<Pick<P, Extract<keyof P, keyof D>>> : P;

	interface Element extends preact.VNode<any> {
	}

	interface ElementClass extends preact.Component<any, any> {
	}

	interface ElementAttributesProperty {
		props: any;
	}

	interface ElementChildrenAttribute {
		children: any;
	}

	interface SVGAttributes extends HTMLAttributes {
		accentHeight?: number | string;
		accumulate?: "none" | "sum";
		additive?: "replace" | "sum";
		alignmentBaseline?: "auto" | "baseline" | "before-edge" | "text-before-edge" | "middle" | "central" | "after-edge" | "text-after-edge" | "ideographic" | "alphabetic" | "hanging" | "mathematical" | "inherit";
		allowReorder?: "no" | "yes";
		alphabetic?: number | string;
		amplitude?: number | string;
		arabicForm?: "initial" | "medial" | "terminal" | "isolated";
		ascent?: number | string;
		attributeName?: string;
		attributeType?: string;
		autoReverse?: number | string;
		azimuth?: number | string;
		baseFrequency?: number | string;
		baselineShift?: number | string;
		baseProfile?: number | string;
		bbox?: number | string;
		begin?: number | string;
		bias?: number | string;
		by?: number | string;
		calcMode?: number | string;
		capHeight?: number | string;
		clip?: number | string;
		clipPath?: string;
		clipPathUnits?: number | string;
		clipRule?: number | string;
		colorInterpolation?: number | string;
		colorInterpolationFilters?: "auto" | "sRGB" | "linearRGB" | "inherit";
		colorProfile?: number | string;
		colorRendering?: number | string;
		contentScriptType?: number | string;
		contentStyleType?: number | string;
		cursor?: number | string;
		cx?: number | string;
		cy?: number | string;
		d?: string;
		decelerate?: number | string;
		descent?: number | string;
		diffuseConstant?: number | string;
		direction?: number | string;
		display?: number | string;
		divisor?: number | string;
		dominantBaseline?: number | string;
		dur?: number | string;
		dx?: number | string;
		dy?: number | string;
		edgeMode?: number | string;
		elevation?: number | string;
		enableBackground?: number | string;
		end?: number | string;
		exponent?: number | string;
		externalResourcesRequired?: number | string;
		fill?: string;
		fillOpacity?: number | string;
		fillRule?: "nonzero" | "evenodd" | "inherit";
		filter?: string;
		filterRes?: number | string;
		filterUnits?: number | string;
		floodColor?: number | string;
		floodOpacity?: number | string;
		focusable?: number | string;
		fontFamily?: string;
		fontSize?: number | string;
		fontSizeAdjust?: number | string;
		fontStretch?: number | string;
		fontStyle?: number | string;
		fontVariant?: number | string;
		fontWeight?: number | string;
		format?: number | string;
		from?: number | string;
		fx?: number | string;
		fy?: number | string;
		g1?: number | string;
		g2?: number | string;
		glyphName?: number | string;
		glyphOrientationHorizontal?: number | string;
		glyphOrientationVertical?: number | string;
		glyphRef?: number | string;
		gradientTransform?: string;
		gradientUnits?: string;
		hanging?: number | string;
		horizAdvX?: number | string;
		horizOriginX?: number | string;
		ideographic?: number | string;
		imageRendering?: number | string;
		in2?: number | string;
		in?: string;
		intercept?: number | string;
		k1?: number | string;
		k2?: number | string;
		k3?: number | string;
		k4?: number | string;
		k?: number | string;
		kernelMatrix?: number | string;
		kernelUnitLength?: number | string;
		kerning?: number | string;
		keyPoints?: number | string;
		keySplines?: number | string;
		keyTimes?: number | string;
		lengthAdjust?: number | string;
		letterSpacing?: number | string;
		lightingColor?: number | string;
		limitingConeAngle?: number | string;
		local?: number | string;
		markerEnd?: string;
		markerHeight?: number | string;
		markerMid?: string;
		markerStart?: string;
		markerUnits?: number | string;
		markerWidth?: number | string;
		mask?: string;
		maskContentUnits?: number | string;
		maskUnits?: number | string;
		mathematical?: number | string;
		mode?: number | string;
		numOctaves?: number | string;
		offset?: number | string;
		opacity?: number | string;
		operator?: number | string;
		order?: number | string;
		orient?: number | string;
		orientation?: number | string;
		origin?: number | string;
		overflow?: number | string;
		overlinePosition?: number | string;
		overlineThickness?: number | string;
		paintOrder?: number | string;
		panose1?: number | string;
		pathLength?: number | string;
		patternContentUnits?: string;
		patternTransform?: number | string;
		patternUnits?: string;
		pointerEvents?: number | string;
		points?: string;
		pointsAtX?: number | string;
		pointsAtY?: number | string;
		pointsAtZ?: number | string;
		preserveAlpha?: number | string;
		preserveAspectRatio?: string;
		primitiveUnits?: number | string;
		r?: number | string;
		radius?: number | string;
		refX?: number | string;
		refY?: number | string;
		renderingIntent?: number | string;
		repeatCount?: number | string;
		repeatDur?: number | string;
		requiredExtensions?: number | string;
		requiredFeatures?: number | string;
		restart?: number | string;
		result?: string;
		rotate?: number | string;
		rx?: number | string;
		ry?: number | string;
		scale?: number | string;
		seed?: number | string;
		shapeRendering?: number | string;
		slope?: number | string;
		spacing?: number | string;
		specularConstant?: number | string;
		specularExponent?: number | string;
		speed?: number | string;
		spreadMethod?: string;
		startOffset?: number | string;
		stdDeviation?: number | string;
		stemh?: number | string;
		stemv?: number | string;
		stitchTiles?: number | string;
		stopColor?: string;
		stopOpacity?: number | string;
		strikethroughPosition?: number | string;
		strikethroughThickness?: number | string;
		string?: number | string;
		stroke?: string;
		strokeDasharray?: string | number;
		strokeDashoffset?: string | number;
		strokeLinecap?: "butt" | "round" | "square" | "inherit";
		strokeLinejoin?: "miter" | "round" | "bevel" | "inherit";
		strokeMiterlimit?: string;
		strokeOpacity?: number | string;
		strokeWidth?: number | string;
		surfaceScale?: number | string;
		systemLanguage?: number | string;
		tableValues?: number | string;
		targetX?: number | string;
		targetY?: number | string;
		textAnchor?: string;
		textDecoration?: number | string;
		textLength?: number | string;
		textRendering?: number | string;
		to?: number | string;
		transform?: string;
		u1?: number | string;
		u2?: number | string;
		underlinePosition?: number | string;
		underlineThickness?: number | string;
		unicode?: number | string;
		unicodeBidi?: number | string;
		unicodeRange?: number | string;
		unitsPerEm?: number | string;
		vAlphabetic?: number | string;
		values?: string;
		vectorEffect?: number | string;
		version?: string;
		vertAdvY?: number | string;
		vertOriginX?: number | string;
		vertOriginY?: number | string;
		vHanging?: number | string;
		vIdeographic?: number | string;
		viewBox?: string;
		viewTarget?: number | string;
		visibility?: number | string;
		vMathematical?: number | string;
		widths?: number | string;
		wordSpacing?: number | string;
		writingMode?: number | string;
		x1?: number | string;
		x2?: number | string;
		x?: number | string;
		xChannelSelector?: string;
		xHeight?: number | string;
		xlinkActuate?: string;
		xlinkArcrole?: string;
		xlinkHref?: string;
		xlinkRole?: string;
		xlinkShow?: string;
		xlinkTitle?: string;
		xlinkType?: string;
		xmlBase?: string;
		xmlLang?: string;
		xmlns?: string;
		xmlnsXlink?: string;
		xmlSpace?: string;
		y1?: number | string;
		y2?: number | string;
		y?: number | string;
		yChannelSelector?: string;
		z?: number | string;
		zoomAndPan?: string;
	}

	interface PathAttributes {
		d: string;
	}

	interface EventHandler<E extends Event> {
		(event: E): void;
	}

	type ClipboardEventHandler = EventHandler<ClipboardEvent>;
	type CompositionEventHandler = EventHandler<CompositionEvent>;
	type DragEventHandler = EventHandler<DragEvent>;
	type FocusEventHandler = EventHandler<FocusEvent>;
	type KeyboardEventHandler = EventHandler<KeyboardEvent>;
	type MouseEventHandler = EventHandler<MouseEvent>;
	type TouchEventHandler = EventHandler<TouchEvent>;
	type UIEventHandler = EventHandler<UIEvent>;
	type WheelEventHandler = EventHandler<WheelEvent>;
	type AnimationEventHandler = EventHandler<AnimationEvent>;
	type TransitionEventHandler = EventHandler<TransitionEvent>;
	type GenericEventHandler = EventHandler<Event>;
	type PointerEventHandler = EventHandler<PointerEvent>;

	interface DOMAttributes extends preact.PreactDOMAttributes {
		// Image Events
		onLoad?: GenericEventHandler;
		onLoadCapture?: GenericEventHandler;

		// Clipboard Events
		onCopy?: ClipboardEventHandler;
		onCopyCapture?: ClipboardEventHandler;
		onCut?: ClipboardEventHandler;
		onCutCapture?: ClipboardEventHandler;
		onPaste?: ClipboardEventHandler;
		onPasteCapture?: ClipboardEventHandler;

		// Composition Events
		onCompositionEnd?: CompositionEventHandler;
		onCompositionEndCapture?: CompositionEventHandler;
		onCompositionStart?: CompositionEventHandler;
		onCompositionStartCapture?: CompositionEventHandler;
		onCompositionUpdate?: CompositionEventHandler;
		onCompositionUpdateCapture?: CompositionEventHandler;

		// Focus Events
		onFocus?: FocusEventHandler;
		onFocusCapture?: FocusEventHandler;
		onBlur?: FocusEventHandler;
		onBlurCapture?: FocusEventHandler;

		// Form Events
		onChange?: GenericEventHandler;
		onChangeCapture?: GenericEventHandler;
		onInput?: GenericEventHandler;
		onInputCapture?: GenericEventHandler;
		onSearch?: GenericEventHandler;
		onSearchCapture?: GenericEventHandler;
		onSubmit?: GenericEventHandler;
		onSubmitCapture?: GenericEventHandler;

		// Keyboard Events
		onKeyDown?: KeyboardEventHandler;
		onKeyDownCapture?: KeyboardEventHandler;
		onKeyPress?: KeyboardEventHandler;
		onKeyPressCapture?: KeyboardEventHandler;
		onKeyUp?: KeyboardEventHandler;
		onKeyUpCapture?: KeyboardEventHandler;

		// Media Events
		onAbort?: GenericEventHandler;
		onAbortCapture?: GenericEventHandler;
		onCanPlay?: GenericEventHandler;
		onCanPlayCapture?: GenericEventHandler;
		onCanPlayThrough?: GenericEventHandler;
		onCanPlayThroughCapture?: GenericEventHandler;
		onDurationChange?: GenericEventHandler;
		onDurationChangeCapture?: GenericEventHandler;
		onEmptied?: GenericEventHandler;
		onEmptiedCapture?: GenericEventHandler;
		onEncrypted?: GenericEventHandler;
		onEncryptedCapture?: GenericEventHandler;
		onEnded?: GenericEventHandler;
		onEndedCapture?: GenericEventHandler;
		onLoadedData?: GenericEventHandler;
		onLoadedDataCapture?: GenericEventHandler;
		onLoadedMetadata?: GenericEventHandler;
		onLoadedMetadataCapture?: GenericEventHandler;
		onLoadStart?: GenericEventHandler;
		onLoadStartCapture?: GenericEventHandler;
		onPause?: GenericEventHandler;
		onPauseCapture?: GenericEventHandler;
		onPlay?: GenericEventHandler;
		onPlayCapture?: GenericEventHandler;
		onPlaying?: GenericEventHandler;
		onPlayingCapture?: GenericEventHandler;
		onProgress?: GenericEventHandler;
		onProgressCapture?: GenericEventHandler;
		onRateChange?: GenericEventHandler;
		onRateChangeCapture?: GenericEventHandler;
		onSeeked?: GenericEventHandler;
		onSeekedCapture?: GenericEventHandler;
		onSeeking?: GenericEventHandler;
		onSeekingCapture?: GenericEventHandler;
		onStalled?: GenericEventHandler;
		onStalledCapture?: GenericEventHandler;
		onSuspend?: GenericEventHandler;
		onSuspendCapture?: GenericEventHandler;
		onTimeUpdate?: GenericEventHandler;
		onTimeUpdateCapture?: GenericEventHandler;
		onVolumeChange?: GenericEventHandler;
		onVolumeChangeCapture?: GenericEventHandler;
		onWaiting?: GenericEventHandler;
		onWaitingCapture?: GenericEventHandler;

		// MouseEvents
		onClick?: MouseEventHandler;
		onClickCapture?: MouseEventHandler;
		onContextMenu?: MouseEventHandler;
		onContextMenuCapture?: MouseEventHandler;
		onDblClick?: MouseEventHandler;
		onDblClickCapture?: MouseEventHandler;
		onDrag?: DragEventHandler;
		onDragCapture?: DragEventHandler;
		onDragEnd?: DragEventHandler;
		onDragEndCapture?: DragEventHandler;
		onDragEnter?: DragEventHandler;
		onDragEnterCapture?: DragEventHandler;
		onDragExit?: DragEventHandler;
		onDragExitCapture?: DragEventHandler;
		onDragLeave?: DragEventHandler;
		onDragLeaveCapture?: DragEventHandler;
		onDragOver?: DragEventHandler;
		onDragOverCapture?: DragEventHandler;
		onDragStart?: DragEventHandler;
		onDragStartCapture?: DragEventHandler;
		onDrop?: DragEventHandler;
		onDropCapture?: DragEventHandler;
		onMouseDown?: MouseEventHandler;
		onMouseDownCapture?: MouseEventHandler;
		onMouseEnter?: MouseEventHandler;
		onMouseEnterCapture?: MouseEventHandler;
		onMouseLeave?: MouseEventHandler;
		onMouseLeaveCapture?: MouseEventHandler;
		onMouseMove?: MouseEventHandler;
		onMouseMoveCapture?: MouseEventHandler;
		onMouseOut?: MouseEventHandler;
		onMouseOutCapture?: MouseEventHandler;
		onMouseOver?: MouseEventHandler;
		onMouseOverCapture?: MouseEventHandler;
		onMouseUp?: MouseEventHandler;
		onMouseUpCapture?: MouseEventHandler;

		// Selection Events
		onSelect?: GenericEventHandler;
		onSelectCapture?: GenericEventHandler;

		// Touch Events
		onTouchCancel?: TouchEventHandler;
		onTouchCancelCapture?: TouchEventHandler;
		onTouchEnd?: TouchEventHandler;
		onTouchEndCapture?: TouchEventHandler;
		onTouchMove?: TouchEventHandler;
		onTouchMoveCapture?: TouchEventHandler;
		onTouchStart?: TouchEventHandler;
		onTouchStartCapture?: TouchEventHandler;

		// Pointer Events
		onPointerOver?: PointerEventHandler;
		onPointerOverCapture?: PointerEventHandler;
		onPointerEnter?: PointerEventHandler;
		onPointerEnterCapture?: PointerEventHandler;
		onPointerDown?: PointerEventHandler;
		onPointerDownCapture?: PointerEventHandler;
		onPointerMove?: PointerEventHandler;
		onPointerMoveCapture?: PointerEventHandler;
		onPointerUp?: PointerEventHandler;
		onPointerUpCapture?: PointerEventHandler;
		onPointerCancel?: PointerEventHandler;
		onPointerCancelCapture?: PointerEventHandler;
		onPointerOut?: PointerEventHandler;
		onPointerOutCapture?: PointerEventHandler;
		onPointerLeave?: PointerEventHandler;
		onPointerLeaveCapture?: PointerEventHandler;
		onGotPointerCapture?: PointerEventHandler;
		onGotPointerCaptureCapture?: PointerEventHandler;
		onLostPointerCapture?: PointerEventHandler;
		onLostPointerCaptureCapture?: PointerEventHandler;

		// UI Events
		onScroll?: UIEventHandler;
		onScrollCapture?: UIEventHandler;

		// Wheel Events
		onWheel?: WheelEventHandler;
		onWheelCapture?: WheelEventHandler;

		// Animation Events
		onAnimationStart?: AnimationEventHandler;
		onAnimationStartCapture?: AnimationEventHandler;
		onAnimationEnd?: AnimationEventHandler;
		onAnimationEndCapture?: AnimationEventHandler;
		onAnimationIteration?: AnimationEventHandler;
		onAnimationIterationCapture?: AnimationEventHandler;

		// Transition Events
		onTransitionEnd?: TransitionEventHandler;
		onTransitionEndCapture?: TransitionEventHandler;
	}

	interface HTMLAttributes extends preact.ClassAttributes<any>, DOMAttributes {
		// Standard HTML Attributes
		accept?: string;
		acceptCharset?: string;
		accessKey?: string;
		action?: string;
		allowFullScreen?: boolean;
		allowTransparency?: boolean;
		alt?: string;
		async?: boolean;
		autocomplete?: string;
		autofocus?: boolean;
		autoPlay?: boolean;
		capture?: boolean;
		cellPadding?: number | string;
		cellSpacing?: number | string;
		charSet?: string;
		challenge?: string;
		checked?: boolean;
		class?: string;
		className?: string;
		cols?: number;
		colSpan?: number;
		content?: string;
		contentEditable?: boolean;
		contextMenu?: string;
		controls?: boolean;
		controlsList?: string;
		coords?: string;
		crossOrigin?: string;
		data?: string;
		dateTime?: string;
		default?: boolean;
		defer?: boolean;
		dir?: string;
		disabled?: boolean;
		download?: any;
		draggable?: boolean;
		encType?: string;
		form?: string;
		formAction?: string;
		formEncType?: string;
		formMethod?: string;
		formNoValidate?: boolean;
		formTarget?: string;
		frameBorder?: number | string;
		headers?: string;
		height?: number | string;
		hidden?: boolean;
		high?: number;
		href?: string;
		hrefLang?: string;
		for?: string;
		httpEquiv?: string;
		icon?: string;
		id?: string;
		inputMode?: string;
		integrity?: string;
		is?: string;
		keyParams?: string;
		keyType?: string;
		kind?: string;
		label?: string;
		lang?: string;
		list?: string;
		loop?: boolean;
		low?: number;
		manifest?: string;
		marginHeight?: number;
		marginWidth?: number;
		max?: number | string;
		maxLength?: number;
		media?: string;
		mediaGroup?: string;
		method?: string;
		min?: number | string;
		minLength?: number;
		multiple?: boolean;
		muted?: boolean;
		name?: string;
		noValidate?: boolean;
		open?: boolean;
		optimum?: number;
		pattern?: string;
		placeholder?: string;
		playsInline?: boolean;
		poster?: string;
		preload?: string;
		radioGroup?: string;
		readOnly?: boolean;
		rel?: string;
		required?: boolean;
		role?: string;
		rows?: number;
		rowSpan?: number;
		sandbox?: string;
		scope?: string;
		scoped?: boolean;
		scrolling?: string;
		seamless?: boolean;
		selected?: boolean;
		shape?: string;
		size?: number;
		sizes?: string;
		slot?: string;
		span?: number;
		spellcheck?: boolean;
		src?: string;
		srcset?: string;
		srcDoc?: string;
		srcLang?: string;
		srcSet?: string;
		start?: number;
		step?: number | string;
		style?: any;
		summary?: string;
		tabIndex?: number;
		target?: string;
		title?: string;
		type?: string;
		useMap?: string;
		value?: string | string[] | number;
		width?: number | string;
		wmode?: string;
		wrap?: string;

		// RDFa Attributes
		about?: string;
		datatype?: string;
		inlist?: any;
		prefix?: string;
		property?: string;
		resource?: string;
		typeof?: string;
		vocab?: string;
	}

	interface IntrinsicElements {
		// HTML
		a: HTMLAttributes;
		abbr: HTMLAttributes;
		address: HTMLAttributes;
		area: HTMLAttributes;
		article: HTMLAttributes;
		aside: HTMLAttributes;
		audio: HTMLAttributes;
		b: HTMLAttributes;
		base: HTMLAttributes;
		bdi: HTMLAttributes;
		bdo: HTMLAttributes;
		big: HTMLAttributes;
		blockquote: HTMLAttributes;
		body: HTMLAttributes;
		br: HTMLAttributes;
		button: HTMLAttributes;
		canvas: HTMLAttributes;
		caption: HTMLAttributes;
		cite: HTMLAttributes;
		code: HTMLAttributes;
		col: HTMLAttributes;
		colgroup: HTMLAttributes;
		data: HTMLAttributes;
		datalist: HTMLAttributes;
		dd: HTMLAttributes;
		del: HTMLAttributes;
		details: HTMLAttributes;
		dfn: HTMLAttributes;
		dialog: HTMLAttributes;
		div: HTMLAttributes;
		dl: HTMLAttributes;
		dt: HTMLAttributes;
		em: HTMLAttributes;
		embed: HTMLAttributes;
		fieldset: HTMLAttributes;
		figcaption: HTMLAttributes;
		figure: HTMLAttributes;
		footer: HTMLAttributes;
		form: HTMLAttributes;
		h1: HTMLAttributes;
		h2: HTMLAttributes;
		h3: HTMLAttributes;
		h4: HTMLAttributes;
		h5: HTMLAttributes;
		h6: HTMLAttributes;
		head: HTMLAttributes;
		header: HTMLAttributes;
		hr: HTMLAttributes;
		html: HTMLAttributes;
		i: HTMLAttributes;
		iframe: HTMLAttributes;
		img: HTMLAttributes;
		input: HTMLAttributes;
		ins: HTMLAttributes;
		kbd: HTMLAttributes;
		keygen: HTMLAttributes;
		label: HTMLAttributes;
		legend: HTMLAttributes;
		li: HTMLAttributes;
		link: HTMLAttributes;
		main: HTMLAttributes;
		map: HTMLAttributes;
		mark: HTMLAttributes;
		menu: HTMLAttributes;
		menuitem: HTMLAttributes;
		meta: HTMLAttributes;
		meter: HTMLAttributes;
		nav: HTMLAttributes;
		noscript: HTMLAttributes;
		object: HTMLAttributes;
		ol: HTMLAttributes;
		optgroup: HTMLAttributes;
		option: HTMLAttributes;
		output: HTMLAttributes;
		p: HTMLAttributes;
		param: HTMLAttributes;
		picture: HTMLAttributes;
		pre: HTMLAttributes;
		progress: HTMLAttributes;
		q: HTMLAttributes;
		rp: HTMLAttributes;
		rt: HTMLAttributes;
		ruby: HTMLAttributes;
		s: HTMLAttributes;
		samp: HTMLAttributes;
		script: HTMLAttributes;
		section: HTMLAttributes;
		select: HTMLAttributes;
		slot: HTMLAttributes;
		small: HTMLAttributes;
		source: HTMLAttributes;
		span: HTMLAttributes;
		strong: HTMLAttributes;
		style: HTMLAttributes;
		sub: HTMLAttributes;
		summary: HTMLAttributes;
		sup: HTMLAttributes;
		table: HTMLAttributes;
		tbody: HTMLAttributes;
		td: HTMLAttributes;
		textarea: HTMLAttributes;
		tfoot: HTMLAttributes;
		th: HTMLAttributes;
		thead: HTMLAttributes;
		time: HTMLAttributes;
		title: HTMLAttributes;
		tr: HTMLAttributes;
		track: HTMLAttributes;
		u: HTMLAttributes;
		ul: HTMLAttributes;
		"var": HTMLAttributes;
		video: HTMLAttributes;
		wbr: HTMLAttributes;

		//SVG
		svg: SVGAttributes;
		animate: SVGAttributes;
		circle: SVGAttributes;
		clipPath: SVGAttributes;
		defs: SVGAttributes;
		ellipse: SVGAttributes;
		feBlend: SVGAttributes;
		feColorMatrix: SVGAttributes;
		feComponentTransfer: SVGAttributes;
		feComposite: SVGAttributes;
		feConvolveMatrix: SVGAttributes;
		feDiffuseLighting: SVGAttributes;
		feDisplacementMap: SVGAttributes;
		feFlood: SVGAttributes;
		feGaussianBlur: SVGAttributes;
		feImage: SVGAttributes;
		feMerge: SVGAttributes;
		feMergeNode: SVGAttributes;
		feMorphology: SVGAttributes;
		feOffset: SVGAttributes;
		feSpecularLighting: SVGAttributes;
		feTile: SVGAttributes;
		feTurbulence: SVGAttributes;
		filter: SVGAttributes;
		foreignObject: SVGAttributes;
		g: SVGAttributes;
		image: SVGAttributes;
		line: SVGAttributes;
		linearGradient: SVGAttributes;
		marker: SVGAttributes;
		mask: SVGAttributes;
		path: SVGAttributes;
		pattern: SVGAttributes;
		polygon: SVGAttributes;
		polyline: SVGAttributes;
		radialGradient: SVGAttributes;
		rect: SVGAttributes;
		stop: SVGAttributes;
		symbol: SVGAttributes;
		text: SVGAttributes;
		tspan: SVGAttributes;
		use: SVGAttributes;
	}
}


if (!isNew && c.getSnapshotBeforeUpdate!=null) {

oldContext = c.getSnapshotBeforeUpdate(oldProps, oldState);

c.base = dom = diff(dom, parentDom, vnode, prev, context, isSvg, append, excessDomChildren, mounts, c);

keep keep keep keep keep replace keep keep keep keep keep

c.base = dom = diff(dom, parentDom, vnode, prev, context, isSvg, excessDomChildren, mounts, c);

import { assign } from './util';
import { diff, commitRoot } from './diff/index';

/**
 * Base Component class. Provides `setState()` and `forceUpdate()`, which
 * trigger rendering
 * @param {object} props The initial component props
 * @param {object} context The initial context from parent components'
 * getChildContext
 */
export function Component(props, context) {
	this.props = props;
	this.context = context;
	// if (this.state==null) this.state = {};
	// this.state = {};
	// this._dirty = true;
	// this._renderCallbacks = []; // Only class components

	// Other properties that Component will have set later,
	// shown here as commented out for quick reference
	// this.base = null;
	// this._ancestorComponent = null; // Always set right after instantiation
	// this._vnode = null;
	// this._nextState = null; // Only class components
	// this._prevVNode = null;
	// this._processingException = null; // Always read, set only when handling error
	// this._constructor = null; // Only functional components, always set right after instantiation
}

/**
 * Update component state and schedule a re-render.
 * @param {object | ((s: object, p: object) => object)} update A hash of state
 * properties to update with new values or a function that given the current
 * state and props returns a new partial state
 * @param {() => void} [callback] A function to be called once component state is
 * updated
 */
Component.prototype.setState = function(update, callback) {

	// only clone state when copying to nextState the first time.
	let s = (this._nextState!==this.state && this._nextState) || (this._nextState = assign({}, this.state));

	// Needed for the devtools to check if state has changed after the tree
	// has been committed
	this._prevState = assign({}, s);

	// if update() mutates state in-place, skip the copy:
	if (typeof update!=='function' || (update = update(s, this.props))) {
		assign(s, update);
	}

	// Skip update if updater function returned null
	if (update==null) return;

	if (callback!=null) this._renderCallbacks.push(callback);

	this._force = false;
	enqueueRender(this);
};

/**
 * Immediately perform a synchronous re-render of the component
 * @param {() => void} [callback] A function to be called after component is
 * re-renderd
 */
Component.prototype.forceUpdate = function(callback) {
	if (this._parentDom!=null) {
		// Set render mode so that we can differantiate where the render request
		// is coming from. We need this because forceUpdate should never call
		// shouldComponentUpdate
		if (this._force==null) this._force = true;

		let mounts = [];
		diff(this._vnode._dom, this._parentDom, this._vnode, this._vnode, this.context, this._parentDom.ownerSVGElement!==undefined, true, null, mounts, this._ancestorComponent);
		commitRoot(mounts, this._vnode);

		// Reset mode to its initial value for the next render
		this._force = null;
	}
	if (callback!=null) callback();
};

/**
 * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
 * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
 * @param {object} props Props (eg: JSX attributes) received from parent
 * element/component
 * @param {object} state The component's current state
 * @param {object} context Context object, as returned by the nearest
 * ancestor's `getChildContext()`
 * @returns {import('./index').ComponentChildren | void}
 */
Component.prototype.render = function () {};

/**
 * The render queue
 * @type {Array<import('./internal').Component>}
 */
let q = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb) => void}
 */
const defer = typeof Promise=='function' ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout;

/*
 * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
 * important that contributors to Preact can consistenly reason about what calls to `setState`, etc.
 * do, and when their effects will be applied. See the links below for some further reading on designing
 * asynchronous APIs.
 * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
 * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
 */

/**
 * Enqueue a rerender of a component
 * @param {import('./internal').Component} c The component to rerender
 */
export function enqueueRender(c) {
	if (!c._dirty && (c._dirty = true) && q.push(c) === 1) {
		(Component.debounce || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let p;
	while ((p=q.pop())) {
		if (p._dirty) p.forceUpdate();
	}
}


/*global coverage, ENABLE_PERFORMANCE, NODE_ENV*/
/*eslint no-console:0*/
/** @jsx h */
import { setupScratch, teardown } from '../_util/helpers';
let { createElement: h, Component, render } = require(NODE_ENV==='production' ? '../../dist/ceviche.min.js' : '../../dist/ceviche');

const MULTIPLIER = ENABLE_PERFORMANCE ? (coverage ? 5 : 1) : 999999;

// let now = typeof performance!=='undefined' && performance.now ? () => performance.now() : () => +new Date();
if (typeof performance === 'undefined') window.performance = { now: () => +new Date() };

function loop(iter, time) {
	let start = performance.now(),
		count = 0;
	while ( performance.now()-start < time ) {
		count++;
		iter();
	}
	return count;
}

function benchmark(iter, callback) {
	let a = 0; // eslint-disable-line no-unused-vars
	function noop() {
		try { a++; }
		finally { a += Math.random(); }
	}

	// warm
	for (let i=100; i--; ) noop(), iter();

	let count = 4,
		time = 500,
		passes = 0,
		noops = loop(noop, time),
		iterations = 0;

	function next() {
		iterations += loop(iter, time);
		setTimeout(++passes===count ? done : next, 10);
	}

	function done() {
		let ticks = Math.round(noops / iterations * count),
			hz = iterations / count / time * 1000,
			message = `${hz|0}/s (${ticks} ticks)`;
		callback({ iterations, noops, count, time, ticks, hz, message });
	}

	next();
}

describe('performance', function() {
	let scratch;

	this.timeout(10000);

	before(function () {
		if (!ENABLE_PERFORMANCE) this.skip();
		if (coverage) {
			console.warn('WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.');
		}
	});

	beforeEach(() => {
		scratch = setupScratch();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should rerender without changes fast', done => {
		let jsx = (

a {'b'} c {0} d

						Foo
						Bar

					<form onSubmit={() => {}}>
						<input type="checkbox" checked />
						<input type="checkbox" checked={false} />
						<fieldset>
							<input type="radio" checked />
							<input type="radio" />
						</fieldset>
						<button-bar>
							<button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button>
							<button style="top:0 ; right: 20">Poor CSS</button>
							<button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button>
							<button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>Object CSS</button>
						</button-bar>
					</form>

		);

		let root;
		benchmark( () => {
			root = render(jsx, scratch, root);
		}, ({ ticks, message }) => {
			console.log(`PERF: empty diff: ${message}`);
			expect(ticks).to.be.below(150 * MULTIPLIER);
			done();
		});
	});

	it('should rerender repeated trees fast', done => {
		class Header extends Component {
			render() {
				return (

a {'b'} c {0} d

							Foo
							Bar

				);
			}
		}
		class Form extends Component {
			render() {
				return (
					<form onSubmit={() => {}}>
						<input type="checkbox" checked />
						<input type="checkbox" checked={false} />
						<fieldset>
							<input type="radio" checked />
							<input type="radio" />
						</fieldset>
						<ButtonBar />
					</form>
				);
			}
		}
		class ButtonBar extends Component {
			render() {
				return (
					<button-bar>
						<Button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</Button>
						<Button style="top:0 ; right: 20">Poor CSS</Button>
						<Button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</Button>
						<Button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>Object CSS</Button>
					</button-bar>
				);
			}
		}
		class Button extends Component {
			render(props) {
				return <button {...props} />;
			}
		}
		class Main extends Component {
			render() {
				return <Form />;
			}
		}
		class Root extends Component {
			render() {
				return (

				);
			}
		}
		class Empty extends Component {
			render() {
				return
;
			}
		}
		class Parent extends Component {
			render({ child: C }) {
				return <C />;
			}
		}

		let root;
		benchmark( () => {
			root = render(<Parent child={Root} />, scratch, root);
			root = render(<Parent child={Empty} />, scratch, root);
		}, ({ ticks, message }) => {
			console.log(`PERF: repeat diff: ${message}`);
			expect(ticks).to.be.below(2000 * MULTIPLIER);
			done();
		});
	});

	it('should construct large VDOM trees fast', done => {
		const FIELDS = [];
		for (let i=100; i--; ) FIELDS.push((i*999).toString(36));

		let out = [];
		function digest(vnode) {
			out.push(vnode);
			out.length = 0;
		}
		benchmark( () => {
			digest(

a {'b'} c {0} d

							Foo
							Bar

						<form onSubmit={() => {}}>
							<input type="checkbox" checked />
							<input type="checkbox" />
							<fieldset>
								{ FIELDS.map( field => (

										{field}:
										<input placeholder={field} />

								)) }
							</fieldset>
							<button-bar>
								<button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</button>
								<button style="top:0 ; right: 20">Poor CSS</button>
								<button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</button>
								<button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>Object CSS</button>
							</button-bar>
						</form>

			);
		}, ({ ticks, message }) => {
			console.log(`PERF: large VTree: ${message}`);
			expect(ticks).to.be.below(2000 * MULTIPLIER);
			done();
		});
	});

	it('should mutate styles/properties quickly', done => {
		let counter = 0;
		const keyLooper = n => c => c % n ? `${c}px` : c;
		const get = (obj, i) => obj[i%obj.length];
		const CLASSES = ['foo', 'foo bar', '', 'baz-bat', null];
		const STYLES = [];
		const MULTIVALUE = ['0 1px', '0 0 1px 0', '0', '1px', '20px 10px', '7em 5px', '1px 0 5em 2px'];
		const STYLEKEYS = [
			['left', keyLooper(3)],
			['top', keyLooper(2)],
			['margin', c => get(MULTIVALUE, c).replace('1px', c+'px')],
			['padding', c => get(MULTIVALUE, c)],
			['position', c => c%5 ? c%2 ? 'absolute' : 'relative' : null],
			['display', c => c%10 ? c%2 ? 'block' : 'inline' : 'none'],
			['color', c => `rgba(${c%255}, ${255 - c%255}, ${50+c%150}, ${c%50/50})`],
			['border', c => c%5 ? `${c%10}px ${c%2?'solid':'dotted'} ${STYLEKEYS[6][1](c)}` : '']
		];
		for (let i=0; i<1000; i++) {
			let style = {};
			for (let j=0; j (

				<input type="checkbox" checked={index%3 == 0} />
				<input value={`test ${index/4|0}`} disabled={index%10 ? null : true} />

p1

p2

p3

p4

		);

		let root, count=0;
		benchmark( () => {
			root = render(app(++count), scratch, root);
		}, ({ ticks, message }) => {
			console.log(`PERF: style/prop mutation: ${message}`);
			expect(ticks).to.be.below(350 * MULTIPLIER);
			done();
		});
	});

	it('should hydrate from SSR quickly', done => {
		class Header extends Component {
			render() {
				return (

a {'b'} c {0} d

							Foo
							Bar

				);
			}
		}
		class Form extends Component {
			render() {
				return (
					<form onSubmit={() => {}}>
						<input type="checkbox" checked />
						<input type="checkbox" checked={false} />
						<fieldset>
							<input type="radio" checked />
							<input type="radio" />
						</fieldset>
						<ButtonBar />
					</form>
				);
			}
		}
		const ButtonBar = () => (
			<button-bar>
				<Button style="width:10px; height:10px; border:1px solid #FFF;">Normal CSS</Button>
				<Button style="top:0 ; right: 20">Poor CSS</Button>
				<Button style="invalid-prop:1;padding:1px;font:12px/1.1 arial,sans-serif;" icon>Poorer CSS</Button>
				<Button style={{ margin: 0, padding: '10px', overflow: 'visible' }}>Object CSS</Button>
			</button-bar>
		);
		class Button extends Component {
			handleClick() {}
			render(props) {
				return <button onClick={this.handleClick} {...props} />;
			}
		}
		const Main = () => <Form />;
		class App extends Component {
			render() {
				return (

				);
			}
		}

		render(<App />, scratch, scratch.firstChild);
		let html = scratch.innerHTML;

		benchmark( () => {
			scratch.innerHTML = html;
			render(<App />, scratch, scratch.firstChild);
		}, ({ ticks, message }) => {
			console.log(`PERF: SSR Hydrate: ${message}`);
			expect(ticks).to.be.below(3000 * MULTIPLIER);
			done();
		});
	});
});


import "mocha";
import { expect } from "chai";
import {
	createElement,
	Component,
	RenderableProps,
	Fragment
} from "../../src/";

export class ContextComponent extends Component<{ foo: string }> {
	getChildContext() {
		return { something: 2 };
	}

	render() {
		return null;
	}
}

export interface SimpleComponentProps {
	initialName: string | null;
}

export interface SimpleState {
	name: string | null;
}

export class SimpleComponent extends Component<
	SimpleComponentProps,
	SimpleState
> {
	constructor(props: SimpleComponentProps) {
		super(props);
		this.state = {
			name: props.initialName
		};
	}

	render() {
		if (!this.state.name) {
			return null;
		}
		const { initialName, children } = this.props;
		return (

					{initialName} / {this.state.name}

				{children}

		);
	}
}

class DestructuringRenderPropsComponent extends Component<
	SimpleComponentProps,
	SimpleState
> {
	constructor(props: SimpleComponentProps) {
		super(props);
		this.state = {
			name: props.initialName
		};
	}

	render({ initialName, children }: RenderableProps<SimpleComponentProps>) {
		if (!this.state.name) {
			return null;
		}
		return (

				{this.props.initialName} / {this.state.name}

		);
	}
}

interface RandomChildrenComponenProps {
	num?: number;
	val?: string;
	span?: boolean;
}

class RandomChildrenComponent extends Component<RandomChildrenComponenProps> {
	render() {
		const { num, val, span } = this.props;
		if (num) {
			return num;
		}
		if (val) {
			return val;
		}
		if (span) {
			return hi
		}
		return null;
	}
}

describe("Component", () => {
	const component = new SimpleComponent({ initialName: "da name" });

	it("has state", () => {
		expect(component.state.name).to.eq("da name");
	});

	it("has props", () => {
		expect(component.props.initialName).to.eq("da name");
	});

	it("has no base when not mounted", () => {
		expect(component.base).to.not.exist;
	});

	describe("setState", () => {
		it("can be used with an object", () => {
			component.setState({ name: "another name" });
		});

		it("can be used with a function", () => {
			const updater = (state: any, props: any) => ({
				name: `${state.name} - ${props.initialName}`
			});
			component.setState(updater);
		});
	});

	describe("render", () => {
		it("can return null", () => {
			const comp = new SimpleComponent({ initialName: null });
			const actual = comp.render();

			expect(actual).to.eq(null);
		});
	});

	describe("Fragment", () => {
		it('should render nested Fragments', () => {
			var vnode = <Fragment>
					<Fragment>foo</Fragment>
					bar
				</Fragment>

			expect(vnode.type).to.be.equal(Fragment);
		});
	});
});


import { createElement as h, render } from 'preact';
import { spy } from 'sinon';
import { setupScratch, teardown, setupRerender } from '../../../test/_util/helpers';
import { useState } from '../../src';

/** @jsx h */

describe('useState', () => {

	/** @type {HTMLDivElement} */
	let scratch;

	/** @type {() => void} */
	let rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('serves the same state across render calls', () => {
		const stateHistory = [];

		function Comp() {
			const [state] = useState({ a: 1 });
			stateHistory.push(state);
			return null;
		}

		render(<Comp />, scratch);
		render(<Comp />, scratch);

		expect(stateHistory).to.deep.equal([{ a: 1 }, { a: 1 }]);
		expect(stateHistory[0]).to.equal(stateHistory[1]);
	});

	it('can initialize the state via a function', () => {
		const initState = spy(() => { a: 1 })

		function Comp() {
			useState(initState);
			return null;
		}

		render(<Comp />, scratch);
		render(<Comp />, scratch);

		expect(initState).to.be.calledOnce;
	});

	it('rerenders when setting the state', () => {
		let lastState;
		let doSetState;

		const Comp = spy(() => {
			const [state, setState] = useState(0);
			lastState = state;
			doSetState = setState;
			return null;
		});

		render(<Comp />, scratch);
		expect(lastState).to.equal(0);
		expect(Comp).to.be.calledOnce;

		doSetState(1);
		rerender();
		expect(lastState).to.equal(1);
		expect(Comp).to.be.calledTwice;

		// Updater function style
		doSetState(current => current * 10);
		rerender();
		expect(lastState).to.equal(10);
		expect(Comp).to.be.calledThrice;
	});

});


if (parentDom && append!==false && dom!=null && dom.parentNode!==parentDom) {

keep keep keep replace replace replace replace replace keep keep keep


import { options } from 'ceviche';
import { Renderer } from './renderer';

/**
 * Wrap function with generic error logging
 *
 * @param {*} fn
 * @returns
 */
function catchErrors(fn) {
	return function(arg) {
		try {
			return fn(arg);
		}
		catch (e) {
			/* istanbul ignore next */
			console.error('The react devtools encountered an error');
			/* istanbul ignore next */
			console.log(e); // eslint-disable-line no-console
		}
	};
}

/* istanbul ignore next */
let noop = () => undefined;

export function initDevTools() {
	// This global variable is injected by the devtools
	/** @type {import('../internal').DevtoolsWindow} */
	let hook = (window).__REACT_DEVTOOLS_GLOBAL_HOOK__;
	if (hook==null) return;

	/** @type {(vnode: import('../internal').VNode) => void} */
	let onCommitRoot = noop;

	/** @type {(vnode: import('../internal').VNode) => void} */
	let onCommitUnmount = noop;

	// Initialize our custom renderer
	let rid = Math.random().toString(16).slice(2);
	let cevicheRenderer = new Renderer(hook, rid);

	catchErrors(() => {
		let isDev = false;
		try {
			isDev = process.env.NODE_ENV!=='production';
		}
		catch (e) {}

		// Tell devtools which bundle type we run in
		window.parent.postMessage({
			source: 'react-devtools-detector',
			reactBuildType: /* istanbul ignore next */  isDev
				? 'development'
				: 'production'
		}, '*');

		let renderer = {
			bundleType: /* istanbul ignore next */  isDev ? 1 : 0,
			version: '16.5.2',
			rendererPackageName: 'preact',
			// We don't need this, but the devtools `attachRenderer` function relys
			// it being there.
			findHostInstanceByFiber(vnode) {
				return vnode._dom;
			},
			// We don't need this, but the devtools `attachRenderer` function relys
			// it being there.
			findFiberByHostInstance(instance) {
				return cevicheRenderer.inst2vnode.get(instance) || null;
			}
		};

		hook._renderers[rid] = renderer;

		// We can't bring our own `attachRenderer` function therefore we simply
		// prevent the devtools from overwriting our custom renderer by creating
		// a noop setter.
		Object.defineProperty(hook.helpers, rid, {
			get: () => cevicheRenderer,
			set: () => {
				if (!cevicheRenderer.connected) {
					helpers.markConnected();
				}
			}
		});

		let helpers = hook.helpers[rid];

		// Tell the devtools that we are ready to start
		hook.emit('renderer-attached', {
			id: rid,
			renderer,
			helpers
		});

		onCommitRoot = catchErrors(root => {
			let roots = hook.getFiberRoots(rid);
			root = helpers.handleCommitFiberRoot(root);
			if (!roots.has(root)) roots.add(root);
		});

		onCommitUnmount = catchErrors(vnode => {
			hook.onCommitFiberUnmount(rid, vnode);
		});
	})();

	// Store (possible) previous hooks so that we don't overwrite them
	let prevVNodeHook = options.vnode;
	let prevCommitRoot = options.commitRoot;
	let prevBeforeUnmount = options.beforeUnmount;
	let prevBeforeDiff = options.beforeDiff;
	let prevAfterDiff = options.afterDiff;

	options.vnode = (vnode) => {
		vnode.startTime = 0;
		vnode.endTime = -1;
		if (prevVNodeHook) prevVNodeHook(vnode);
	};

	options.beforeDiff = (vnode) => {
		vnode.startTime = now();
		if (prevBeforeDiff!=null) prevBeforeDiff(vnode);
	};

	options.afterDiff = (vnode) => {
		vnode.endTime = now();
		if (prevAfterDiff!=null) prevAfterDiff(vnode);
	};

	options.commitRoot = catchErrors((vnode) => {
		// Call previously defined hook
		if (prevCommitRoot!=null) prevCommitRoot(vnode);

		// These cases are already handled by `beforeUnmount`
		if (vnode==null || vnode._dom==null) return;
		onCommitRoot(vnode);
	});

	options.beforeUnmount = catchErrors((vnode) => {
		// Call previously defined hook
		if (prevBeforeUnmount!=null) prevBeforeUnmount(vnode);
		onCommitUnmount(vnode);
	});
}

/**
 * Get current timestamp in ms. Used for profiling.
 * @returns {number}
 */
export let now = Date.now;

try {
	/* istanbul ignore else */
	now = performance.now.bind(performance);
}
catch (e) {}


{
	"compilerOptions": {
		"strict": true,
	},
	"include": [
		"./**/*.ts"
	]
}


ConnectionManager.prototype.refreshTypeParser = function(dataTypes) {

_.each(dataTypes, function (dataType, key) {

throw new Error('Parse function not supported for type ' + dataType.key + ' in dialect ' + this.dialectName);

keep keep keep replace keep keep keep keep

'use strict';

/* jshint -W030 */
/* jshint -W110 */
var chai = require('chai')
  , Sequelize = require('../../index')
  , expect = chai.expect
  , Support = require(__dirname + '/support')
  , sinon = require('sinon')
  , _ = require('lodash')
  , moment = require('moment')
  , current = Support.sequelize
  , uuid = require('node-uuid')
  , DataTypes = require('../../lib/data-types')
  , dialect = Support.getTestDialect();

describe(Support.getTestDialectTeaser('DataTypes'), function() {
  afterEach(function () {
    // Restore some sanity by resetting all parsers
    switch (dialect) {
      case 'postgres':
        var types = require('../../node_modules/pg/node_modules/pg-types');

        _.each(DataTypes, function (dataType) {
          if (dataType.types && dataType.types.postgres) {
            dataType.types.postgres.oids.forEach(function (oid) {
              types.setTypeParser(oid, _.identity);
            });
          }
        });
        require('../../node_modules/pg/node_modules/pg-types/lib/binaryParsers').init(function (oid, converter) {
          types.setTypeParser(oid, 'binary', converter);
        });
        require('../../node_modules/pg/node_modules/pg-types/lib/textParsers').init(function (oid, converter) {
          types.setTypeParser(oid, 'text', converter);
        });

        this.sequelize.connectionManager.refreshTypes(DataTypes.postgres); // Reload custom parsers for hstore and geometry
        break;
      default:
        this.sequelize.connectionManager.$clearTypeParser();
    }
  });

  it('allows me to return values from a custom parse function', function () {
    var parse = Sequelize.DATE.parse = sinon.spy(function (value) {
      return moment(value, 'YYYY-MM-DD HH:mm:ss Z');
    });

    var stringify = Sequelize.DATE.prototype.stringify = sinon.spy(function (value, options) {
      if (!moment.isMoment(value)) {
        value = this.$applyTimezone(value, options);
      }
      return value.format('YYYY-MM-DD HH:mm:ss Z');
    });

    current.refreshTypes();

    var User = current.define('user', {
      dateField: Sequelize.DATE
    }, {
      timestamps: false
    });

    return current.sync({ force: true }).then(function () {
      return User.create({
        dateField: moment("2011 10 31", 'YYYY MM DD')
      });
    }).then(function () {
      return User.findAll().get(0);
    }).then(function (user) {
      expect(parse).to.have.been.called;
      expect(stringify).to.have.been.called;

      expect(moment.isMoment(user.dateField)).to.be.ok;

      delete Sequelize.DATE.parse;
    });
  });

  var testSuccess = function (Type, value) {
    var parse = Type.constructor.parse = sinon.spy(function (value) {
      return value;
    });

    var stringify = Type.constructor.prototype.stringify = sinon.spy(function (value) {
      return Sequelize.ABSTRACT.prototype.stringify.apply(this, arguments);
    });

    current.refreshTypes();

    var User = current.define('user', {
      field: Type
    }, {
      timestamps: false
    });

    return current.sync({ force: true }).then(function () {
      return User.create({
        field: value
      });
    }).then(function () {
      return User.findAll().get(0);
    }).then(function (user) {
      expect(parse).to.have.been.called;
      expect(stringify).to.have.been.called;

      delete Type.constructor.parse;
      delete Type.constructor.prototype.stringify;
    });
  };

  var testFailure = function (Type, value) {
    Type.constructor.parse = _.noop();

    expect(function ()  {
      current.refreshTypes();
    }).to.throw('Parse function not supported for type ' + Type.key + ' in dialect ' + dialect);

    delete Type.constructor.parse;
  };

  if (dialect === 'postgres') {
    it('calls parse and stringify for JSON', function () {
      var Type = new Sequelize.JSON();

      return testSuccess(Type, { test: 42, nested: { foo: 'bar' }});
    });

    it('calls parse and stringify for JSONB', function () {
      var Type = new Sequelize.JSONB();

      return testSuccess(Type, { test: 42, nested: { foo: 'bar' }});
    });

    it('calls parse and stringify for HSTORE', function () {
      var Type = new Sequelize.HSTORE();

      return testSuccess(Type, { test: 42, nested: false });
    });

    it('calls parse and stringify for RANGE', function () {
      var Type = new Sequelize.RANGE(new Sequelize.INTEGER());

      return testSuccess(Type, [1, 2]);
    });
  }

  it('calls parse and stringify for DATE', function () {
    var Type = new Sequelize.DATE();

    return testSuccess(Type, new Date());
  });

  it('calls parse and stringify for DATEONLY', function () {
    var Type = new Sequelize.DATEONLY();

    return testSuccess(Type, new Date());
  });

  it('calls parse and stringify for TIME', function () {
    var Type = new Sequelize.TIME();

    return testSuccess(Type, new Date());
  });

  it('calls parse and stringify for BLOB', function () {
    var Type = new Sequelize.BLOB();

    return testSuccess(Type, 'foobar');
  });

  it('calls parse and stringify for CHAR', function () {
    var Type = new Sequelize.CHAR();

    return testSuccess(Type, 'foobar');
  });

  it('calls parse and stringify for STRING', function () {
    var Type = new Sequelize.STRING();

    return testSuccess(Type, 'foobar');
  });

  it('calls parse and stringify for TEXT', function () {
    var Type = new Sequelize.TEXT();

    if (dialect === 'mssql') {
      // Text uses nvarchar, same type as string
      testFailure(Type);
    } else {
      return testSuccess(Type, 'foobar');
    }
  });

   it('calls parse and stringify for BOOLEAN', function () {
    var Type = new Sequelize.BOOLEAN();

    return testSuccess(Type, true);
  });

   it('calls parse and stringify for INTEGER', function () {
    var Type = new Sequelize.INTEGER();

    return testSuccess(Type, 1);
  });

  it('calls parse and stringify for DECIMAL', function () {
    var Type = new Sequelize.DECIMAL();

    return testSuccess(Type, 1.5);
  });

   it('calls parse and stringify for BIGINT', function () {
    var Type = new Sequelize.BIGINT();

    if (dialect === 'mssql') {
      // Same type as integer
      testFailure(Type);
    } else {
      return testSuccess(Type, 1);
    }
  });

  it('calls parse and stringify for DOUBLE', function () {
    var Type = new Sequelize.DOUBLE();

    return testSuccess(Type, 1.5);
  });

  it('calls parse and stringify for FLOAT', function () {
    var Type = new Sequelize.FLOAT();

    if (dialect === 'postgres') {
      // Postgres doesn't have float, maps to either decimal or double
      testFailure(Type);
    } else {
      return testSuccess(Type, 1.5);
    }
  });

  it('calls parse and stringify for REAL', function () {
    var Type = new Sequelize.REAL();

    return testSuccess(Type, 1.5);
  });

  it('calls parse and stringify for GEOMETRY', function () {
    var Type = new Sequelize.GEOMETRY();

    if (['postgres', 'mysql'].indexOf(dialect) !== -1) {
      return testSuccess(Type, { type: "Point", coordinates: [125.6, 10.1] });
    } else {
      // Not implemented yet
      testFailure(Type);
    }
  });

  it('calls parse and stringify for UUID', function () {
    var Type = new Sequelize.UUID();

    if (['postgres', 'sqlite'].indexOf(dialect) !== -1) {
      return testSuccess(Type, uuid.v4());
    } else {
      // No native uuid type
      testFailure(Type);
    }
  });

  it('calls parse and stringify for ENUM', function () {
    var Type = new Sequelize.ENUM('hat', 'cat');

     // No dialects actually allow us to identify that we get an enum back..
    testFailure(Type);
  });
});


docs
examples
test
README.md
.watchr.js
changelog.md
Makefile
coverage*


# Class Transaction
[View code](https://github.com/sequelize/sequelize/blob/0de404640d4c71e2d1f1259356650dfb586a248b/lib/transaction.js#L19)

The transaction object is used to identify a running transaction. It is created by calling `Sequelize.transaction()`.

To run a query under a transaction, you should pass the transaction in the options object.

**Params:**

| Name | Type | Description |
| ---- | ---- | ----------- |
| sequelize | Sequelize | A configured sequelize Instance |
| options | Object | An object with options |
| options.autocommit=true | Boolean | Sets the autocommit property of the transaction. |
| options.isolationLevel=true | String | Sets the isolation level of the transaction. |
| options.deferrable | String | Sets the constraints to be deferred or immediately checked. |

***

## `ISOLATION_LEVELS`
[View code](https://github.com/sequelize/sequelize/blob/0de404640d4c71e2d1f1259356650dfb586a248b/lib/transaction.js#L71)

Isolations levels can be set per-transaction by passing `options.isolationLevel` to `sequelize.transaction`.
Default to `REPEATABLE_READ` but you can override the default isolation level by passing `options.isolationLevel` in `new Sequelize`.

The possible isolations levels to use when starting a transaction:

```js
{
  READ_UNCOMMITTED: "READ UNCOMMITTED",
  READ_COMMITTED: "READ COMMITTED",
  REPEATABLE_READ: "REPEATABLE READ",
  SERIALIZABLE: "SERIALIZABLE"
}
```

Pass in the desired level as the first argument:

```js
return sequelize.transaction({
  isolationLevel: Sequelize.Transaction.SERIALIZABLE
}, function (t) {

 // your transactions

}).then(function(result) {
  // transaction has been committed. Do something after the commit if required.
}).catch(function(err) {
  // do something with the err.
});
```

***

## `LOCK`
[View code](https://github.com/sequelize/sequelize/blob/0de404640d4c71e2d1f1259356650dfb586a248b/lib/transaction.js#L115)

Possible options for row locking. Used in conjuction with `find` calls:

```js
t1 // is a transaction
t1.LOCK.UPDATE,
t1.LOCK.SHARE,
t1.LOCK.KEY_SHARE, // Postgres 9.3+ only
t1.LOCK.NO_KEY_UPDATE // Postgres 9.3+ only
```

Usage:
```js
t1 // is a transaction
Model.findAll({
  where: ...,
  transaction: t1,
  lock: t1.LOCK...
});
```

Postgres also supports specific locks while eager loading by using OF:
```js
UserModel.findAll({
  where: ...,
  include: [TaskModel, ...],
  transaction: t1,
  lock: {
    level: t1.LOCK...,
    of: UserModel
  }
});
```
UserModel will be locked but TaskModel won't!

***

## `commit()` -> `Promise`
[View code](https://github.com/sequelize/sequelize/blob/0de404640d4c71e2d1f1259356650dfb586a248b/lib/transaction.js#L127)

Commit the transaction

***

## `rollback()` -> `Promise`
[View code](https://github.com/sequelize/sequelize/blob/0de404640d4c71e2d1f1259356650dfb586a248b/lib/transaction.js#L154)

Rollback (abort) the transaction

***

_This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on IRC, open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org) and [dox](https://github.com/tj/dox)_


# Imprint - Boring legal stuff for the rest of us.
As there are people who are suing for fun and glory, you can find the respective information about the author of the page right here. Have fun reading ...

## AUTHOR(S)

```
Main author:

Sascha Depold
Uhlandstr. 122
10717 Berlin
sascha [at] depold [dot] com
[plus] 49 152 [slash] 03878582
```

## INHALTLICHE VERANTWORTUNG

```
Ich übernehme keine Haftung für ausgehende Links.
Daher musst du dich bei Problemen an deren Betreiber wenden!
```


'use strict';

var chai = require('chai')
  , expect = chai.expect
  , Support = require(__dirname + '/support')
  , dialect = Support.getTestDialect()
  , Sequelize = require(__dirname + '/../../index')
  , Promise = Sequelize.Promise;

if (dialect !== 'sqlite') {
  // Sqlite does not support setting timezone

  describe(Support.getTestDialectTeaser('Timezone'), function() {
    beforeEach(function() {
      this.sequelizeWithTimezone = Support.createSequelizeInstance({
        timezone: '+07:00'
      });
      this.sequelizeWithNamedTimezone = Support.createSequelizeInstance({
        timezone: 'America/New_York'
      });
    });

    it('returns the same value for current timestamp', function() {
      var now = 'now()'
        , startQueryTime = Date.now();

      if (dialect === 'mssql') {
        now = 'GETDATE()';
      }

      var query = 'SELECT ' + now + ' as now';
      return Promise.all([
        this.sequelize.query(query, { type: this.sequelize.QueryTypes.SELECT }),
        this.sequelizeWithTimezone.query(query, { type: this.sequelize.QueryTypes.SELECT })
      ]).spread(function(now1, now2) {
        var elapsedQueryTime = (Date.now() - startQueryTime) + 1001;
        expect(now1[0].now.getTime()).to.be.closeTo(now2[0].now.getTime(), elapsedQueryTime);
      });
    });

    if (Support.dialectIsMySQL()) {
      it('handles existing timestamps', function() {
        var NormalUser = this.sequelize.define('user', {})
          , TimezonedUser = this.sequelizeWithTimezone.define('user', {});

        return this.sequelize.sync({ force: true }).bind(this).then(function() {
          return TimezonedUser.create({});
        }).then(function(timezonedUser) {
          this.timezonedUser = timezonedUser;
          return NormalUser.findById(timezonedUser.id);
        }).then(function(normalUser) {
          // Expect 7 hours difference, in milliseconds.
          // This difference is expected since two instances, configured for each their timezone is trying to read the same timestamp
          // this test does not apply to PG, since it stores the timezone along with the timestamp.
          expect(normalUser.createdAt.getTime() - this.timezonedUser.createdAt.getTime()).to.be.closeTo(60 * 60 * 7 * 1000, 50);
        });
      });

      it('handles named timezones', function() {
        var NormalUser = this.sequelize.define('user', {})
          , TimezonedUser = this.sequelizeWithNamedTimezone.define('user', {});

        return this.sequelize.sync({ force: true }).bind(this).then(function() {
          return TimezonedUser.create({});
        }).then(function(timezonedUser) {
          this.timezonedUser = timezonedUser;
          return NormalUser.findById(timezonedUser.id);
        }).then(function(normalUser) {
          // Expect 5 hours difference, in milliseconds, +/- 1 hour for DST
          expect(normalUser.createdAt.getTime() - this.timezonedUser.createdAt.getTime()).to.be.closeTo(60 * 60 * 4 * 1000 * -1, 60 * 60 * 1000);
        });
      });
    }
  });
}


Copyright (c) 2014-2015 Sequelize contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


'use strict';

/* jshint -W030 */
var chai = require('chai')
  , expect = chai.expect
  , Support = require(__dirname + '/support')
  , DataTypes = require(__dirname + '/../../lib/data-types')
  , dialect = Support.getTestDialect()
  , _ = require('lodash')
  , count = 0
  , log = function (sql) {
    // sqlite fires a lot more querys than the other dbs. this is just a simple hack, since i'm lazy
    if (dialect !== 'sqlite' || count === 0) {
      count++;
    }
  };

describe(Support.getTestDialectTeaser('QueryInterface'), function() {
  beforeEach(function() {
    this.sequelize.options.quoteIdenifiers = true;
    this.queryInterface = this.sequelize.getQueryInterface();
  });

  describe('dropAllTables', function() {
    it('should drop all tables', function() {
      var self = this;
      return this.queryInterface.dropAllTables().then(function() {
        return self.queryInterface.showAllTables({logging: log}).then(function(tableNames) {
          expect(count).to.be.equal(1);
          count = 0;
          expect(tableNames).to.be.empty;
          return self.queryInterface.createTable('table', { name: DataTypes.STRING }, {
            logging: log
          }).then(function() {
            expect(count).to.be.equal(1);
            count = 0;
            return self.queryInterface.showAllTables({logging: log}).then(function(tableNames) {
              expect(count).to.be.equal(1);
              count = 0;
              expect(tableNames).to.have.length(1);
              return self.queryInterface.dropAllTables({logging: log}).then(function() {
                expect(count).to.be.at.least(1);
                count = 0;
                return self.queryInterface.showAllTables().then(function(tableNames) {
                  expect(tableNames).to.be.empty;
                });
              });
            });
          });
        });
      });
    });

    it('should be able to skip given tables', function() {
      var self = this;
      return self.queryInterface.createTable('skipme', {
        name: DataTypes.STRING
      }).then(function() {
        return self.queryInterface.dropAllTables({skip: ['skipme']}).then(function() {
          return self.queryInterface.showAllTables().then(function(tableNames) {
            if (dialect === 'mssql' /* current.dialect.supports.schemas */) {
              tableNames = _.pluck(tableNames, 'tableName');
            }
            expect(tableNames).to.contain('skipme');
          });
        });
      });
    });
  });

  describe('indexes', function() {
    beforeEach(function() {
      var self = this;
      return this.queryInterface.dropTable('Group', {logging: log}).then(function() {
        expect(count).to.be.at.least(1);
        count = 0;
        return self.queryInterface.createTable('Group', {
          username: DataTypes.STRING,
          isAdmin: DataTypes.BOOLEAN,
          from: DataTypes.STRING
        });
      });
    });

    it('adds, reads and removes an index to the table', function() {
      var self = this;
      return this.queryInterface.addIndex('Group', ['username', 'isAdmin'], {
        logging: log
      }).then(function() {
        expect(count).to.be.equal(1);
        count = 0;
        return self.queryInterface.showIndex('Group', {logging: log}).then(function(indexes) {
          expect(count).to.be.equal(1);
          count = 0;

          var indexColumns = _.uniq(indexes.map(function(index) { return index.name; }));
          expect(indexColumns).to.include('group_username_is_admin');
          return self.queryInterface.removeIndex('Group', ['username', 'isAdmin'], {logging: log}).then(function() {
            expect(count).to.be.equal(1);
            count = 0;
            return self.queryInterface.showIndex('Group').then(function(indexes) {
              indexColumns = _.uniq(indexes.map(function(index) { return index.name; }));
              expect(indexColumns).to.be.empty;
            });
          });
        });
      });
    });

    it('works with schemas', function() {
      var self = this;
      return self.sequelize.dropAllSchemas({logging: log}).then(function() {
        return self.sequelize.createSchema('schema', {logging: log});
      }).then(function() {
        return self.queryInterface.createTable('table', {
          name: {
            type: DataTypes.STRING
          },
          isAdmin: {
            type: DataTypes.STRING
          }
        }, {
          schema: 'schema'
        });
      }).then(function() {
          return self.queryInterface.addIndex({
            schema: 'schema',
            tableName: 'table'
          }, ['name', 'isAdmin'], {
            logging: log
          }, 'schema_table').then(function() {
            return self.queryInterface.showIndex({
              schema: 'schema',
              tableName: 'table'
            }, {logging: log}).then(function(indexes) {
              expect(indexes.length).to.eq(1);
              count = 0;
            });
          });
      });
    });

    it('does not fail on reserved keywords', function() {
      return this.queryInterface.addIndex('Group', ['from']);
    });
  });

  describe('describeTable', function() {
    it('reads the metadata of the table', function() {
      var self = this;
      var Users = self.sequelize.define('_Users', {
        username: DataTypes.STRING,
        isAdmin: DataTypes.BOOLEAN,
        enumVals: DataTypes.ENUM('hello', 'world')
      }, { freezeTableName: true });

      return Users.sync({ force: true }).then(function() {
        return self.queryInterface.describeTable('_Users', {logging: log}).then(function(metadata) {
          expect(count).to.be.at.least(1);
          count = 0;

          var id = metadata.id;
          var username = metadata.username;
          var isAdmin = metadata.isAdmin;
          var enumVals = metadata.enumVals;

          expect(id.primaryKey).to.be.ok;

          var assertVal = 'VARCHAR(255)';
          switch (dialect) {
            case 'postgres':
              assertVal = 'CHARACTER VARYING';
              break;
            case 'mssql':
              assertVal = 'NVARCHAR';
              break;
          }
          expect(username.type).to.equal(assertVal);
          expect(username.allowNull).to.be.true;
          expect(username.defaultValue).to.be.null;

          assertVal = 'TINYINT(1)';
          switch (dialect) {
            case 'postgres':
              assertVal = 'BOOLEAN';
              break;
            case 'mssql':
              assertVal = 'BIT';
              break;
          }
          expect(isAdmin.type).to.equal(assertVal);
          expect(isAdmin.allowNull).to.be.true;
          expect(isAdmin.defaultValue).to.be.null;

          if (dialect === 'postgres' || dialect === 'postgres-native') {
            expect(enumVals.special).to.be.instanceof(Array);
            expect(enumVals.special).to.have.length(2);
          }
        });
      });
    });
  });

  describe('createTable', function() {
    it('should create a auto increment primary key', function() {
      return this.queryInterface.createTable('TableWithPK', {
        table_id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        }
      }).bind(this).then(function() {
        return this.queryInterface.insert(null, 'TableWithPK', {}, {raw: true, returning: true, plain: true}).then(function(response) {
          expect(response.table_id || (typeof response !== 'object' && response)).to.be.ok;
        });
      });
    });

    it('should work with enums (1)', function() {
      return this.queryInterface.createTable('SomeTable', {
        someEnum: DataTypes.ENUM('value1', 'value2', 'value3')
      });
    });

    it('should work with enums (2)', function() {
      return this.queryInterface.createTable('SomeTable', {
        someEnum: {
          type: DataTypes.ENUM,
          values: ['value1', 'value2', 'value3']
        }
      });
    });

    it('should work with enums (3)', function() {
      return this.queryInterface.createTable('SomeTable', {
        someEnum: {
          type: DataTypes.ENUM,
          values: ['value1', 'value2', 'value3'],
          field: 'otherName'
        }
      });
    });

    it('should work with schemas', function() {
      var self = this;
      return self.sequelize.dropAllSchemas({logging: log}).then(function() {
        // TODO: FIXME: somehow these do not fire the logging function
        if (dialect !== 'mysql' && dialect !== 'sqlite' && dialect !== 'mariadb') {
          expect(count).to.be.above(0);
        }
        count = 0;
        return self.sequelize.createSchema('hero', {logging: log});
      }).then(function() {
        expect(count).to.be.equal(1);
        count = 0;
        return self.queryInterface.createTable('User', {
          name: {
            type: DataTypes.STRING
          }
        }, {
          schema: 'hero'
        });
      }).then(function() {
        return self.queryInterface.rawSelect('User', {
          schema: 'hero',
          logging: log
        }, 'name');
      }).then(function() {
        expect(count).to.be.equal(1);
        count = 0;
      });
    });
  });

  describe('renameColumn', function() {
    it('rename a simple column', function() {
      var self = this;
      var Users = self.sequelize.define('_Users', {
        username: DataTypes.STRING
      }, { freezeTableName: true });

      return Users.sync({ force: true }).then(function() {
        return self.queryInterface.renameColumn('_Users', 'username', 'pseudo', {logging: log}).then(function() {
          if (dialect === 'sqlite')
            count++;
          expect(count).to.be.equal(2);
          count = 0;
        });
      });
    });

    it('works with schemas', function() {
      var self = this;
      var Users = self.sequelize.define('User', {
        username: DataTypes.STRING
      }, {
        tableName: 'Users',
        schema: 'archive'
      });

      return self.sequelize.dropAllSchemas().then(function() {
        return self.sequelize.createSchema('archive');
      }).then(function() {
        return Users.sync({ force: true }).then(function() {
          return self.queryInterface.renameColumn({
            schema: 'archive',
            tableName: 'Users'
          }, 'username', 'pseudo');
        });
      });
    });

    it('rename a column non-null without default value', function() {
      var self = this;
      var Users = self.sequelize.define('_Users', {
        username: {
          type: DataTypes.STRING,
          allowNull: false
        }
      }, { freezeTableName: true });

      return Users.sync({ force: true }).then(function() {
        return self.queryInterface.renameColumn('_Users', 'username', 'pseudo');
      });
    });

    it('rename a boolean column non-null without default value', function() {
      var self = this;
      var Users = self.sequelize.define('_Users', {
        active: {
          type: DataTypes.BOOLEAN,
          allowNull: false,
          defaultValue: false
        }
      }, { freezeTableName: true });

      return Users.sync({ force: true }).then(function() {
        return self.queryInterface.renameColumn('_Users', 'active', 'enabled');
      });
    });

    it('renames a column primary key autoIncrement column', function() {
      var self = this;
      var Fruits = self.sequelize.define('Fruit', {
        fruitId: {
          type: DataTypes.INTEGER,
          allowNull: false,
          primaryKey: true,
          autoIncrement: true
        }
      }, { freezeTableName: true });

      return Fruits.sync({ force: true }).then(function() {
        return self.queryInterface.renameColumn('Fruit', 'fruitId', 'fruit_id');
      });
    });
  });

  describe('changeColumn', function() {
    it('should support schemas', function() {
      return this.sequelize.dropAllSchemas().bind(this).then(function() {
        return this.sequelize.createSchema('archive');
      }).then(function() {
        return this.queryInterface.createTable({
          tableName: 'users',
          schema: 'archive'
        }, {
          id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true
          },
          currency: DataTypes.INTEGER
        }).bind(this).then(function() {
          return this.queryInterface.changeColumn({
            tableName: 'users',
            schema: 'archive'
          }, 'currency', {
            type: DataTypes.FLOAT
          }, {
            logging: log
          }).then(function() {
            expect(count).to.be.equal(1);
            count = 0;
          });
        });
      });
    });
  });

  describe('addColumn', function() {
    beforeEach(function() {
      return this.queryInterface.createTable('users', {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        }
      });
    });

    it('should be able to add a foreign key reference', function() {
      return this.queryInterface.createTable('level', {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        }
      }).bind(this).then(function() {
        return this.queryInterface.addColumn('users', 'level_id', {
          type: DataTypes.INTEGER,
          references: {
            model: 'level',
            key:   'id'
          },
          onUpdate: 'cascade',
          onDelete: 'set null'
        }, {logging: log});
      }).then(function() {
        expect(count).to.be.equal(1);
        count = 0;
      });
    });

    it('should work with schemas', function() {
      return this.queryInterface.createTable({
        tableName: 'users',
        schema: 'archive'
      }, {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        }
      }).bind(this).then(function() {
        return this.queryInterface.addColumn({
          tableName: 'users',
          schema: 'archive'
        }, 'level_id', {
          type: DataTypes.INTEGER
        });
      });
    });

    it('should work with enums (1)', function() {
      return this.queryInterface.addColumn('users', 'someEnum', DataTypes.ENUM('value1', 'value2', 'value3'));
    });

    it('should work with enums (2)', function() {
      return this.queryInterface.addColumn('users', 'someOtherEnum', {
        type: DataTypes.ENUM,
        values: ['value1', 'value2', 'value3']
      });
    });
  });

  describe('describeForeignKeys', function() {
    beforeEach(function() {
      return this.queryInterface.createTable('users', {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        }
      }).bind(this).then(function() {
        return this.queryInterface.createTable('hosts', {
          id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true
          },
          admin: {
            type: DataTypes.INTEGER,
            references: {
              model: 'users',
              key:   'id'
            }
          },
          operator: {
            type: DataTypes.INTEGER,
            references: {
              model: 'users',
              key:   'id'
            },
            onUpdate: 'cascade'
          },
          owner: {
            type: DataTypes.INTEGER,
            references: {
              model: 'users',
              key:   'id'
            },
            onUpdate: 'cascade',
            onDelete: 'set null'
          }
        });
      });
    });

    it('should get a list of foreign keys for the table', function() {
      var sql = this.queryInterface.QueryGenerator.getForeignKeysQuery('hosts', this.sequelize.config.database);

      return this.sequelize.query(sql, {type: this.sequelize.QueryTypes.FOREIGNKEYS, logging: log}).then(function(fks) {
        expect(count).to.be.equal(1);
        expect(fks).to.have.length(3);
        count = 0;
        var keys = Object.keys(fks[0]),
          keys2 = Object.keys(fks[1]),
          keys3 = Object.keys(fks[2]);

        if (dialect === 'postgres' || dialect === 'postgres-native') {
          expect(keys).to.have.length(6);
          expect(keys2).to.have.length(7);
          expect(keys3).to.have.length(7);
        } else if (dialect === 'sqlite') {
          expect(keys).to.have.length(8);
        } else if (dialect === 'mysql' || dialect === 'mssql') {
          expect(keys).to.have.length(1);
        } else {
          console.log('This test doesn\'t support ' + dialect);
        }
      });
    });
  });
});


stores[dialect][type] =  dataType.parse;

'use strict';

var Utils = require('../../utils')
  , AbstractQuery = require('../abstract/query')
  , sequelizeErrors = require('../../errors.js')
  , parserStore = require('../parserStore')('mssql');

var Query = function(connection, sequelize, options) {
  this.connection = connection;
  this.instance = options.instance;
  this.model = options.model;
  this.sequelize = sequelize;
  this.options = Utils._.extend({
    logging: console.log,
    plain: false,
    raw: false
  }, options || {});

  this.checkLoggingOption();
};

Utils.inherit(Query, AbstractQuery);

Query.prototype.getInsertIdField = function() {
  return 'id';
};

Query.formatBindParameters = AbstractQuery.formatBindParameters;
Query.prototype.run = function(sql, parameters) {
  var self = this;
  this.sql = sql;

  this.sequelize.log('Executing (' + (this.connection.uuid || 'default') + '): ' + this.sql, this.options);

  var promise = new Utils.Promise(function(resolve, reject) {
      // TRANSACTION SUPPORT
      if (Utils._.contains(self.sql, 'BEGIN TRANSACTION')) {
        self.connection.beginTransaction(function(err) {
          if (!!err) {
            reject(self.formatError(err));
          } else {
            resolve(self.formatResults());
          }
        } /* name, isolation_level */);
      } else if (Utils._.contains(self.sql, 'COMMIT TRANSACTION')) {
        self.connection.commitTransaction(function(err) {
          if (!!err) {
            reject(self.formatError(err));
          } else {
            resolve(self.formatResults());
          }
        });
      } else if (Utils._.contains(self.sql, 'ROLLBACK TRANSACTION')) {
        self.connection.rollbackTransaction(function(err) {
          if (!!err) {
            reject(self.formatError(err));
          } else {
            resolve(self.formatResults());
          }
        });
      } else {
        // QUERY SUPPORT
        var results = [];

        var request = new self.connection.lib.Request(self.sql, function(err) {
          if (err) {
            err.sql = sql;
            reject(self.formatError(err));
          } else {
            resolve(self.formatResults(results));
          }
        });

        request.on('row', function(columns) {
          var row = {};
          columns.forEach(function(column) {
            var typeid = column.metadata.type.id
              , value = column.value
              , parse = parserStore.get(typeid);

            if (value !== null & parse) {
              value = parse(value);
            }
            row[column.metadata.colName] = value;
          });

          results.push(row);
        });

        self.connection.execSql(request);
      }
  });

  return promise;
};

/**
 * High level function that handles the results of a query execution.
 *
 *
 * Example:
 *  query.formatResults([
 *    {
 *      id: 1,              // this is from the main table
 *      attr2: 'snafu',     // this is from the main table
 *      Tasks.id: 1,        // this is from the associated table
 *      Tasks.title: 'task' // this is from the associated table
 *    }
 *  ])
 *
 * @param {Array} data - The result of the query execution.
 */
Query.prototype.formatResults = function(data) {
  var result = this.instance;
  if (this.isInsertQuery(data)) {
    this.handleInsertQuery(data);

    if (!this.instance) {
      if (this.options.plain) {
        // NOTE: super contrived. This just passes the newly added query-interface
        //       test returning only the PK. There isn't a way in MSSQL to identify
        //       that a given return value is the PK, and we have no schema information
        //       because there was no calling Model.
        var record = data[0];
        result = record[Object.keys(record)[0]];
      } else {
        result = data;
      }
    }
  }

  if (this.isShowTablesQuery()) {
    result = this.handleShowTablesQuery(data);
  } else if (this.isDescribeQuery()) {
    result = {};
    data.forEach(function(_result) {
      if (_result.Default) {
        _result.Default = _result.Default.replace("('",'').replace("')",'').replace(/'/g,''); /* jshint ignore: line */
      }

      result[_result.Name] = {
        type: _result.Type.toUpperCase(),
        allowNull: (_result.IsNull === 'YES' ? true : false),
        defaultValue: _result.Default,
        primaryKey: _result.Constraint === 'PRIMARY KEY'
      };
    });
  } else if (this.isShowIndexesQuery()) {
    result = this.handleShowIndexesQuery(data);
  } else if (this.isSelectQuery()) {
    result = this.handleSelectQuery(data);
  } else if (this.isCallQuery()) {
    result = data[0];
  } else if (this.isBulkUpdateQuery()) {
    result = data.length;
  } else if (this.isBulkDeleteQuery()){
    result = data[0] && data[0].AFFECTEDROWS;
  } else if (this.isVersionQuery()) {
    result = data[0].version;
  } else if (this.isForeignKeysQuery()) {
    result = data;
  } else if (this.isRawQuery()) {
    // MSSQL returns row data and metadata (affected rows etc) in a single object - let's standarize it, sorta
    result = [data, data];
   }

  return result;
};

Query.prototype.handleShowTablesQuery = function(results) {
  return results.map(function(resultSet) {
    return {
      tableName: resultSet.TABLE_NAME,
      schema: resultSet.TABLE_SCHEMA
    };
  });
};

Query.prototype.formatError = function (err) {
  var match;
  match = err.message.match(/Violation of UNIQUE KEY constraint '((.|\s)*)'. Cannot insert duplicate key in object '.*'. The duplicate key value is \((.*)\)./);
  match = match || err.message.match(/Cannot insert duplicate key row in object .* with unique index '(.*)'/);
  if (match && match.length > 1) {
    var fields = {}
      , message = 'Validation error'
      , uniqueKey = this.model && this.model.uniqueKeys[match[1]];

    if (uniqueKey && !!uniqueKey.msg) {
      message = uniqueKey.msg;
    }
    if (!!match[2]) {
      var values = match[2].split(',').map(Function.prototype.call, String.prototype.trim);
      if (!!uniqueKey) {
        fields = Utils._.zipObject(uniqueKey.fields, values);
      } else {
        fields[match[1]] = match[2];
      }
    }

    var errors = [];
    var self = this;
    Utils._.forOwn(fields, function(value, field) {
      errors.push(new sequelizeErrors.ValidationErrorItem(
        self.getUniqueConstraintErrorMessage(field),
        'unique violation', field, value));
    });

    return new sequelizeErrors.UniqueConstraintError({
      message: message,
      errors: errors,
      parent: err,
      fields: fields
    });
  }

  match = err.message.match(/Failed on step '(.*)'.Could not create constraint. See previous errors./) ||
          err.message.match(/The DELETE statement conflicted with the REFERENCE constraint "(.*)". The conflict occurred in database "(.*)", table "(.*)", column '(.*)'./) ||
          err.message.match(/The INSERT statement conflicted with the FOREIGN KEY constraint "(.*)". The conflict occurred in database "(.*)", table "(.*)", column '(.*)'./) ||
          err.message.match(/The UPDATE statement conflicted with the FOREIGN KEY constraint "(.*)". The conflict occurred in database "(.*)", table "(.*)", column '(.*)'./);
  if (match && match.length > 0) {
    return new sequelizeErrors.ForeignKeyConstraintError({
      fields: null,
      index: match[1],
      parent: err
    });
  }

  return new sequelizeErrors.DatabaseError(err);
};

Query.prototype.isShowOrDescribeQuery = function() {
  var result = false;

  result = result || (this.sql.toLowerCase().indexOf("select c.column_name as 'name', c.data_type as 'type', c.is_nullable as 'isnull'") === 0); /* jshint ignore: line */
  result = result || (this.sql.toLowerCase().indexOf('select tablename = t.name, name = ind.name,') === 0);
  result = result || (this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0);

  return result;
};

Query.prototype.isShowIndexesQuery = function () {
  return this.sql.toLowerCase().indexOf('exec sys.sp_helpindex @objname') === 0;
};

Query.prototype.handleShowIndexesQuery = function (data) {
  // Group by index name, and collect all fields
  data = Utils._.foldl(data, function (acc, item) {
    if (!(item.index_name in acc)) {
      acc[item.index_name] = item;
      item.fields = [];
    }

    Utils._.forEach(item.index_keys.split(','), function(column) {
      var columnName = column.trim();
      if (columnName.indexOf('(-)') !== -1) {
        columnName = columnName.replace('(-)','');
      }

      acc[item.index_name].fields.push({
        attribute: columnName,
        length: undefined,
        order: (column.indexOf('(-)') !== -1 ? 'DESC' : 'ASC'),
        collate: undefined
      });
    });
    delete item.index_keys;
    return acc;
  }, {});

  return Utils._.map(data, function(item) {
    return {
      primary: (item.index_name.toLowerCase().indexOf('pk') === 0),
      fields: item.fields,
      name: item.index_name,
      tableName: undefined,
      unique: (item.index_description.toLowerCase().indexOf('unique') !== -1),
      type: undefined,
    };
  });
};

Query.prototype.handleInsertQuery = function(results, metaData) {
  if (this.instance) {
    // add the inserted row id to the instance
    var autoIncrementField = this.model.autoIncrementField
      , autoIncrementFieldAlias = null
      , id = null;

    if (this.model.rawAttributes.hasOwnProperty(autoIncrementField) &&
        this.model.rawAttributes[autoIncrementField].field !== undefined)
      autoIncrementFieldAlias = this.model.rawAttributes[autoIncrementField].field ;

    id = id || (results && results[0][this.getInsertIdField()]);
    id = id || (metaData && metaData[this.getInsertIdField()]);
    id = id || (results && results[0][autoIncrementField]);
    id = id || (autoIncrementFieldAlias && results && results[0][autoIncrementFieldAlias]);

    this.instance[autoIncrementField] = id;
  }
};

module.exports = Query;


test*.js
*.swp
.idea
.DS_STORE
node_modules
npm-debug.log
*~
test/binary/tmp/*
test/tmp/*
test/dialects/sqlite/test.sqlite
test/sqlite/test.sqlite
coverage-*
site


'use strict';

/* jshint -W030 */
var chai = require('chai')
  , sinon = require('sinon')
  , expect = chai.expect
  , Support = require(__dirname + '/support')
  , _ = require('lodash')
  , current = Support.sequelize
  , Promise = current.Promise;

describe(Support.getTestDialectTeaser('Hooks'), function() {
  beforeEach(function () {
    this.Model = current.define('m');
  });

  describe('callback', function () {
    // Legacy - remove at some point

    it('success', function () {
      this.Model.beforeCreate(function (attributes, options, fn) {
        fn();
      });

      return expect(this.Model.runHooks('beforeCreate', {}, {})).to.be.resolved;
    });

    it('error', function () {
      this.Model.beforeCreate(function (attributes, options, fn) {
        fn('No!');
      });

      return expect(this.Model.runHooks('beforeCreate', {}, {})).to.be.rejectedWith('No!');
    });
  });

  describe('arguments', function () {
    it('hooks can modify passed arguments', function () {
      this.Model.addHook('beforeCreate', function (options) {
        options.answer = 41;
      });

      var options = {};
      return this.Model.runHooks('beforeCreate', options).then(function () {
        expect(options.answer).to.equal(41);
      });
    });
  });

  describe('multiple hooks', function () {
    beforeEach(function () {
      this.hook1 = sinon.spy();
      this.hook2 = sinon.spy();
      this.hook3 = sinon.spy();
    });

    describe('runs all hooks on success', function () {
      afterEach(function () {
        expect(this.hook1).to.have.been.calledOnce;
        expect(this.hook2).to.have.been.calledOnce;
        expect(this.hook3).to.have.been.calledOnce;
      });

      it('using addHook', function () {
        this.Model.addHook('beforeCreate', this.hook1);
        this.Model.addHook('beforeCreate', this.hook2);
        this.Model.addHook('beforeCreate', this.hook3);

        return this.Model.runHooks('beforeCreate');
      });

      it('using function', function () {
        this.Model.beforeCreate(this.hook1);
        this.Model.beforeCreate(this.hook2);
        this.Model.beforeCreate(this.hook3);

        return this.Model.runHooks('beforeCreate');
      });

      it('using define', function () {
        return current.define('M', {}, {
          hooks: {
            beforeCreate: [this.hook1, this.hook2, this.hook3]
          }
        }).runHooks('beforeCreate');
      });

      it('using a mixture', function () {
        var Model = current.define('M', {}, {
          hooks: {
            beforeCreate: this.hook1
          }
        });
        Model.beforeCreate(this.hook2);
        Model.addHook('beforeCreate', this.hook3);

        return Model.runHooks('beforeCreate');
      });
    });

    it('stops execution when a hook throws', function () {
      this.Model.beforeCreate(function () {
        this.hook1();

        throw new Error('No!');
      }.bind(this));
      this.Model.beforeCreate(this.hook2);

      return expect(this.Model.runHooks('beforeCreate')).to.be.rejected.then(function () {
        expect(this.hook1).to.have.been.calledOnce;
        expect(this.hook2).not.to.have.been.called;
      }.bind(this));
    });

    it('stops execution when a hook rejects', function () {
      this.Model.beforeCreate(function () {
        this.hook1();

        return Promise.reject('No!');
      }.bind(this));
      this.Model.beforeCreate(this.hook2);

      return expect(this.Model.runHooks('beforeCreate')).to.be.rejected.then(function () {
        expect(this.hook1).to.have.been.calledOnce;
        expect(this.hook2).not.to.have.been.called;
      }.bind(this));
    });
  });

  describe('global hooks', function () {
    describe('using addHook', function () {

      it('invokes the global hook', function () {
        var globalHook = sinon.spy();

        current.addHook('beforeUpdate', globalHook);

        return this.Model.runHooks('beforeUpdate').then(function () {
          expect(globalHook).to.have.been.calledOnce;
        });
      });

      it('invokes the global hook, when the model also has a hook', function () {
        var globalHookBefore = sinon.spy()
          , globalHookAfter = sinon.spy()
          , localHook = sinon.spy();

        current.addHook('beforeUpdate', globalHookBefore);

        var Model = current.define('m', {}, {
          hooks: {
            beforeUpdate: localHook
          }
        });

        current.addHook('beforeUpdate', globalHookAfter);

        return Model.runHooks('beforeUpdate').then(function () {
          expect(globalHookBefore).to.have.been.calledOnce;
          expect(globalHookAfter).to.have.been.calledOnce;
          expect(localHook).to.have.been.calledOnce;

          expect(localHook).to.have.been.calledBefore(globalHookBefore);
          expect(localHook).to.have.been.calledBefore(globalHookAfter);
        });
      });
    });

    describe('using define hooks', function () {
      beforeEach(function () {
        this.beforeCreate = sinon.spy();
        this.sequelize = Support.createSequelizeInstance({
          define: {
            hooks: {
              beforeCreate: this.beforeCreate
            }
          }
        });
      });

      it('runs the global hook when no hook is passed', function () {
        var Model = this.sequelize.define('M', {}, {
          hooks: {
            beforeUpdate: _.noop // Just to make sure we can define other hooks without overwriting the global one
          }
        });

        return Model.runHooks('beforeCreate').bind(this).then(function () {
          expect(this.beforeCreate).to.have.been.calledOnce;
        });
      });

      it('does not run the global hook when the model specifies its own hook', function () {
        var localHook = sinon.spy()
          , Model = this.sequelize.define('M', {}, {
            hooks: {
              beforeCreate: localHook
            }
          });

        return Model.runHooks('beforeCreate').bind(this).then(function () {
          expect(this.beforeCreate).not.to.have.been.called;
          expect(localHook).to.have.been.calledOnce;
        });
      });
    });
  });

  describe('#removeHook', function() {
    it('should remove hook', function() {
      var hook1 = sinon.spy()
        , hook2 = sinon.spy();

      this.Model.addHook('beforeCreate', 'myHook', hook1);
      this.Model.beforeCreate('myHook2', hook2);

      return this.Model.runHooks('beforeCreate').bind(this).then(function() {
        expect(hook1).to.have.been.calledOnce;
        expect(hook2).to.have.been.calledOnce;

        hook1.reset();
        hook2.reset();

        this.Model.removeHook('beforeCreate', 'myHook');
        this.Model.removeHook('beforeCreate', 'myHook2');

        return this.Model.runHooks('beforeCreate');
      }).then(function() {
        expect(hook1).not.to.have.been.called;
        expect(hook2).not.to.have.been.called;
      });
    });
  });

  describe('#addHook', function() {
    it('should add additional hook when previous exists', function() {
      var hook1 = sinon.spy()
        , hook2 = sinon.spy()
        , Model;

      Model = this.sequelize.define('Model', {}, {
        hooks: { beforeCreate: hook1 }
      });

      Model.addHook('beforeCreate', hook2);

      return Model.runHooks('beforeCreate').then(function() {
        expect(hook1).to.have.been.calledOnce;
        expect(hook2).to.have.been.calledOnce;
      });
    });
  });

  describe('aliases', function() {
    beforeEach(function () {
      this.beforeDelete = sinon.spy();
      this.afterDelete = sinon.spy();
    });

    afterEach(function () {
      expect(this.beforeDelete).to.have.been.calledOnce;
      expect(this.afterDelete).to.have.been.calledOnce;
    });

    describe('direct method', function() {
      it('#delete', function() {
        this.Model.beforeDelete(this.beforeDelete);
        this.Model.afterDelete(this.afterDelete);

        return Promise.join(
          this.Model.runHooks('beforeDestroy'),
          this.Model.runHooks('afterDestroy')
        );
      });
    });

    describe('.hook() method', function() {
      it('#delete', function() {
        this.Model.hook('beforeDelete', this.beforeDelete);
        this.Model.hook('afterDelete', this.afterDelete);

        return Promise.join(
          this.Model.runHooks('beforeDestroy'),
          this.Model.runHooks('afterDestroy')
        );
      });
    });
  });

  describe('promises', function() {
    it('can return a promise', function() {
      var self = this;

      this.Model.beforeBulkCreate(function() {
        return self.sequelize.Promise.resolve();
      });

      return expect(this.Model.runHooks('beforeBulkCreate')).to.be.resolved;
    });

    it('can return undefined', function() {
      this.Model.beforeBulkCreate(function() {
        // This space intentionally left blank
      });

      return expect(this.Model.runHooks('beforeBulkCreate')).to.be.resolved;
    });

    it('can return an error by rejecting', function() {
      this.Model.beforeCreate(function() {
        return Promise.reject(new Error('Forbidden'));
      });

      return expect(this.Model.runHooks('beforeCreate')).to.be.rejectedWith('Forbidden');
    });

    it('can return an error by throwing', function() {
      this.Model.beforeCreate(function() {
        throw (new Error('Forbidden'));
      });

      return expect(this.Model.runHooks('beforeCreate')).to.be.rejectedWith('Forbidden');
    });
  });
});