mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 15:27:32 +09:00
Dactyloidae iOS initial commit
This commit is contained in:
parent
daa6179d22
commit
7154a0497e
2123 changed files with 197052 additions and 0 deletions
116
mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.h
vendored
Normal file
116
mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.h
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
File: UIImage+ImageEffects.h
|
||||
Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur.
|
||||
Version: 1.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
|
||||
Copyright © 2013 Apple Inc. All rights reserved.
|
||||
WWDC 2013 License
|
||||
|
||||
NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013
|
||||
Session. Please refer to the applicable WWDC 2013 Session for further
|
||||
information.
|
||||
|
||||
IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and
|
||||
your use, installation, modification or redistribution of this Apple
|
||||
software constitutes acceptance of these terms. If you do not agree with
|
||||
these terms, please do not use, install, modify or redistribute this
|
||||
Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple
|
||||
Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES
|
||||
NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
|
||||
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
EA1002
|
||||
5/3/2013
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
NOBLUR,
|
||||
BOXFILTER,
|
||||
TENTFILTER
|
||||
} BlurType;
|
||||
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@interface UIImage (ImageEffects)
|
||||
|
||||
- (UIImage *) applyLightEffect;
|
||||
- (UIImage *) applyExtraLightEffect;
|
||||
- (UIImage *) applyDarkEffect;
|
||||
- (UIImage *) applyDarkEffectWithTent: (CGFloat) radius;
|
||||
- (UIImage *) applyTintEffectWithColor:(UIColor *)tintColor;
|
||||
|
||||
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius blurType: (BlurType) blurType tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;
|
||||
|
||||
@end
|
||||
|
||||
288
mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.m
vendored
Normal file
288
mobile/ios/ThirdParty/Apple/UIImage+ImageEffects.m
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
File: UIImage+ImageEffects.m
|
||||
Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur.
|
||||
Version: 1.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
|
||||
|
||||
Copyright © 2013 Apple Inc. All rights reserved.
|
||||
WWDC 2013 License
|
||||
|
||||
NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013
|
||||
Session. Please refer to the applicable WWDC 2013 Session for further
|
||||
information.
|
||||
|
||||
IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and
|
||||
your use, installation, modification or redistribution of this Apple
|
||||
software constitutes acceptance of these terms. If you do not agree with
|
||||
these terms, please do not use, install, modify or redistribute this
|
||||
Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple
|
||||
Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES
|
||||
NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
|
||||
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
EA1002
|
||||
5/3/2013
|
||||
*/
|
||||
|
||||
#import "UIImage+ImageEffects.h"
|
||||
|
||||
@import Accelerate;
|
||||
#import <float.h>
|
||||
|
||||
|
||||
@implementation UIImage (ImageEffects)
|
||||
|
||||
|
||||
- (UIImage *)applyLightEffect
|
||||
{
|
||||
UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
|
||||
return [self applyBlurWithRadius:30 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
|
||||
- (UIImage *)applyExtraLightEffect
|
||||
{
|
||||
UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
|
||||
return [self applyBlurWithRadius:20 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
|
||||
- (UIImage *)applyDarkEffect
|
||||
{
|
||||
UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
|
||||
return [self applyBlurWithRadius:10 blurType: BOXFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *) applyDarkEffectWithTent: (CGFloat) radius
|
||||
{
|
||||
UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.5];
|
||||
return [self applyBlurWithRadius:radius blurType: TENTFILTER tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
|
||||
}
|
||||
|
||||
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
|
||||
{
|
||||
const CGFloat EffectColorAlpha = 0.6;
|
||||
UIColor *effectColor = tintColor;
|
||||
size_t componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
|
||||
if (componentCount == 2) {
|
||||
CGFloat b;
|
||||
if ([tintColor getWhite:&b alpha:NULL]) {
|
||||
effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
|
||||
}
|
||||
}
|
||||
else {
|
||||
CGFloat r, g, b;
|
||||
if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
|
||||
effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
|
||||
}
|
||||
}
|
||||
return [self applyBlurWithRadius:10 blurType: BOXFILTER tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
|
||||
}
|
||||
|
||||
|
||||
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius blurType: (BlurType) blurType tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
|
||||
{
|
||||
// Check pre-conditions.
|
||||
if (self.size.width < 1 || self.size.height < 1) {
|
||||
NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
|
||||
return nil;
|
||||
}
|
||||
if (!self.CGImage) {
|
||||
NSLog (@"*** error: image must be backed by a CGImage: %@", self);
|
||||
return nil;
|
||||
}
|
||||
if (maskImage && !maskImage.CGImage) {
|
||||
NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGRect imageRect = { CGPointZero, self.size };
|
||||
UIImage *effectImage = self;
|
||||
|
||||
BOOL hasBlur = blurRadius > __FLT_EPSILON__ && blurType != NOBLUR;
|
||||
BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
|
||||
if (hasBlur || hasSaturationChange) {
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef effectInContext = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(effectInContext, 1.0, -1.0);
|
||||
CGContextTranslateCTM(effectInContext, 0, -self.size.height);
|
||||
CGContextDrawImage(effectInContext, imageRect, self.CGImage);
|
||||
|
||||
vImage_Buffer effectInBuffer;
|
||||
effectInBuffer.data = CGBitmapContextGetData(effectInContext);
|
||||
effectInBuffer.width = CGBitmapContextGetWidth(effectInContext);
|
||||
effectInBuffer.height = CGBitmapContextGetHeight(effectInContext);
|
||||
effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
|
||||
vImage_Buffer effectOutBuffer;
|
||||
effectOutBuffer.data = CGBitmapContextGetData(effectOutContext);
|
||||
effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext);
|
||||
effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext);
|
||||
effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
|
||||
|
||||
if (hasBlur) {
|
||||
// A description of how to compute the box kernel width from the Gaussian
|
||||
// radius (aka standard deviation) appears in the SVG spec:
|
||||
// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
|
||||
//
|
||||
// For larger values of 's' (s >= 2.0), an approximation can be used: Three
|
||||
// successive box-blurs build a piece-wise quadratic convolution kernel, which
|
||||
// approximates the Gaussian kernel to within roughly 3%.
|
||||
//
|
||||
// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
|
||||
//
|
||||
// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
|
||||
//
|
||||
CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
|
||||
uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
|
||||
if (radius % 2 != 1) {
|
||||
radius += 1; // force radius to be odd so that the three box-blur methodology works.
|
||||
}
|
||||
|
||||
if (blurType == BOXFILTER)
|
||||
{
|
||||
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
|
||||
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
|
||||
}
|
||||
else
|
||||
{
|
||||
vImageTentConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
|
||||
}
|
||||
}
|
||||
BOOL effectImageBuffersAreSwapped = NO;
|
||||
if (hasSaturationChange) {
|
||||
CGFloat s = saturationDeltaFactor;
|
||||
CGFloat floatingPointSaturationMatrix[] = {
|
||||
0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
|
||||
0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
|
||||
0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
const int32_t divisor = 256;
|
||||
NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
|
||||
int16_t saturationMatrix[matrixSize];
|
||||
for (NSUInteger i = 0; i < matrixSize; ++i) {
|
||||
saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
|
||||
}
|
||||
if (hasBlur) {
|
||||
vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
|
||||
effectImageBuffersAreSwapped = YES;
|
||||
}
|
||||
else {
|
||||
vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
|
||||
}
|
||||
}
|
||||
if (!effectImageBuffersAreSwapped)
|
||||
effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
if (effectImageBuffersAreSwapped)
|
||||
effectImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
// Set up output context.
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
|
||||
CGContextRef outputContext = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(outputContext, 1.0, -1.0);
|
||||
CGContextTranslateCTM(outputContext, 0, -self.size.height);
|
||||
|
||||
// Draw effect image.
|
||||
if (hasBlur) {
|
||||
CGContextSaveGState(outputContext);
|
||||
if (maskImage) {
|
||||
CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
|
||||
}
|
||||
CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
|
||||
CGContextRestoreGState(outputContext);
|
||||
}
|
||||
|
||||
// Add in color tint.
|
||||
if (tintColor) {
|
||||
CGContextSaveGState(outputContext);
|
||||
CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
|
||||
CGContextFillRect(outputContext, imageRect);
|
||||
CGContextRestoreGState(outputContext);
|
||||
}
|
||||
|
||||
// Output image is ready.
|
||||
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return outputImage;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
33
mobile/ios/ThirdParty/Box/Box.swift
vendored
Normal file
33
mobile/ios/ThirdParty/Box/Box.swift
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
||||
|
||||
/// Wraps a type `T` in a reference type.
|
||||
///
|
||||
/// Typically this is used to work around limitations of value types (for example, the lack of codegen for recursive value types and type-parameterized enums with >1 case). It is also useful for sharing a single (presumably large) value without copying it.
|
||||
public final class Box<T>: BoxType, CustomStringConvertible {
|
||||
/// Initializes a `Box` with the given value.
|
||||
public init(_ value: T) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
|
||||
/// Constructs a `Box` with the given `value`.
|
||||
public class func unit(_ value: T) -> Box<T> {
|
||||
return Box(value)
|
||||
}
|
||||
|
||||
|
||||
/// The (immutable) value wrapped by the receiver.
|
||||
public let value: T
|
||||
|
||||
/// Constructs a new Box by transforming `value` by `f`.
|
||||
public func map<U>(_ f: (T) -> U) -> Box<U> {
|
||||
return Box<U>(f(value))
|
||||
}
|
||||
|
||||
|
||||
// MARK: Printable
|
||||
|
||||
public var description: String {
|
||||
return String(describing: value)
|
||||
}
|
||||
}
|
||||
46
mobile/ios/ThirdParty/Box/BoxType.swift
vendored
Normal file
46
mobile/ios/ThirdParty/Box/BoxType.swift
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
||||
|
||||
// MARK: BoxType
|
||||
|
||||
/// The type conformed to by all boxes.
|
||||
public protocol BoxType {
|
||||
/// The type of the wrapped value.
|
||||
associatedtype Value
|
||||
|
||||
/// Initializes an intance of the type with a value.
|
||||
init(_ value: Value)
|
||||
|
||||
/// The wrapped value.
|
||||
var value: Value { get }
|
||||
}
|
||||
|
||||
/// The type conformed to by mutable boxes.
|
||||
public protocol MutableBoxType: BoxType {
|
||||
/// The (mutable) wrapped value.
|
||||
var value: Value { get set }
|
||||
}
|
||||
|
||||
|
||||
// MARK: Equality
|
||||
|
||||
/// Equality of `BoxType`s of `Equatable` types.
|
||||
///
|
||||
/// We cannot declare that e.g. `Box<T: Equatable>` conforms to `Equatable`, so this is a relatively ad hoc definition.
|
||||
public func == <B: BoxType> (lhs: B, rhs: B) -> Bool where B.Value: Equatable {
|
||||
return lhs.value == rhs.value
|
||||
}
|
||||
|
||||
/// Inequality of `BoxType`s of `Equatable` types.
|
||||
///
|
||||
/// We cannot declare that e.g. `Box<T: Equatable>` conforms to `Equatable`, so this is a relatively ad hoc definition.
|
||||
public func != <B: BoxType> (lhs: B, rhs: B) -> Bool where B.Value: Equatable {
|
||||
return lhs.value != rhs.value
|
||||
}
|
||||
|
||||
|
||||
// MARK: Map
|
||||
|
||||
/// Maps the value of a box into a new box.
|
||||
public func map<B: BoxType, C: BoxType>(_ v: B, f: (B.Value) -> C.Value) -> C {
|
||||
return C(f(v.value))
|
||||
}
|
||||
21
mobile/ios/ThirdParty/Box/LICENSE
vendored
Normal file
21
mobile/ios/ThirdParty/Box/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Rob Rix
|
||||
|
||||
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.
|
||||
27
mobile/ios/ThirdParty/Box/MutableBox.swift
vendored
Normal file
27
mobile/ios/ThirdParty/Box/MutableBox.swift
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
||||
|
||||
/// Wraps a type `T` in a mutable reference type.
|
||||
///
|
||||
/// While this, like `Box<T>` could be used to work around limitations of value types, it is much more useful for sharing a single mutable value such that mutations are shared.
|
||||
///
|
||||
/// As with all mutable state, this should be used carefully, for example as an optimization, rather than a default design choice. Most of the time, `Box<T>` will suffice where any `BoxType` is needed.
|
||||
public final class MutableBox<T>: MutableBoxType, CustomStringConvertible {
|
||||
/// Initializes a `MutableBox` with the given value.
|
||||
public init(_ value: T) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// The (mutable) value wrapped by the receiver.
|
||||
public var value: T
|
||||
|
||||
/// Constructs a new MutableBox by transforming `value` by `f`.
|
||||
public func map<U>(_ f: (T) -> U) -> MutableBox<U> {
|
||||
return MutableBox<U>(f(value))
|
||||
}
|
||||
|
||||
// MARK: Printable
|
||||
|
||||
public var description: String {
|
||||
return String(describing: value)
|
||||
}
|
||||
}
|
||||
58
mobile/ios/ThirdParty/Box/README.md
vendored
Normal file
58
mobile/ios/ThirdParty/Box/README.md
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# Box
|
||||
|
||||
This is a Swift microframework which implements `Box<T>` & `MutableBox<T>`, with implementations of `==`/`!=` where `T`: `Equatable`.
|
||||
|
||||
`Box` is typically used to work around limitations of value types:
|
||||
|
||||
- recursive `struct`s/`enum`s
|
||||
- type-parameterized `enum`s where more than one `case` has a value
|
||||
|
||||
## Use
|
||||
|
||||
Wrapping & unwrapping a `Box`:
|
||||
|
||||
```swift
|
||||
// Wrap:
|
||||
let box = Box(1)
|
||||
|
||||
// Unwrap:
|
||||
let value = box.value
|
||||
```
|
||||
|
||||
Changing the value of a `MutableBox`:
|
||||
|
||||
```swift
|
||||
// Mutation:
|
||||
let mutableBox = MutableBox(1)
|
||||
mutableBox.value = 2
|
||||
```
|
||||
|
||||
Building a recursive value type:
|
||||
|
||||
```swift
|
||||
struct BinaryTree {
|
||||
let value: Int
|
||||
let left: Box<BinaryTree>?
|
||||
let right: Box<BinaryTree>?
|
||||
}
|
||||
```
|
||||
|
||||
Building a parameterized `enum`:
|
||||
|
||||
```swift
|
||||
enum Result<T> {
|
||||
case Success(Box<T>)
|
||||
case Failure(NSError)
|
||||
}
|
||||
```
|
||||
|
||||
See the sources for more details.
|
||||
|
||||
## Integration
|
||||
|
||||
1. Add this repo as a submodule in e.g. `External/Box`:
|
||||
|
||||
git submodule add https://github.com/robrix/Box.git External/Box
|
||||
2. Drag `Box.xcodeproj` into your `.xcworkspace`/`.xcodeproj`.
|
||||
3. Add `Box.framework` to your target’s `Link Binary With Libraries` build phase.
|
||||
4. You may also want to add a `Copy Files` phase which copies `Box.framework` (and any other framework dependencies you need) into your bundle’s `Frameworks` directory. If your target is a framework, you may instead want the client app to include `Box.framework`.
|
||||
BIN
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/BuddyBuildSDK
vendored
Normal file
BIN
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/BuddyBuildSDK
vendored
Normal file
Binary file not shown.
147
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/Headers/BuddyBuildSDK.h
vendored
Normal file
147
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/Headers/BuddyBuildSDK.h
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright (c) 2015 Doe Pics Hit, Inc. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIApplication.h>
|
||||
|
||||
typedef NSString*(^BBReturnNSStringCallback)();
|
||||
typedef BOOL (^BBReturnBooleanCallback)();
|
||||
typedef void (^BBCallback)();
|
||||
|
||||
@interface BuddyBuildSDK : NSObject
|
||||
|
||||
// Deprecated
|
||||
+ (void)setup:(id<UIApplicationDelegate>)bbAppDelegate;
|
||||
|
||||
/**
|
||||
* Initialize the SDK
|
||||
*
|
||||
* This should be called at (or near) the start of the appdelegate
|
||||
*/
|
||||
+ (void)setup;
|
||||
|
||||
/*
|
||||
* Associate arbitrary key/value pairs with your crash reports
|
||||
* which will be visible from the buddybuild dashboard
|
||||
*/
|
||||
+ (void) setCrashMetadataObject:(id)object forKey:(NSString*)key;
|
||||
|
||||
/*
|
||||
* Programatically trigger the screenshot feedback UI without pressing the screenshot buttons
|
||||
* If you have screenshot feedback disabled through the buddybuild setting,
|
||||
* you can still trigger it by calling this method
|
||||
*/
|
||||
|
||||
+ (void)takeScreenshotAndShowFeedbackScreen;
|
||||
|
||||
/*
|
||||
* If you distribute a build to someone with their email address, buddybuild can
|
||||
* figure out who they are and attach their info to feedback and crash reports.
|
||||
*
|
||||
* However, if you send out a build to a mailing list, or through TestFlight or
|
||||
* the App Store we are unable to infer who they are. If you see 'Unknown User'
|
||||
* this is likely the cause.
|
||||
|
||||
* Often you'll know the identity of your user, for example, after they've
|
||||
* logged in. You can provide buddybuild a callback to identify the current user.
|
||||
*/
|
||||
|
||||
+ (void)setUserDisplayNameCallback:(BBReturnNSStringCallback)bbCallback;
|
||||
|
||||
/*
|
||||
* You might have API keys and other secrets that your app needs to consume.
|
||||
* However, you may not want to check these secrets into the source code.
|
||||
*
|
||||
* You can provide your secrets to buddybuild. Buddybuild can then expose them
|
||||
* to you at build time through environment variables. These secrets can also be
|
||||
* configured to be included into built app. We obfuscate the device keys to
|
||||
* prevent unauthorized access.
|
||||
*/
|
||||
+ (NSString*)valueForDeviceKey:(NSString*)bbKey;
|
||||
|
||||
/*
|
||||
* To temporarily disable screenshot interception you can provide a callback
|
||||
* here.
|
||||
*
|
||||
* When screenshotting is turned on through a buddybuild setting, and no
|
||||
* callback is provided then screenshotting is by default on.
|
||||
*
|
||||
* If screenshotting is disabled through the buddybuild setting, then this
|
||||
* callback has no effect
|
||||
*
|
||||
*/
|
||||
+ (void)setScreenshotAllowedCallback:(BBReturnBooleanCallback)bbCallback;
|
||||
|
||||
/*
|
||||
* Once a piece of feedback is sent this callback will be called
|
||||
* so you can take additional actions if necessary
|
||||
*/
|
||||
+ (void)setScreenshotFeedbackSentCallback:(BBCallback)bbCallback;
|
||||
|
||||
/*
|
||||
* Once a crash report is sent this callback will be called
|
||||
* so you can take additional actions if necessary
|
||||
*/
|
||||
+ (void)setCrashReportSentCallback:(BBCallback)bbCallback;
|
||||
|
||||
/*
|
||||
* Buddybuild Build Number
|
||||
*/
|
||||
+ (NSString*)buildNumber;
|
||||
|
||||
/*
|
||||
* Scheme
|
||||
*/
|
||||
+ (NSString*)scheme;
|
||||
|
||||
/*
|
||||
* App ID
|
||||
*/
|
||||
+ (NSString*)appID;
|
||||
|
||||
/*
|
||||
* Build ID
|
||||
*/
|
||||
+ (NSString*)buildID;
|
||||
|
||||
/*
|
||||
* Build Configuration
|
||||
*/
|
||||
|
||||
+ (NSString*)buildConfiguration;
|
||||
|
||||
/*
|
||||
* Branch name for this build
|
||||
*/
|
||||
|
||||
+ (NSString*)branchName;
|
||||
|
||||
/*
|
||||
* Returns the user's email or more specifically, the email that was used to download and deploy the build.
|
||||
* Returns "Unknown User" in cases where buddybuild is unable to identify the user.
|
||||
* This is the same email seen in crash instances and feedbacks in the dashboard
|
||||
* NOTE: To be called after [BuddyBuildSDK setup]
|
||||
* this is different than the one returned in the user display name callback.
|
||||
*/
|
||||
+ (NSString*)userEmail;
|
||||
|
||||
/* Manually invoke the screenshot tutorial
|
||||
* If you don't want it to appear on app launch, disable it in the
|
||||
* dashboard by going to settings -> buddybuildSDK -> Feature Settings and turning off the screenshot tutorial
|
||||
* You will be able to show it at any time from anywhere in your app
|
||||
*/
|
||||
+ (void) showScreenshotTutorial;
|
||||
|
||||
|
||||
+(void) crash;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIView (BuddyBuildSDK)
|
||||
|
||||
// Certain features of buddybuild involve capturing the screen (either through a static screenshot, or as a video for instant replays in crash reporting or video feedback.
|
||||
// Your app may contain certain sensitive customer information that you do not want to be included in the video.
|
||||
// If you set this property to be true, this view will be redacted from the screen capture and blacked out
|
||||
|
||||
@property (nonatomic, assign) BOOL buddybuildViewIsPrivate;
|
||||
|
||||
@end
|
||||
1
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/build.num
vendored
Normal file
1
mobile/ios/ThirdParty/BuddyBuild/BuddyBuildSDK.framework/build.num
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
d1039cf
|
||||
137
mobile/ios/ThirdParty/FilledPageControl.swift
vendored
Normal file
137
mobile/ios/ThirdParty/FilledPageControl.swift
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// FilledPageControl
|
||||
//
|
||||
// Copyright (c) 2016 Kyle Zaragoza <popwarsweet@gmail.com>
|
||||
// MIT License
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable open class FilledPageControl: UIView {
|
||||
|
||||
// MARK: - PageControl
|
||||
|
||||
@IBInspectable open var pageCount: Int = 0 {
|
||||
didSet {
|
||||
updateNumberOfPages(pageCount)
|
||||
}
|
||||
}
|
||||
@IBInspectable open var progress: CGFloat = 0 {
|
||||
didSet {
|
||||
updateActivePageIndicatorMasks(progress)
|
||||
}
|
||||
}
|
||||
open var currentPage: Int {
|
||||
return Int(round(progress))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Appearance
|
||||
|
||||
override open var tintColor: UIColor! {
|
||||
didSet {
|
||||
inactiveLayers.forEach() { $0.backgroundColor = tintColor.cgColor }
|
||||
}
|
||||
}
|
||||
@IBInspectable open var inactiveRingWidth: CGFloat = 1 {
|
||||
didSet {
|
||||
updateActivePageIndicatorMasks(progress)
|
||||
}
|
||||
}
|
||||
@IBInspectable open var indicatorPadding: CGFloat = 10 {
|
||||
didSet {
|
||||
layoutPageIndicators(inactiveLayers)
|
||||
}
|
||||
}
|
||||
@IBInspectable open var indicatorRadius: CGFloat = 5 {
|
||||
didSet {
|
||||
layoutPageIndicators(inactiveLayers)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var indicatorDiameter: CGFloat {
|
||||
return indicatorRadius * 2
|
||||
}
|
||||
fileprivate var inactiveLayers = [CALayer]()
|
||||
|
||||
|
||||
// MARK: - State Update
|
||||
|
||||
fileprivate func updateNumberOfPages(_ count: Int) {
|
||||
// no need to update
|
||||
guard count != inactiveLayers.count else { return }
|
||||
// reset current layout
|
||||
inactiveLayers.forEach() { $0.removeFromSuperlayer() }
|
||||
inactiveLayers = [CALayer]()
|
||||
// add layers for new page count
|
||||
inactiveLayers = stride(from: 0, to:count, by:1).map() { _ in
|
||||
let layer = CALayer()
|
||||
layer.backgroundColor = self.tintColor.cgColor
|
||||
self.layer.addSublayer(layer)
|
||||
return layer
|
||||
}
|
||||
layoutPageIndicators(inactiveLayers)
|
||||
updateActivePageIndicatorMasks(progress)
|
||||
self.invalidateIntrinsicContentSize()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Layout
|
||||
|
||||
fileprivate func updateActivePageIndicatorMasks(_ progress: CGFloat) {
|
||||
// ignore if progress is outside of page indicators' bounds
|
||||
guard progress >= 0 && progress <= CGFloat(pageCount - 1) else { return }
|
||||
|
||||
// mask rect w/ default stroke width
|
||||
let insetRect = CGRect(x: 0, y: 0, width: indicatorDiameter, height: indicatorDiameter).insetBy(dx: inactiveRingWidth, dy: inactiveRingWidth)
|
||||
let leftPageFloat = trunc(progress)
|
||||
let leftPageInt = Int(progress)
|
||||
|
||||
// inset right moving page indicator
|
||||
let spaceToMove = insetRect.width / 2
|
||||
let percentPastLeftIndicator = progress - leftPageFloat
|
||||
let additionalSpaceToInsetRight = spaceToMove * percentPastLeftIndicator
|
||||
let closestRightInsetRect = insetRect.insetBy(dx: additionalSpaceToInsetRight, dy: additionalSpaceToInsetRight)
|
||||
|
||||
// inset left moving page indicator
|
||||
let additionalSpaceToInsetLeft = (1 - percentPastLeftIndicator) * spaceToMove
|
||||
let closestLeftInsetRect = insetRect.insetBy(dx: additionalSpaceToInsetLeft, dy: additionalSpaceToInsetLeft)
|
||||
|
||||
// adjust masks
|
||||
for (idx, layer) in inactiveLayers.enumerated() {
|
||||
let maskLayer = CAShapeLayer()
|
||||
maskLayer.fillRule = kCAFillRuleEvenOdd
|
||||
|
||||
let boundsPath = UIBezierPath(rect: layer.bounds)
|
||||
let circlePath: UIBezierPath
|
||||
if leftPageInt == idx {
|
||||
circlePath = UIBezierPath(ovalIn: closestLeftInsetRect)
|
||||
} else if leftPageInt + 1 == idx {
|
||||
circlePath = UIBezierPath(ovalIn: closestRightInsetRect)
|
||||
} else {
|
||||
circlePath = UIBezierPath(ovalIn: insetRect)
|
||||
}
|
||||
boundsPath.append(circlePath)
|
||||
maskLayer.path = boundsPath.cgPath
|
||||
layer.mask = maskLayer
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func layoutPageIndicators(_ layers: [CALayer]) {
|
||||
let layerDiameter = indicatorRadius * 2
|
||||
var layerFrame = CGRect(x: 0, y: 0, width: layerDiameter, height: layerDiameter)
|
||||
layers.forEach() { layer in
|
||||
layer.cornerRadius = self.indicatorRadius
|
||||
layer.frame = layerFrame
|
||||
layerFrame.origin.x += layerDiameter + indicatorPadding
|
||||
}
|
||||
}
|
||||
|
||||
override open var intrinsicContentSize: CGSize {
|
||||
return sizeThatFits(CGSize.zero)
|
||||
}
|
||||
|
||||
override open func sizeThatFits(_ size: CGSize) -> CGSize {
|
||||
let layerDiameter = indicatorRadius * 2
|
||||
return CGSize(width: CGFloat(inactiveLayers.count) * layerDiameter + CGFloat(inactiveLayers.count - 1) * indicatorPadding,
|
||||
height: layerDiameter)
|
||||
}
|
||||
}
|
||||
193
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/LPInbox.h
vendored
Normal file
193
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/LPInbox.h
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
//
|
||||
// LPInbox.h
|
||||
// Leanplum
|
||||
//
|
||||
// Created by Aleksandar Gyorev on 05/08/15.
|
||||
// Copyright (c) 2015 Leanplum, Inc. All rights reserved.
|
||||
//
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma mark - LPInboxMessage interface
|
||||
|
||||
@interface LPInboxMessage : NSObject <NSCoding>
|
||||
|
||||
#pragma mark - LPInboxMessage methods
|
||||
|
||||
/**
|
||||
* Returns the message identifier of the inbox message.
|
||||
*/
|
||||
- (NSString *)messageId;
|
||||
|
||||
/**
|
||||
* Returns the title of the inbox message.
|
||||
*/
|
||||
- (NSString *)title;
|
||||
|
||||
/**
|
||||
* Returns the subtitle of the inbox message.
|
||||
*/
|
||||
- (NSString *)subtitle;
|
||||
|
||||
/**
|
||||
* Returns the image path of the inbox message. Can be nil.
|
||||
* Use with [UIImage contentsOfFile:].
|
||||
*/
|
||||
- (NSString *)imageFilePath;
|
||||
|
||||
/**
|
||||
* Returns the image URL of the inbox message.
|
||||
* You can safely use this with prefetching enabled.
|
||||
* It will return the file URL path instead if the image is in cache.
|
||||
*/
|
||||
- (NSURL *)imageURL;
|
||||
|
||||
/**
|
||||
* Returns the data of the inbox message. Advanced use only.
|
||||
*/
|
||||
- (NSDictionary *)data;
|
||||
|
||||
/**
|
||||
* Returns the delivery timestamp of the inbox message.
|
||||
*/
|
||||
- (NSDate *)deliveryTimestamp;
|
||||
|
||||
/**
|
||||
* Return the expiration timestamp of the inbox message.
|
||||
*/
|
||||
- (NSDate *)expirationTimestamp;
|
||||
|
||||
/**
|
||||
* Returns YES if the inbox message is read.
|
||||
*/
|
||||
- (BOOL)isRead;
|
||||
|
||||
/**
|
||||
* Read the inbox message, marking it as read and invoking its open action.
|
||||
*/
|
||||
- (void)read;
|
||||
|
||||
/**
|
||||
* Remove the inbox message from the inbox.
|
||||
*/
|
||||
- (void)remove;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - LPInbox interface
|
||||
|
||||
/**
|
||||
* This block is used when you define a callback.
|
||||
*/
|
||||
typedef void (^LeanplumInboxChangedBlock)(void);
|
||||
typedef void (^LeanplumInboxSyncedBlock)(BOOL success);
|
||||
|
||||
@interface LPInbox : NSObject
|
||||
|
||||
#pragma mark - LPInbox methods
|
||||
|
||||
/**
|
||||
* Returns the number of all inbox messages on the device.
|
||||
*/
|
||||
- (NSUInteger)count;
|
||||
|
||||
/**
|
||||
* Returns the number of the unread inbox messages on the device.
|
||||
*/
|
||||
- (NSUInteger)unreadCount;
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all inbox messages on the device sorted in ascending
|
||||
* chronological order, i.e. the id of the oldest message is the first one, and the most
|
||||
* recent one is the last one in the array.
|
||||
*/
|
||||
- (NSArray *)messagesIds;
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the inbox messages (as LPInboxMessage objects)
|
||||
* on the device, sorted in ascending chronological order, i.e. the oldest message is the
|
||||
* first one, and the most recent one is the last one in the array.
|
||||
*/
|
||||
- (NSArray *)allMessages;
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the unread inbox messages on the device, sorted
|
||||
* in ascending chronological order, i.e. the oldest message is the first one, and the
|
||||
* most recent one is the last one in the array.
|
||||
*/
|
||||
- (NSArray *)unreadMessages;
|
||||
|
||||
/**
|
||||
* Returns the inbox messages associated with the given messageId identifier.
|
||||
*/
|
||||
- (LPInboxMessage *)messageForId:(NSString *)messageId;
|
||||
|
||||
/**
|
||||
* Call this method if you don't want Inbox images to be prefetched.
|
||||
* Useful if you only want to deal with image URL.
|
||||
*/
|
||||
- (void)disableImagePrefetching;
|
||||
|
||||
/**
|
||||
* Block to call when the inbox receive new values from the server.
|
||||
* This will be called on start, and also later on if the user is in an experiment
|
||||
* that can update in realtime.
|
||||
*/
|
||||
- (void)onChanged:(LeanplumInboxChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Block to call when forceContentUpdate was called.
|
||||
* Returns true if syncing was successful.
|
||||
* Note: use onChanged: for UI.
|
||||
*/
|
||||
- (void)onForceContentUpdate:(LeanplumInboxSyncedBlock)block;
|
||||
|
||||
/**
|
||||
@{
|
||||
* Adds a responder to be executed when an event happens.
|
||||
* Uses NSInvocation instead of blocks.
|
||||
* @see [Leanplum onStartResponse:]
|
||||
*/
|
||||
- (void)addInboxChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
- (void)removeInboxChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
/**@}*/
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - LPNewsfeed for backwards compatibility
|
||||
@interface LPNewsfeedMessage : LPInboxMessage
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^LeanplumNewsfeedChangedBlock)(void);
|
||||
|
||||
@interface LPNewsfeed : NSObject
|
||||
|
||||
+ (LPNewsfeed *)sharedState;
|
||||
- (NSUInteger)count;
|
||||
- (NSUInteger)unreadCount;
|
||||
- (NSArray *)messagesIds;
|
||||
- (NSArray *)allMessages;
|
||||
- (NSArray *)unreadMessages;
|
||||
- (void)onChanged:(LeanplumNewsfeedChangedBlock)block;
|
||||
- (LPNewsfeedMessage *)messageForId:(NSString *)messageId;
|
||||
- (void)addNewsfeedChangedResponder:(id)responder withSelector:(SEL)selector __attribute__((deprecated));
|
||||
- (void)removeNewsfeedChangedResponder:(id)responder withSelector:(SEL)selector __attribute__((deprecated));
|
||||
|
||||
@end
|
||||
929
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/Leanplum.h
vendored
Normal file
929
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Headers/Leanplum.h
vendored
Normal file
|
|
@ -0,0 +1,929 @@
|
|||
//
|
||||
// Leanplum.h
|
||||
// Leanplum iOS SDK Version 2.0.4
|
||||
//
|
||||
// Copyright (c) 2012 Leanplum, Inc. All rights reserved.
|
||||
//
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "LPInbox.h"
|
||||
|
||||
#ifndef LP_NOT_TV
|
||||
#define LP_NOT_TV (!defined(TARGET_OS_TV) || !TARGET_OS_TV)
|
||||
#endif
|
||||
|
||||
#define _LP_DEFINE_HELPER(name,val,type) LPVar* name; \
|
||||
static void __attribute__((constructor)) initialize_##name() { \
|
||||
@autoreleasepool { \
|
||||
name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] with##type:val]; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup Macros Variable Macros
|
||||
* Use these macros to define variables inside your app.
|
||||
* Underscores within variable names will nest variables within groups.
|
||||
* To define variables in a more custom way, copy and modify
|
||||
* the template above in your own code.
|
||||
* @see LPVar
|
||||
* @{
|
||||
*/
|
||||
#define DEFINE_VAR_INT(name,val) _LP_DEFINE_HELPER(name, val, Int)
|
||||
#define DEFINE_VAR_BOOL(name,val) _LP_DEFINE_HELPER(name, val, Bool)
|
||||
#define DEFINE_VAR_STRING(name,val) _LP_DEFINE_HELPER(name, val, String)
|
||||
#define DEFINE_VAR_NUMBER(name,val) _LP_DEFINE_HELPER(name, val, Number)
|
||||
#define DEFINE_VAR_FLOAT(name,val) _LP_DEFINE_HELPER(name, val, Float)
|
||||
#define DEFINE_VAR_CGFLOAT(name,val) _LP_DEFINE_HELPER(name, val, CGFloat)
|
||||
#define DEFINE_VAR_DOUBLE(name,val) _LP_DEFINE_HELPER(name, val, Double)
|
||||
#define DEFINE_VAR_SHORT(name,val) _LP_DEFINE_HELPER(name, val, Short)
|
||||
#define DEFINE_VAR_LONG(name,val) _LP_DEFINE_HELPER(name, val, Long)
|
||||
#define DEFINE_VAR_CHAR(name,val) _LP_DEFINE_HELPER(name, val, Char)
|
||||
#define DEFINE_VAR_LONG_LONG(name,val) _LP_DEFINE_HELPER(name, val, LongLong)
|
||||
#define DEFINE_VAR_INTEGER(name,val) _LP_DEFINE_HELPER(name, val, Integer)
|
||||
#define DEFINE_VAR_UINT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInt)
|
||||
#define DEFINE_VAR_UCHAR(name,val) _LP_DEFINE_HELPER(name, val, UnsignedChar)
|
||||
#define DEFINE_VAR_ULONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLong)
|
||||
#define DEFINE_VAR_UINTEGER(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInteger)
|
||||
#define DEFINE_VAR_USHORT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedShort)
|
||||
#define DEFINE_VAR_ULONGLONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLongLong)
|
||||
#define DEFINE_VAR_UNSIGNED_INT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInt)
|
||||
#define DEFINE_VAR_UNSIGNED_INTEGER(name,val) _LP_DEFINE_HELPER(name, val, UnsignedInteger)
|
||||
#define DEFINE_VAR_UNSIGNED_CHAR(name,val) _LP_DEFINE_HELPER(name, val, UnsignedChar)
|
||||
#define DEFINE_VAR_UNSIGNED_LONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLong)
|
||||
#define DEFINE_VAR_UNSIGNED_LONG_LONG(name,val) _LP_DEFINE_HELPER(name, val, UnsignedLongLong)
|
||||
#define DEFINE_VAR_UNSIGNED_SHORT(name,val) _LP_DEFINE_HELPER(name, val, UnsignedShort)
|
||||
#define DEFINE_VAR_FILE(name,filename) _LP_DEFINE_HELPER(name, filename, File)
|
||||
#define DEFINE_VAR_DICTIONARY(name,dict) _LP_DEFINE_HELPER(name, dict, Dictionary)
|
||||
#define DEFINE_VAR_ARRAY(name,array) _LP_DEFINE_HELPER(name, array, Array)
|
||||
#define DEFINE_VAR_COLOR(name,val) _LP_DEFINE_HELPER(name, val, Color)
|
||||
|
||||
#define DEFINE_VAR_DICTIONARY_WITH_OBJECTS_AND_KEYS(name,...) LPVar* name; \
|
||||
static void __attribute__((constructor)) initialize_##name() { \
|
||||
@autoreleasepool { \
|
||||
name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] withDictionary:[NSDictionary dictionaryWithObjectsAndKeys:__VA_ARGS__]]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_VAR_ARRAY_WITH_OBJECTS(name,...) LPVar* name; \
|
||||
static void __attribute__((constructor)) initialize_##name() { \
|
||||
@autoreleasepool { \
|
||||
name = [LPVar define:[@#name stringByReplacingOccurrencesOfString:@"_" withString:@"."] withArray:[NSArray arrayWithObjects:__VA_ARGS__]]; \
|
||||
} \
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Use this code in development mode (or in production), to use the advertising ID.
|
||||
* It's useful in development mode so that we remember your device even if you reinstall your app.
|
||||
* Since it's a MACRO, this won't get compiled into your app in production, and will be safe
|
||||
* to submit to Apple.
|
||||
*/
|
||||
#define LEANPLUM_USE_ADVERTISING_ID \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
|
||||
id LeanplumIdentifierManager = [NSClassFromString(@"ASIdentifierManager") \
|
||||
performSelector:NSSelectorFromString(@"sharedManager")]; \
|
||||
if (floor(NSFoundationVersionNumber) <= 1299 /* NSFoundationVersionNumber_iOS_9_x_Max */ || \
|
||||
[LeanplumIdentifierManager performSelector: \
|
||||
NSSelectorFromString(@"isAdvertisingTrackingEnabled")]) { \
|
||||
/* < iOS10 || isAdvertisingTrackingEnabled */ \
|
||||
[Leanplum setDeviceId:[[LeanplumIdentifierManager performSelector: \
|
||||
NSSelectorFromString(@"advertisingIdentifier")] \
|
||||
performSelector:NSSelectorFromString(@"UUIDString")]]; \
|
||||
} \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
@class LPActionContext;
|
||||
@class SKPaymentTransaction;
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
|
||||
@class NSExtensionContext;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup _ Callback Blocks
|
||||
* Those blocks are used when you define callbacks.
|
||||
* @{
|
||||
*/
|
||||
typedef void (^LeanplumStartBlock)(BOOL success);
|
||||
typedef void (^LeanplumVariablesChangedBlock)(void);
|
||||
typedef void (^LeanplumInterfaceChangedBlock)(void);
|
||||
typedef void (^LeanplumSetLocationBlock)(BOOL success);
|
||||
// Returns whether the action was handled.
|
||||
typedef BOOL (^LeanplumActionBlock)(LPActionContext* context);
|
||||
typedef void (^LeanplumHandleNotificationBlock)(void);
|
||||
typedef void (^LeanplumShouldHandleNotificationBlock)(NSDictionary *userInfo, LeanplumHandleNotificationBlock response);
|
||||
typedef NSUInteger LeanplumUIBackgroundFetchResult; // UIBackgroundFetchResult
|
||||
typedef void (^LeanplumFetchCompletionBlock)(LeanplumUIBackgroundFetchResult result);
|
||||
typedef void (^LeanplumPushSetupBlock)(void);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Leanplum Action Kind Message types
|
||||
* This is a bit-field. To choose both kinds, use
|
||||
* kLeanplumActionKindMessage | kLeanplumActionKindAction
|
||||
*/
|
||||
typedef enum {
|
||||
kLeanplumActionKindMessage = 0b1,
|
||||
kLeanplumActionKindAction = 0b10,
|
||||
} LeanplumActionKind;
|
||||
|
||||
#define LP_PURCHASE_EVENT @"Purchase"
|
||||
|
||||
@interface Leanplum : NSObject
|
||||
|
||||
/**
|
||||
* Optional. Sets the API server. The API path is of the form http[s]://hostname/servletName
|
||||
* @param hostName The name of the API host, such as api.leanplum.com
|
||||
* @param servletName The name of the API servlet, such as api
|
||||
* @param ssl Whether to use SSL
|
||||
*/
|
||||
+ (void)setApiHostName:(NSString *)hostName withServletName:(NSString *)servletName usingSsl:(BOOL)ssl;
|
||||
|
||||
/**
|
||||
* Optional. Adjusts the network timeouts.
|
||||
* The default timeout is 10 seconds for requests, and 15 seconds for file downloads.
|
||||
* @{
|
||||
*/
|
||||
+ (void)setNetworkTimeoutSeconds:(int)seconds;
|
||||
+ (void)setNetworkTimeoutSeconds:(int)seconds forDownloads:(int)downloadSeconds;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Sets whether to show the network activity indicator in the status bar when making requests.
|
||||
* Default: YES.
|
||||
*/
|
||||
+ (void)setNetworkActivityIndicatorEnabled:(BOOL)enabled;
|
||||
|
||||
/**
|
||||
* Advanced: Whether new variables can be downloaded mid-session. By default, this is disabled.
|
||||
* Currently, if this is enabled, new variables can only be downloaded if a push notification is sent
|
||||
* while the app is running, and the notification's metadata hasn't be downloaded yet.
|
||||
*/
|
||||
+ (void)setCanDownloadContentMidSessionInProductionMode:(BOOL)value;
|
||||
|
||||
/**
|
||||
* Modifies the file hashing setting in development mode.
|
||||
* By default, Leanplum will hash file variables to determine if they're modified and need
|
||||
* to be uploaded to the server if we're running in the simulator.
|
||||
* Setting this to NO will reduce startup latency in development mode, but it's possible
|
||||
* that Leanplum will not always have the most up-to-date versions of your resources.
|
||||
*/
|
||||
+ (void)setFileHashingEnabledInDevelopmentMode:(BOOL)enabled;
|
||||
|
||||
/**
|
||||
* Sets whether to enable verbose logging in development mode. Default: NO.
|
||||
*/
|
||||
+ (void)setVerboseLoggingInDevelopmentMode:(BOOL)enabled;
|
||||
|
||||
/**
|
||||
* Sets a custom event name for in-app purchase tracking. Default: Purchase.
|
||||
*/
|
||||
+ (void)setInAppPurchaseEventName:(NSString *)event;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Must call either this or {@link setAppId:withProductionKey:}
|
||||
* before issuing any calls to the API, including start.
|
||||
* @param appId Your app ID.
|
||||
* @param accessKey Your development key.
|
||||
*/
|
||||
+ (void)setAppId:(NSString *)appId withDevelopmentKey:(NSString *)accessKey;
|
||||
|
||||
/**
|
||||
* Must call either this or {@link Leanplum::setAppId:withDevelopmentKey:}
|
||||
* before issuing any calls to the API, including start.
|
||||
* @param appId Your app ID.
|
||||
* @param accessKey Your production key.
|
||||
*/
|
||||
+ (void)setAppId:(NSString *)appId withProductionKey:(NSString *)accessKey;
|
||||
/**@}*/
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
|
||||
/**
|
||||
* Apps running as extensions need to call this before start.
|
||||
* @param context The current extensionContext. You can get this from UIViewController.
|
||||
*/
|
||||
+ (void)setExtensionContext:(NSExtensionContext *)context;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Call this before start to allow your interfaces to change on the fly.
|
||||
* Needed in development mode to enable the interface editor, as well as in production to allow
|
||||
* changes to be applied.
|
||||
*/
|
||||
+ (void)allowInterfaceEditing __attribute__((deprecated("Use LeanplumUIEditor pod instead.")));
|
||||
|
||||
/**
|
||||
* Check if interface editing is enabled.
|
||||
*/
|
||||
+ (BOOL)interfaceEditingEnabled __attribute__((deprecated("Use LeanplumUIEditor pod instead.")));
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Sets a custom device ID. For example, you may want to pass the advertising ID to do attribution.
|
||||
* By default, the device ID is the identifier for vendor.
|
||||
*/
|
||||
+ (void)setDeviceId:(NSString *)deviceId;
|
||||
|
||||
/**
|
||||
* By default, Leanplum reports the version of your app using CFBundleVersion, which
|
||||
* can be used for reporting and targeting on the Leanplum dashboard.
|
||||
* If you wish to use CFBundleShortVersionString or any other string as the version,
|
||||
* you can call this before your call to [Leanplum start]
|
||||
*/
|
||||
+ (void)setAppVersion:(NSString *)appVersion;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Syncs resources between Leanplum and the current app.
|
||||
* You should only call this once, and before {@link start}.
|
||||
* Deprecated. Use {@link syncResourcesAsync:} instead.
|
||||
*/
|
||||
+ (void)syncResources __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Syncs resources between Leanplum and the current app.
|
||||
* You should only call this once, and before {@link start}.
|
||||
* @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to
|
||||
* index the app's resources. If async is set, resources may not be available immediately
|
||||
* when the app starts.
|
||||
*/
|
||||
+ (void)syncResourcesAsync:(BOOL)async;
|
||||
|
||||
/**
|
||||
* Syncs resources between Leanplum and the current app.
|
||||
* You should only call this once, and before {@link start}.
|
||||
* Deprecated. Use {@link syncResourcePaths:excluding:async} instead.
|
||||
* @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to
|
||||
* index the app's resources. If async is set, resources may not be available immediately
|
||||
* when the app starts.
|
||||
* @param patternsToIncludeOrNil Limit paths to only those matching at least one pattern in this
|
||||
* list. Supply nil to indicate no inclusion patterns. Paths are relative to the app's bundle.
|
||||
* @param patternsToExcludeOrNil Exclude paths matching at least one of these patterns.
|
||||
* Supply nil to indicate no exclusion patterns.
|
||||
*/
|
||||
+ (void)syncResourcePaths:(NSArray *)patternsToIncludeOrNil
|
||||
excluding:(NSArray *)patternsToExcludeOrNil __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Syncs resources between Leanplum and the current app.
|
||||
* You should only call this once, and before {@link start}.
|
||||
* @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to
|
||||
* index the app's resources. If async is set, resources may not be available immediately
|
||||
* when the app starts.
|
||||
* @param patternsToIncludeOrNil Limit paths to only those matching at least one pattern in this
|
||||
* list. Supply nil to indicate no inclusion patterns. Paths are relative to the app's bundle.
|
||||
* @param patternsToExcludeOrNil Exclude paths matching at least one of these patterns.
|
||||
* Supply nil to indicate no exclusion patterns.
|
||||
* @param async Whether the call should be asynchronous. Resource syncing can take 1-2 seconds to
|
||||
* index the app's resources. If async is set, resources may not be available immediately
|
||||
* when the app starts.
|
||||
*/
|
||||
+ (void)syncResourcePaths:(NSArray *)patternsToIncludeOrNil
|
||||
excluding:(NSArray *)patternsToExcludeOrNil
|
||||
async:(BOOL)async;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Call this when your application starts.
|
||||
* This will initiate a call to Leanplum's servers to get the values
|
||||
* of the variables used in your app.
|
||||
*/
|
||||
+ (void)start;
|
||||
+ (void)startWithResponseHandler:(LeanplumStartBlock)response;
|
||||
+ (void)startWithUserAttributes:(NSDictionary *)attributes;
|
||||
+ (void)startWithUserId:(NSString *)userId;
|
||||
+ (void)startWithUserId:(NSString *)userId responseHandler:(LeanplumStartBlock)response;
|
||||
+ (void)startWithUserId:(NSString *)userId userAttributes:(NSDictionary *)attributes;
|
||||
+ (void)startWithUserId:(NSString *)userId userAttributes:(NSDictionary *)attributes
|
||||
responseHandler:(LeanplumStartBlock)startResponse;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Returns whether or not Leanplum has finished starting.
|
||||
*/
|
||||
+ (BOOL)hasStarted;
|
||||
|
||||
/**
|
||||
* Returns whether or not Leanplum has finished starting and the device is registered
|
||||
* as a developer.
|
||||
*/
|
||||
+ (BOOL)hasStartedAndRegisteredAsDeveloper;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Block to call when the start call finishes, and variables are returned
|
||||
* back from the server. Calling this multiple times will call each block
|
||||
* in succession.
|
||||
*/
|
||||
+ (void)onStartResponse:(LeanplumStartBlock)block;
|
||||
|
||||
/**
|
||||
* Block to call when the variables receive new values from the server.
|
||||
* This will be called on start, and also later on if the user is in an experiment
|
||||
* that can update in realtime.
|
||||
*/
|
||||
+ (void)onVariablesChanged:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Block to call when the interface receive new values from the server.
|
||||
* This will be called on start, and also later on if the user is in an experiment
|
||||
* that can update in realtime.
|
||||
*/
|
||||
+ (void)onInterfaceChanged:(LeanplumInterfaceChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Block to call when no more file downloads are pending (either when
|
||||
* no files needed to be downloaded or all downloads have been completed).
|
||||
*/
|
||||
+ (void)onVariablesChangedAndNoDownloadsPending:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Block to call ONCE when no more file downloads are pending (either when
|
||||
* no files needed to be downloaded or all downloads have been completed).
|
||||
*/
|
||||
+ (void)onceVariablesChangedAndNoDownloadsPending:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Defines new action and message types to be performed at points set up on the Leanplum dashboard.
|
||||
*/
|
||||
+ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args;
|
||||
+ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args
|
||||
withOptions:(NSDictionary *)options;
|
||||
+ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args
|
||||
withResponder:(LeanplumActionBlock)responder;
|
||||
+ (void)defineAction:(NSString *)name ofKind:(LeanplumActionKind)kind withArguments:(NSArray *)args
|
||||
withOptions:(NSDictionary *)options
|
||||
withResponder:(LeanplumActionBlock)responder;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Block to call when an action is received, such as to show a message to the user.
|
||||
*/
|
||||
+ (void)onAction:(NSString *)actionName invoke:(LeanplumActionBlock)block;
|
||||
|
||||
/**
|
||||
* Handles a push notification for apps that use Background Notifications.
|
||||
* Without background notifications, Leanplum handles them automatically.
|
||||
* Deprecated. Leanplum calls handleNotification automatically now. If you
|
||||
* implement application:didReceiveRemoteNotification:fetchCompletionHandler:
|
||||
* in your app delegate, you should remove any calls to [Leanplum handleNotification]
|
||||
* and call the completion handler yourself.
|
||||
*/
|
||||
+ (void)handleNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(LeanplumFetchCompletionBlock)completionHandler
|
||||
__attribute__((deprecated("Leanplum calls handleNotification automatically now. If you "
|
||||
"implement application:didReceiveRemoteNotification:fetchCompletionHandler: in your app "
|
||||
"delegate, you should remove any calls to [Leanplum handleNotification] and call the "
|
||||
"completion handler yourself.")));
|
||||
|
||||
#if LP_NOT_TV
|
||||
/**
|
||||
* Call this to handle custom actions for local notifications.
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
+ (void)handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
completionHandler:(void (^)())completionHandler;
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Call this to handle custom actions for remote notifications.
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
+ (void)handleActionWithIdentifier:(NSString *)identifier
|
||||
forRemoteNotification:(NSDictionary *)notification
|
||||
completionHandler:(void (^)())completionHandler;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
/*
|
||||
* Block to call that decides whether a notification should be displayed when it is
|
||||
* received while the app is running, and the notification is not muted.
|
||||
* Overrides the default behavior of showing an alert view with the notification message.
|
||||
*/
|
||||
+ (void)setShouldOpenNotificationHandler:(LeanplumShouldHandleNotificationBlock)block;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Adds a responder to be executed when an event happens.
|
||||
* Similar to the methods above but uses NSInvocations instead of blocks.
|
||||
* @see onStartResponse:
|
||||
*/
|
||||
+ (void)addStartResponseResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)addVariablesChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)addInterfaceChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)addVariablesChangedAndNoDownloadsPendingResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)addResponder:(id)responder withSelector:(SEL)selector forActionNamed:(NSString *)actionName;
|
||||
+ (void)removeStartResponseResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)removeVariablesChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)removeInterfaceChangedResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)removeVariablesChangedAndNoDownloadsPendingResponder:(id)responder withSelector:(SEL)selector;
|
||||
+ (void)removeResponder:(id)responder withSelector:(SEL)selector forActionNamed:(NSString *)actionName;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Sets additional user attributes after the session has started.
|
||||
* Variables retrieved by start won't be targeted based on these attributes, but
|
||||
* they will count for the current session for reporting purposes.
|
||||
* Only those attributes given in the dictionary will be updated. All other
|
||||
* attributes will be preserved.
|
||||
*/
|
||||
+ (void)setUserAttributes:(NSDictionary *)attributes;
|
||||
|
||||
/**
|
||||
* Updates a user ID after session start.
|
||||
*/
|
||||
+ (void)setUserId:(NSString *)userId;
|
||||
|
||||
/**
|
||||
* Updates a user ID after session start with a dictionary of user attributes.
|
||||
*/
|
||||
+ (void)setUserId:(NSString *)userId withUserAttributes:(NSDictionary *)attributes;
|
||||
|
||||
/**
|
||||
* Sets the traffic source info for the current user.
|
||||
* Keys in info must be one of: publisherId, publisherName, publisherSubPublisher,
|
||||
* publisherSubSite, publisherSubCampaign, publisherSubAdGroup, publisherSubAd.
|
||||
*/
|
||||
+ (void)setTrafficSourceInfo:(NSDictionary *)info;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Advances to a particular state in your application. The string can be
|
||||
* any value of your choosing, and will show up in the dashboard.
|
||||
* A state is a section of your app that the user is currently in.
|
||||
* @param state The name of the state.
|
||||
*/
|
||||
+ (void)advanceTo:(NSString *)state;
|
||||
|
||||
/**
|
||||
* Advances to a particular state in your application. The string can be
|
||||
* any value of your choosing, and will show up in the dashboard.
|
||||
* A state is a section of your app that the user is currently in.
|
||||
* @param state The name of the state.
|
||||
* @param info Anything else you want to log with the state. For example, if the state
|
||||
* is watchVideo, info could be the video ID.
|
||||
*/
|
||||
+ (void)advanceTo:(NSString *)state withInfo:(NSString *)info;
|
||||
|
||||
/**
|
||||
* Advances to a particular state in your application. The string can be
|
||||
* any value of your choosing, and will show up in the dashboard.
|
||||
* A state is a section of your app that the user is currently in.
|
||||
* You can specify up to 200 types of parameters per app across all events and state.
|
||||
* The parameter keys must be strings, and values either strings or numbers.
|
||||
* @param state The name of the state.
|
||||
* @param params A dictionary with custom parameters.
|
||||
*/
|
||||
+ (void)advanceTo:(NSString *)state withParameters:(NSDictionary *)params;
|
||||
|
||||
/**
|
||||
* Advances to a particular state in your application. The string can be
|
||||
* any value of your choosing, and will show up in the dashboard.
|
||||
* A state is a section of your app that the user is currently in.
|
||||
* You can specify up to 200 types of parameters per app across all events and state.
|
||||
* The parameter keys must be strings, and values either strings or numbers.
|
||||
* @param state The name of the state. (nullable)
|
||||
* @param info Anything else you want to log with the state. For example, if the state
|
||||
* is watchVideo, info could be the video ID.
|
||||
* @param params A dictionary with custom parameters.
|
||||
*/
|
||||
+ (void)advanceTo:(NSString *)state withInfo:(NSString *)info andParameters:(NSDictionary *)params;
|
||||
|
||||
/**
|
||||
* Pauses the current state.
|
||||
* You can use this if your game has a "pause" mode. You shouldn't call it
|
||||
* when someone switches out of your app because that's done automatically.
|
||||
*/
|
||||
+ (void)pauseState;
|
||||
|
||||
/**
|
||||
* Resumes the current state.
|
||||
*/
|
||||
+ (void)resumeState;
|
||||
|
||||
/**
|
||||
* Automatically tracks all of the screens in the app as states.
|
||||
* You should not use this in conjunction with advanceTo as the user can only be in
|
||||
* 1 state at a time. This method requires LeanplumUIEditor module.
|
||||
*/
|
||||
+ (void)trackAllAppScreens;
|
||||
|
||||
/**
|
||||
* LPTrackScreenMode enum.
|
||||
* LPTrackScreenModeDefault mans that states are the full view controller type name.
|
||||
* LPTrackScreenModeStripViewController will cause the string "ViewController" to be stripped from
|
||||
* the end of the state.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, LPTrackScreenMode) {
|
||||
LPTrackScreenModeDefault = 0,
|
||||
LPTrackScreenModeStripViewController
|
||||
};
|
||||
|
||||
/**
|
||||
* Automatically tracks all of the screens in the app as states.
|
||||
* You should not use this in conjunction with advanceTo as the user can only be in
|
||||
* 1 state at a time. This method requires LeanplumUIEditor module.
|
||||
* @param trackScreenMode Choose mode for display. Default is the view controller type name.
|
||||
*/
|
||||
+ (void)trackAllAppScreensWithMode:(LPTrackScreenMode)trackScreenMode;
|
||||
|
||||
/**
|
||||
* Manually track purchase event with currency code in your application. It is advised to use
|
||||
* trackInAppPurchases to automatically track IAPs.
|
||||
*/
|
||||
+ (void)trackPurchase:(NSString *)event withValue:(double)value
|
||||
andCurrencyCode:(NSString *)currencyCode andParameters:(NSDictionary *)params;
|
||||
|
||||
/**
|
||||
* Automatically tracks InApp purchase and does server side receipt validation.
|
||||
*/
|
||||
+ (void)trackInAppPurchases;
|
||||
|
||||
/**
|
||||
* Manually tracks InApp purchase and does server side receipt validation.
|
||||
*/
|
||||
+ (void)trackInAppPurchase:(SKPaymentTransaction *)transaction;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Logs a particular event in your application. The string can be
|
||||
* any value of your choosing, and will show up in the dashboard.
|
||||
* To track a purchase, use LP_PURCHASE_EVENT.
|
||||
*/
|
||||
+ (void)track:(NSString *)event;
|
||||
+ (void)track:(NSString *)event withValue:(double)value;
|
||||
+ (void)track:(NSString *)event withInfo:(NSString *)info;
|
||||
+ (void)track:(NSString *)event withValue:(double)value andInfo:(NSString *)info;
|
||||
|
||||
// See above for the explanation of params.
|
||||
+ (void)track:(NSString *)event withParameters:(NSDictionary *)params;
|
||||
+ (void)track:(NSString *)event withValue:(double)value andParameters:(NSDictionary *)params;
|
||||
+ (void)track:(NSString *)event withValue:(double)value andInfo:(NSString *)info andParameters:(NSDictionary *)params;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Gets the path for a particular resource. The resource can be overridden by the server.
|
||||
*/
|
||||
+ (NSString *)pathForResource:(NSString *)name ofType:(NSString *)extension;
|
||||
+ (id)objectForKeyPath:(id)firstComponent, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
+ (id)objectForKeyPathComponents:(NSArray *)pathComponents;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Gets a list of variants that are currently active for this user.
|
||||
* Each variant is a dictionary containing an id.
|
||||
*/
|
||||
+ (NSArray *)variants;
|
||||
|
||||
/**
|
||||
* Returns metadata for all active in-app messages.
|
||||
* Recommended only for debugging purposes and advanced use cases.
|
||||
*/
|
||||
+ (NSDictionary *)messageMetadata;
|
||||
|
||||
/**
|
||||
* Forces content to update from the server. If variables have changed, the
|
||||
* appropriate callbacks will fire. Use sparingly as if the app is updated,
|
||||
* you'll have to deal with potentially inconsistent state or user experience.
|
||||
*/
|
||||
+ (void)forceContentUpdate;
|
||||
|
||||
/**
|
||||
* Forces content to update from the server. If variables have changed, the
|
||||
* appropriate callbacks will fire. Use sparingly as if the app is updated,
|
||||
* you'll have to deal with potentially inconsistent state or user experience.
|
||||
* The provided callback will always fire regardless
|
||||
* of whether the variables have changed.
|
||||
*/
|
||||
+ (void)forceContentUpdate:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* This should be your first statement in a unit test. This prevents
|
||||
* Leanplum from communicating with the server.
|
||||
*/
|
||||
+ (void)enableTestMode;
|
||||
|
||||
/**
|
||||
* Used to enable or disable test mode. Test mode prevents Leanplum from
|
||||
* communicating with the server. This is useful for unit tests.
|
||||
*/
|
||||
+ (void)setTestModeEnabled:(BOOL)isTestModeEnabled;
|
||||
|
||||
/**
|
||||
* Customize push setup. If this API should be called before [Leanplum start]. If this API is not
|
||||
* used the default push setup from the docs will be used for "Push Ask to Ask" and
|
||||
* "Register For Push".
|
||||
*/
|
||||
+ (void)setPushSetup:(LeanplumPushSetupBlock)block;
|
||||
|
||||
/**
|
||||
* Get the push setup block.
|
||||
*/
|
||||
+ (LeanplumPushSetupBlock)pushSetupBlock;
|
||||
|
||||
/**
|
||||
* Returns YES if the app existed on the device more than a day previous to a version built with
|
||||
* Leanplum was installed.
|
||||
*/
|
||||
+ (BOOL)isPreLeanplumInstall;
|
||||
|
||||
/**
|
||||
* Returns the deviceId in the current Leanplum session. This should only be called after
|
||||
* [Leanplum start].
|
||||
*/
|
||||
+ (NSString *)deviceId;
|
||||
|
||||
/**
|
||||
* Returns the userId in the current Leanplum session. This should only be called after
|
||||
* [Leanplum start].
|
||||
*/
|
||||
+ (NSString *)userId;
|
||||
|
||||
/**
|
||||
* Returns an instance to the singleton LPInbox object.
|
||||
*/
|
||||
+ (LPInbox *)inbox;
|
||||
|
||||
/**
|
||||
* Returns an instance to the singleton LPNewsfeed object.
|
||||
* Deprecated. Use {@link inbox} instead.
|
||||
*/
|
||||
+ (LPNewsfeed *)newsfeed __attribute__((deprecated("Use inbox instead.")));
|
||||
|
||||
/**
|
||||
* Types of location accuracy. Higher value implies better accuracy.
|
||||
*/
|
||||
typedef enum {
|
||||
LPLocationAccuracyIP = 0,
|
||||
LPLocationAccuracyCELL = 1,
|
||||
LPLocationAccuracyGPS = 2
|
||||
} LPLocationAccuracyType;
|
||||
|
||||
/**
|
||||
* Set location manually. Calls setDeviceLocationWithLatitude:longitude:type: with cell type.
|
||||
* Best if used in after calling setDeviceLocationWithLatitude:.
|
||||
*/
|
||||
+ (void)setDeviceLocationWithLatitude:(double)latitude
|
||||
longitude:(double)longitude;
|
||||
|
||||
/**
|
||||
* Set location manually. Best if used in after calling setDeviceLocationWithLatitude:.
|
||||
* Useful if you want to apply additional logic before sending in the location.
|
||||
*/
|
||||
+ (void)setDeviceLocationWithLatitude:(double)latitude
|
||||
longitude:(double)longitude
|
||||
type:(LPLocationAccuracyType)type;
|
||||
|
||||
/**
|
||||
* Set location manually. Best if used in after calling setDeviceLocationWithLatitude:.
|
||||
* If you have the CLPlacemark info: city is locality, region is administrativeArea,
|
||||
* and country is ISOcountryCode.
|
||||
*/
|
||||
+ (void)setDeviceLocationWithLatitude:(double)latitude
|
||||
longitude:(double)longitude
|
||||
city:(NSString *)city
|
||||
region:(NSString *)region
|
||||
country:(NSString *)country
|
||||
type:(LPLocationAccuracyType)type;
|
||||
|
||||
/**
|
||||
* Disables collecting location automatically. Will do nothing if Leanplum-Location is not used.
|
||||
*/
|
||||
+ (void)disableLocationCollection;
|
||||
|
||||
@end
|
||||
|
||||
@interface LeanplumCompatibility : NSObject
|
||||
|
||||
/**
|
||||
* Used only for compatibility with Google Analytics.
|
||||
*/
|
||||
+ (void)gaTrack:(NSObject *)trackingObject;
|
||||
|
||||
@end
|
||||
|
||||
@class LPVar;
|
||||
|
||||
/**
|
||||
* Receives callbacks for {@link LPVar}
|
||||
*/
|
||||
@protocol LPVarDelegate <NSObject>
|
||||
@optional
|
||||
/**
|
||||
* For file variables, called when the file is ready.
|
||||
*/
|
||||
- (void)fileIsReady:(LPVar *)var;
|
||||
/**
|
||||
* Called when the value of the variable changes.
|
||||
*/
|
||||
- (void)valueDidChange:(LPVar *)var;
|
||||
@end
|
||||
|
||||
/**
|
||||
* A variable is any part of your application that can change from an experiment.
|
||||
* Check out {@link Macros the macros} for defining variables more easily.
|
||||
*/
|
||||
@interface LPVar : NSObject
|
||||
/**
|
||||
* @{
|
||||
* Defines a {@link LPVar}
|
||||
*/
|
||||
|
||||
+ (LPVar *)define:(NSString *)name;
|
||||
+ (LPVar *)define:(NSString *)name withInt:(int)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withFloat:(float)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withDouble:(double)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withCGFloat:(CGFloat)cgFloatValue;
|
||||
+ (LPVar *)define:(NSString *)name withShort:(short)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withChar:(char)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withBool:(BOOL)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withString:(NSString *)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withNumber:(NSNumber *)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withInteger:(NSInteger)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withLong:(long)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withLongLong:(long long)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedChar:(unsigned char)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedInt:(unsigned int)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedInteger:(NSUInteger)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedLong:(unsigned long)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedLongLong:(unsigned long long)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withUnsignedShort:(unsigned short)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withFile:(NSString *)defaultFilename;
|
||||
+ (LPVar *)define:(NSString *)name withDictionary:(NSDictionary *)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withArray:(NSArray *)defaultValue;
|
||||
+ (LPVar *)define:(NSString *)name withColor:(UIColor *)defaultValue;
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* Returns the name of the variable.
|
||||
*/
|
||||
- (NSString *)name;
|
||||
|
||||
/**
|
||||
* Returns the components of the variable's name.
|
||||
*/
|
||||
- (NSArray *)nameComponents;
|
||||
|
||||
/**
|
||||
* Returns the default value of a variable.
|
||||
*/
|
||||
- (id)defaultValue;
|
||||
|
||||
/**
|
||||
* Returns the kind of the variable.
|
||||
*/
|
||||
- (NSString *)kind;
|
||||
|
||||
/**
|
||||
* Returns whether the variable has changed since the last time the app was run.
|
||||
*/
|
||||
- (BOOL)hasChanged;
|
||||
|
||||
/**
|
||||
* For file variables, called when the file is ready.
|
||||
*/
|
||||
- (void)onFileReady:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Called when the value of the variable changes.
|
||||
*/
|
||||
- (void)onValueChanged:(LeanplumVariablesChangedBlock)block;
|
||||
|
||||
/**
|
||||
* Sets the delegate of the variable in order to use
|
||||
* {@link LPVarDelegate::fileIsReady:} and {@link LPVarDelegate::valueDidChange:}
|
||||
*/
|
||||
- (void)setDelegate:(id <LPVarDelegate>)delegate;
|
||||
|
||||
/**
|
||||
* @{
|
||||
* Accessess the value(s) of the variable
|
||||
*/
|
||||
- (id)objectForKey:(NSString *)key;
|
||||
- (id)objectAtIndex:(NSUInteger )index;
|
||||
- (id)objectForKeyPath:(id)firstComponent, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
- (id)objectForKeyPathComponents:(NSArray *)pathComponents;
|
||||
- (NSUInteger)count;
|
||||
|
||||
- (NSNumber *)numberValue;
|
||||
- (NSString *)stringValue;
|
||||
- (NSString *)fileValue;
|
||||
- (UIImage *)imageValue;
|
||||
- (int)intValue;
|
||||
- (double)doubleValue;
|
||||
- (CGFloat)cgFloatValue;
|
||||
- (float)floatValue;
|
||||
- (short)shortValue;
|
||||
- (BOOL)boolValue;
|
||||
- (char)charValue;
|
||||
- (long)longValue;
|
||||
- (long long)longLongValue;
|
||||
- (NSInteger)integerValue;
|
||||
- (unsigned char)unsignedCharValue;
|
||||
- (unsigned short)unsignedShortValue;
|
||||
- (unsigned int)unsignedIntValue;
|
||||
- (NSUInteger)unsignedIntegerValue;
|
||||
- (unsigned long)unsignedLongValue;
|
||||
- (unsigned long long)unsignedLongLongValue;
|
||||
- (UIColor *)colorValue;
|
||||
/**@}*/
|
||||
@end
|
||||
|
||||
@interface LPActionArg : NSObject
|
||||
/**
|
||||
* @{
|
||||
* Defines a Leanplum Action Argument
|
||||
*/
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withNumber:(NSNumber *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withString:(NSString *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withBool:(BOOL)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withFile:(NSString *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withDict:(NSDictionary *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withArray:(NSArray *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withAction:(NSString *)defaultValue;
|
||||
+ (LPActionArg *)argNamed:(NSString *)name withColor:(UIColor *)defaultValue;
|
||||
/**@}*/
|
||||
- (NSString *)name;
|
||||
- (NSString *)kind;
|
||||
- (id)defaultValue;
|
||||
|
||||
@end
|
||||
|
||||
@interface LPActionContext : NSObject
|
||||
|
||||
- (NSString *)actionName;
|
||||
|
||||
- (NSString *)stringNamed:(NSString *)name;
|
||||
- (NSString *)fileNamed:(NSString *)name;
|
||||
- (NSNumber *)numberNamed:(NSString *)name;
|
||||
- (BOOL)boolNamed:(NSString *)name;
|
||||
- (NSDictionary *)dictionaryNamed:(NSString *)name;
|
||||
- (NSArray *)arrayNamed:(NSString *)name;
|
||||
- (UIColor *)colorNamed:(NSString *)name;
|
||||
- (NSString *)htmlWithTemplateNamed:(NSString *)templateName;
|
||||
|
||||
/**
|
||||
* Runs the action given by the "name" key.
|
||||
*/
|
||||
- (void)runActionNamed:(NSString *)name;
|
||||
|
||||
/**
|
||||
* Runs and tracks an event for the action given by the "name" key.
|
||||
* This will track an event if no action is set.
|
||||
*/
|
||||
- (void)runTrackedActionNamed:(NSString *)name;
|
||||
|
||||
/**
|
||||
* Tracks an event in the context of the current message.
|
||||
*/
|
||||
- (void)track:(NSString *)event withValue:(double)value andParameters:(NSDictionary *)params;
|
||||
|
||||
/**
|
||||
* Tracks an event in the conext of the current message, with any parent actions prepended to the
|
||||
* message event name.
|
||||
*/
|
||||
- (void)trackMessageEvent:(NSString *)event
|
||||
withValue:(double)value
|
||||
andInfo:(NSString *)info
|
||||
andParameters:(NSDictionary *)params;
|
||||
|
||||
/**
|
||||
* Prevents the currently active message from appearing again in the future.
|
||||
*/
|
||||
- (void)muteFutureMessagesOfSameKind;
|
||||
|
||||
/**
|
||||
* Checks if the action context has any missing files that still need to be downloaded.
|
||||
*/
|
||||
- (BOOL)hasMissingFiles;
|
||||
|
||||
@end
|
||||
BIN
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Info.plist
vendored
Normal file
BIN
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Info.plist
vendored
Normal file
Binary file not shown.
BIN
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Leanplum
vendored
Normal file
BIN
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Leanplum
vendored
Normal file
Binary file not shown.
6
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Modules/module.modulemap
vendored
Normal file
6
mobile/ios/ThirdParty/Leanplum/Leanplum.framework/Modules/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
framework module Leanplum {
|
||||
umbrella header "Leanplum.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
115
mobile/ios/ThirdParty/Reachability.swift
vendored
Normal file
115
mobile/ios/ThirdParty/Reachability.swift
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2015 Isuru Nanayakkara
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
import Foundation
|
||||
import SystemConfiguration
|
||||
|
||||
|
||||
let ReachabilityStatusChangedNotification = "ReachabilityStatusChangedNotification"
|
||||
|
||||
enum ReachabilityType: CustomStringConvertible {
|
||||
case wwan
|
||||
case wiFi
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .wwan: return "WWAN"
|
||||
case .wiFi: return "WiFi"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ReachabilityStatus: CustomStringConvertible {
|
||||
case offline
|
||||
case online(ReachabilityType)
|
||||
case unknown
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .offline: return "Offline"
|
||||
case .online(let type): return "Online (\(type))"
|
||||
case .unknown: return "Unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class Reach {
|
||||
|
||||
func connectionStatus() -> ReachabilityStatus {
|
||||
var zeroAddress = sockaddr_in()
|
||||
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
|
||||
zeroAddress.sin_family = sa_family_t(AF_INET)
|
||||
|
||||
guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
|
||||
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
|
||||
}
|
||||
}) else {
|
||||
return .unknown
|
||||
}
|
||||
|
||||
var flags : SCNetworkReachabilityFlags = []
|
||||
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
|
||||
return .unknown
|
||||
}
|
||||
|
||||
return ReachabilityStatus(reachabilityFlags: flags)
|
||||
}
|
||||
|
||||
|
||||
func monitorReachabilityChanges() {
|
||||
let host = "google.com"
|
||||
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
|
||||
let reachability = SCNetworkReachabilityCreateWithName(nil, host)!
|
||||
|
||||
SCNetworkReachabilitySetCallback(reachability, { (_, flags, _) in
|
||||
let status = ReachabilityStatus(reachabilityFlags: flags)
|
||||
|
||||
NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityStatusChangedNotification),
|
||||
object: nil,
|
||||
userInfo: ["Status": status.description])
|
||||
|
||||
}, &context)
|
||||
|
||||
SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ReachabilityStatus {
|
||||
fileprivate init(reachabilityFlags flags: SCNetworkReachabilityFlags) {
|
||||
let connectionRequired = flags.contains(.connectionRequired)
|
||||
let isReachable = flags.contains(.reachable)
|
||||
let isWWAN = flags.contains(.isWWAN)
|
||||
|
||||
if !connectionRequired && isReachable {
|
||||
if isWWAN {
|
||||
self = .online(.wwan)
|
||||
} else {
|
||||
self = .online(.wiFi)
|
||||
}
|
||||
} else {
|
||||
self = .offline
|
||||
}
|
||||
}
|
||||
}
|
||||
11
mobile/ios/ThirdParty/Result/Error.swift
vendored
Normal file
11
mobile/ios/ThirdParty/Result/Error.swift
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Error.swift
|
||||
// Result
|
||||
//
|
||||
// Created by John Gallagher on 9/12/14.
|
||||
// Copyright (c) 2014 Big Nerd Ranch. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public typealias MaybeErrorType = Error & CustomStringConvertible
|
||||
19
mobile/ios/ThirdParty/Result/LICENSE
vendored
Normal file
19
mobile/ios/ThirdParty/Result/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2014 John Gallagher <jgallagher@bignerdranch.com>
|
||||
|
||||
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.
|
||||
24
mobile/ios/ThirdParty/Result/README.md
vendored
Normal file
24
mobile/ios/ThirdParty/Result/README.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Result
|
||||
|
||||
`Result` is a Swift framework that includes the `Result` enum and an
|
||||
`ErrorType` protocol.
|
||||
|
||||
Both types are extremely small. I look forward to two changes in Swift's future:
|
||||
|
||||
* A fix for the Swift compiler issue that requires the `Success` case of
|
||||
`Result` to box its `T` type somehow. This repo uses
|
||||
[Box](https://github.com/robrix/Box) as a workaround.
|
||||
* (Hopefully) The inclusion of these types or their moral equivalents in the
|
||||
Swift standard library, at which point this repo can be removed.
|
||||
|
||||
## Integration
|
||||
|
||||
Add this repository as a submodule, or use [Carthage](https://github.com/Carthage/Carthage/).
|
||||
|
||||
## Author
|
||||
|
||||
John Gallagher, jgallagher@bignerdranch.com
|
||||
|
||||
## License
|
||||
|
||||
Deferred is available under the MIT license. See the LICENSE file for more info.
|
||||
76
mobile/ios/ThirdParty/Result/Result.swift
vendored
Normal file
76
mobile/ios/ThirdParty/Result/Result.swift
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Result.swift
|
||||
// Result
|
||||
//
|
||||
// Created by John Gallagher on 9/12/14.
|
||||
// Copyright (c) 2014 Big Nerd Ranch. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
//import Box
|
||||
|
||||
public enum Maybe<T> {
|
||||
case failure(MaybeErrorType)
|
||||
|
||||
// TODO: Get rid of Box hack at some point after 6.3
|
||||
case success(Box<T>)
|
||||
|
||||
public init(failure: MaybeErrorType) {
|
||||
self = .failure(failure)
|
||||
}
|
||||
|
||||
public init(success: T) {
|
||||
self = .success(Box(success))
|
||||
}
|
||||
|
||||
public var successValue: T? {
|
||||
switch self {
|
||||
case let .success(success): return success.value
|
||||
case .failure: return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var failureValue: MaybeErrorType? {
|
||||
switch self {
|
||||
case .success: return nil
|
||||
case let .failure(error): return error
|
||||
}
|
||||
}
|
||||
|
||||
public var isSuccess: Bool {
|
||||
switch self {
|
||||
case .success: return true
|
||||
case .failure: return false
|
||||
}
|
||||
}
|
||||
|
||||
public var isFailure: Bool {
|
||||
switch self {
|
||||
case .success: return false
|
||||
case .failure: return true
|
||||
}
|
||||
}
|
||||
|
||||
public func map<U>(_ f: (T) -> U) -> Maybe<U> {
|
||||
switch self {
|
||||
case let .failure(error): return .failure(error)
|
||||
case let .success(value): return .success(Box(f(value.value)))
|
||||
}
|
||||
}
|
||||
|
||||
public func bind<U>(_ f: (T) -> Maybe<U>) -> Maybe<U> {
|
||||
switch self {
|
||||
case let .failure(error): return .failure(error)
|
||||
case let .success(value): return f(value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Maybe: CustomStringConvertible {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case let .failure(error): return "Result.Failure(\(error))"
|
||||
case let .success(value): return "Result.Success(\(value.value))"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
mobile/ios/ThirdParty/SQLite.swift/.cocoadocs.yml
vendored
Normal file
2
mobile/ios/ThirdParty/SQLite.swift/.cocoadocs.yml
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
additional_guides:
|
||||
- Documentation/Index.md
|
||||
27
mobile/ios/ThirdParty/SQLite.swift/.gitignore
vendored
Normal file
27
mobile/ios/ThirdParty/SQLite.swift/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
|
||||
# Carthage
|
||||
/Carthage/
|
||||
|
||||
# Swift Package Manager
|
||||
.build
|
||||
Packages/
|
||||
0
mobile/ios/ThirdParty/SQLite.swift/.gitmodules
vendored
Normal file
0
mobile/ios/ThirdParty/SQLite.swift/.gitmodules
vendored
Normal file
1
mobile/ios/ThirdParty/SQLite.swift/.swift-version
vendored
Normal file
1
mobile/ios/ThirdParty/SQLite.swift/.swift-version
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
3.0
|
||||
26
mobile/ios/ThirdParty/SQLite.swift/.travis.yml
vendored
Normal file
26
mobile/ios/ThirdParty/SQLite.swift/.travis.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
language: objective-c
|
||||
rvm: 2.2
|
||||
osx_image: xcode8.2
|
||||
env:
|
||||
global:
|
||||
- IOS_SIMULATOR="iPhone 6s"
|
||||
matrix:
|
||||
include:
|
||||
- env: BUILD_SCHEME="SQLite iOS"
|
||||
- env: BUILD_SCHEME="SQLite Mac"
|
||||
- env: VALIDATOR_SUBSPEC="none"
|
||||
- env: VALIDATOR_SUBSPEC="standard"
|
||||
- env: VALIDATOR_SUBSPEC="standalone"
|
||||
- env: VALIDATOR_SUBSPEC="SQLCipher"
|
||||
- env: CARTHAGE_PLATFORM="iOS"
|
||||
- env: CARTHAGE_PLATFORM="Mac"
|
||||
- env: CARTHAGE_PLATFORM="watchOS"
|
||||
- env: CARTHAGE_PLATFORM="tvOS"
|
||||
- env: PACKAGE_MANAGER_COMMAND="test -Xlinker -lsqlite3"
|
||||
before_install:
|
||||
- gem update bundler
|
||||
- gem install xcpretty --no-document
|
||||
- brew update
|
||||
- brew outdated carthage || brew upgrade carthage
|
||||
script:
|
||||
- ./run-tests.sh
|
||||
34
mobile/ios/ThirdParty/SQLite.swift/CHANGELOG.md
vendored
Normal file
34
mobile/ios/ThirdParty/SQLite.swift/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
0.11.2 (25-12-2016), [diff][diff-0.11.2]
|
||||
========================================
|
||||
|
||||
* Fixed SQLCipher integration with read-only databases ([#559][])
|
||||
* Preliminary Swift Package Manager support ([#548][], [#560][])
|
||||
* Fixed null pointer when fetching an empty BLOB ([#561][])
|
||||
* Allow `where` as alias for `filter` ([#571][])
|
||||
|
||||
0.11.1 (06-12-2016), [diff][diff-0.11.1]
|
||||
========================================
|
||||
|
||||
* Integrate SQLCipher via CocoaPods ([#546][], [#553][])
|
||||
* Made lastInsertRowid consistent with other SQLite wrappers ([#532][])
|
||||
* Fix for ~= operator used with Double ranges
|
||||
* Various documentation updates
|
||||
|
||||
0.11.0 (19-10-2016)
|
||||
===================
|
||||
|
||||
* Swift3 migration ([diff][diff-0.11.0])
|
||||
|
||||
|
||||
[diff-0.11.0]: https://github.com/stephencelis/SQLite.swift/compare/0.10.1...0.11.0
|
||||
[diff-0.11.1]: https://github.com/stephencelis/SQLite.swift/compare/0.11.0...0.11.1
|
||||
[diff-0.11.2]: https://github.com/stephencelis/SQLite.swift/compare/0.11.1...0.11.2
|
||||
|
||||
[#532]: https://github.com/stephencelis/SQLite.swift/issues/532
|
||||
[#546]: https://github.com/stephencelis/SQLite.swift/issues/546
|
||||
[#548]: https://github.com/stephencelis/SQLite.swift/pull/548
|
||||
[#553]: https://github.com/stephencelis/SQLite.swift/pull/553
|
||||
[#559]: https://github.com/stephencelis/SQLite.swift/pull/559
|
||||
[#560]: https://github.com/stephencelis/SQLite.swift/pull/560
|
||||
[#561]: https://github.com/stephencelis/SQLite.swift/issues/561
|
||||
[#571]: https://github.com/stephencelis/SQLite.swift/issues/571
|
||||
108
mobile/ios/ThirdParty/SQLite.swift/CONTRIBUTING.md
vendored
Normal file
108
mobile/ios/ThirdParty/SQLite.swift/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Contributing
|
||||
|
||||
The where and when to open an [issue](#issues) or [pull
|
||||
request](#pull-requests).
|
||||
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are used to track **bugs** and **feature requests**. Need **help** or
|
||||
have a **general question**? [Ask on Stack Overflow][] (tag `sqlite.swift`).
|
||||
|
||||
Before reporting a bug or requesting a feature, [run a few searches][Search] to
|
||||
see if a similar issue has already been opened and ensure you’re not submitting
|
||||
a duplicate.
|
||||
|
||||
If you find a similar issue, read the existing conversation and see if it
|
||||
addresses everything. If it doesn’t, continue the conversation there.
|
||||
|
||||
If your searches return empty, see the [bug](#bugs) or [feature
|
||||
request](#feature-requests) guidelines below.
|
||||
|
||||
[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift
|
||||
[Search]: https://github.com/stephencelis/SQLite.swift/search?type=Issues
|
||||
|
||||
|
||||
### Bugs
|
||||
|
||||
Think you’ve discovered a new **bug**? Let’s try troubleshooting a few things
|
||||
first.
|
||||
|
||||
- **Is it an installation issue?** <a name='bugs-1'/>
|
||||
|
||||
If this is your first time building SQLite.swift in your project, you may
|
||||
encounter a build error, _e.g._:
|
||||
|
||||
No such module 'SQLite'
|
||||
|
||||
Please carefully re-read the [installation instructions][] to make sure
|
||||
everything is in order.
|
||||
|
||||
- **Have you read the documentation?** <a name='bugs-2'/>
|
||||
|
||||
If you can’t seem to get something working, check
|
||||
[the documentation][See Documentation] to see if the solution is there.
|
||||
|
||||
- **Are you up-to-date?** <a name='bugs-3'/>
|
||||
|
||||
If you’re perusing [the documentation][See Documentation] online and find
|
||||
that an example is just not working, please upgrade to the latest version
|
||||
of SQLite.swift and try again before continuing.
|
||||
|
||||
- **Is it an unhelpful build error?** <a name='bugs-4'/>
|
||||
|
||||
While Swift error messaging is improving with each release, complex
|
||||
expressions still lend themselves to misleading errors. If you encounter an
|
||||
error on a complex line, breaking it down into smaller pieces generally
|
||||
yields a more understandable error.
|
||||
|
||||
- **Is it an _even more_ unhelpful build error?** <a name='bugs-5'/>
|
||||
|
||||
Have you updated Xcode recently? Did your project stop building out of the
|
||||
blue?
|
||||
|
||||
Hold down the **option** key and select **Clean Build Folder…** from the
|
||||
**Product** menu (⌥⇧⌘K).
|
||||
|
||||
Made it through everything above and still having trouble? Sorry!
|
||||
[Open an issue][]! And _please_:
|
||||
|
||||
- Be as descriptive as possible.
|
||||
- Provide as much information needed to _reliably reproduce_ the issue.
|
||||
- Attach screenshots if possible.
|
||||
- Better yet: attach GIFs or link to video.
|
||||
- Even better: link to a sample project exhibiting the issue.
|
||||
- Include the SQLite.swift commit or branch experiencing the issue.
|
||||
- Include devices and operating systems affected.
|
||||
- Include build information: the Xcode and OS X versions affected.
|
||||
|
||||
[installation instructions]: Documentation/Index.md#installation
|
||||
[See Documentation]: Documentation/Index.md#sqliteswift-documentation
|
||||
[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new
|
||||
|
||||
|
||||
### Feature Requests
|
||||
|
||||
Have an innovative **feature request**? [Open an issue][]! Be thorough! Provide
|
||||
context and examples. Be open to discussion.
|
||||
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Interested in contributing but don’t know where to start? Try the [`help
|
||||
wanted`][help wanted] label.
|
||||
|
||||
Ready to submit a fix or a feature? [Submit a pull request][]! And _please_:
|
||||
|
||||
- If code changes, run the tests and make sure everything still works.
|
||||
- Write new tests for new functionality.
|
||||
- Update documentation comments where applicable.
|
||||
- Maintain the existing style.
|
||||
- Don’t forget to have fun.
|
||||
|
||||
While we cannot guarantee a merge to every pull request, we do read each one
|
||||
and love your input.
|
||||
|
||||
|
||||
[help wanted]: https://github.com/stephencelis/SQLite.swift/labels/help%20wanted
|
||||
[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvos/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvos/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvsimulator/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/appletvsimulator/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos-10.0/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos-10.0/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphoneos/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator-10.0/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator-10.0/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator10.0.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/iphonesimulator/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.11/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.11/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.12/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx-10.12/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/macosx/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchos/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchos/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchsimulator/module.modulemap
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/CocoaPods/watchsimulator/module.modulemap
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
module CSQLite [system] {
|
||||
header "/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/SDKs/WatchSimulator.sdk/usr/include/sqlite3.h"
|
||||
export *
|
||||
}
|
||||
1587
mobile/ios/ThirdParty/SQLite.swift/Documentation/Index.md
vendored
Normal file
1587
mobile/ios/ThirdParty/SQLite.swift/Documentation/Index.md
vendored
Normal file
File diff suppressed because it is too large
Load diff
24
mobile/ios/ThirdParty/SQLite.swift/Documentation/Planning.md
vendored
Normal file
24
mobile/ios/ThirdParty/SQLite.swift/Documentation/Planning.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# SQLite.swift Planning
|
||||
|
||||
This document captures both near term steps (aka Roadmap) and feature requests.
|
||||
The goal is to add some visibility and guidance for future additions and Pull Requests, as well as to keep the Issues list clear of enhancement requests so that bugs are more visible.
|
||||
|
||||
## Roadmap
|
||||
|
||||
_Lists agreed upon next steps in approximate priority order._
|
||||
|
||||
## Feature Requests
|
||||
|
||||
_A gathering point for ideas for new features. In general, the corresponding issue will be closed once it is added here, with the assumption that it will be referred to when it comes time to add the corresponding feature._
|
||||
|
||||
### Features
|
||||
|
||||
* encapsulate ATTACH DATABASE / DETACH DATABASE as methods, per [#30](https://github.com/stephencelis/SQLite.swift/issues/30)
|
||||
* provide separate threads for update vs read, so updates don't block reads, per [#236](https://github.com/stephencelis/SQLite.swift/issues/236)
|
||||
* expose triggers, per [#164](https://github.com/stephencelis/SQLite.swift/issues/164)
|
||||
|
||||
## Suspended Feature Requests
|
||||
|
||||
_Features that are not actively being considered, perhaps because of no clean type-safe way to implement them with the current Swift, or bugs, or just general uncertainty._
|
||||
|
||||
* provide a mechanism for INSERT INTO multiple values, per [#168](https://github.com/stephencelis/SQLite.swift/issues/168)
|
||||
BIN
mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/installation@2x.png
vendored
Normal file
BIN
mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/installation@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 305 KiB |
BIN
mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/playground@2x.png
vendored
Normal file
BIN
mobile/ios/ThirdParty/SQLite.swift/Documentation/Resources/playground@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
21
mobile/ios/ThirdParty/SQLite.swift/LICENSE.txt
vendored
Normal file
21
mobile/ios/ThirdParty/SQLite.swift/LICENSE.txt
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014-2015 Stephen Celis (<stephen@stephencelis.com>)
|
||||
|
||||
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.
|
||||
60
mobile/ios/ThirdParty/SQLite.swift/Makefile
vendored
Normal file
60
mobile/ios/ThirdParty/SQLite.swift/Makefile
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
BUILD_TOOL = xcodebuild
|
||||
BUILD_SCHEME = SQLite Mac
|
||||
IOS_SIMULATOR = iPhone 6s
|
||||
IOS_VERSION = 9.3
|
||||
ifeq ($(BUILD_SCHEME),SQLite iOS)
|
||||
BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" -destination "platform=iOS Simulator,name=$(IOS_SIMULATOR),OS=$(IOS_VERSION)"
|
||||
else
|
||||
BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)"
|
||||
endif
|
||||
|
||||
XCPRETTY := $(shell command -v xcpretty)
|
||||
SWIFTCOV := $(shell command -v swiftcov)
|
||||
GCOVR := $(shell command -v gcovr)
|
||||
TEST_ACTIONS := clean build build-for-testing test-without-building
|
||||
|
||||
default: test
|
||||
|
||||
build:
|
||||
$(BUILD_TOOL) $(BUILD_ARGUMENTS)
|
||||
|
||||
test:
|
||||
ifdef XCPRETTY
|
||||
@set -o pipefail && $(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS) | $(XCPRETTY) -c
|
||||
else
|
||||
$(BUILD_TOOL) $(BUILD_ARGUMENTS) $(TEST_ACTIONS)
|
||||
endif
|
||||
|
||||
coverage:
|
||||
ifdef SWIFTCOV
|
||||
$(SWIFTCOV) generate --output coverage \
|
||||
$(BUILD_TOOL) $(BUILD_ARGUMENTS) -configuration Release test \
|
||||
-- ./SQLite/*.swift
|
||||
ifdef GCOVR
|
||||
$(GCOVR) \
|
||||
--root . \
|
||||
--use-gcov-files \
|
||||
--html \
|
||||
--html-details \
|
||||
--output coverage/index.html \
|
||||
--keep
|
||||
else
|
||||
@echo gcovr must be installed for HTML output: https://github.com/gcovr/gcovr
|
||||
endif
|
||||
else
|
||||
@echo swiftcov must be installed for coverage: https://github.com/realm/SwiftCov
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(BUILD_TOOL) $(BUILD_ARGUMENTS) clean
|
||||
rm -r coverage
|
||||
|
||||
repl:
|
||||
@$(BUILD_TOOL) $(BUILD_ARGUMENTS) -derivedDataPath $(TMPDIR)/SQLite.swift > /dev/null && \
|
||||
swift -F '$(TMPDIR)/SQLite.swift/Build/Products/Debug'
|
||||
|
||||
sloc:
|
||||
@zsh -c "grep -vE '^ *//|^$$' SQLite/*/*.{swift,h,m} | wc -l"
|
||||
|
||||
.PHONY: test coverage clean repl sloc
|
||||
17
mobile/ios/ThirdParty/SQLite.swift/Package.swift
vendored
Normal file
17
mobile/ios/ThirdParty/SQLite.swift/Package.swift
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "SQLite",
|
||||
targets: [
|
||||
Target(
|
||||
name: "SQLite",
|
||||
dependencies: [
|
||||
.Target(name: "SQLiteObjc")
|
||||
]),
|
||||
Target(name: "SQLiteObjc")
|
||||
],
|
||||
dependencies: [
|
||||
.Package(url: "https://github.com/stephencelis/CSQLite.git", majorVersion: 0)
|
||||
],
|
||||
exclude: ["Tests/CocoaPods", "Tests/Carthage"]
|
||||
)
|
||||
263
mobile/ios/ThirdParty/SQLite.swift/README.md
vendored
Normal file
263
mobile/ios/ThirdParty/SQLite.swift/README.md
vendored
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# SQLite.swift
|
||||
|
||||
[![Build Status][Badge]][Travis] [](http://cocoadocs.org/docsets/SQLite.swift) [](https://developer.apple.com/swift/) [](http://cocoadocs.org/docsets/SQLite.swift) [](https://github.com/Carthage/Carthage) [](https://gitter.im/stephencelis/SQLite.swift)
|
||||
|
||||
A type-safe, [Swift][]-language layer over [SQLite3][].
|
||||
|
||||
[SQLite.swift][] provides compile-time confidence in SQL statement
|
||||
syntax _and_ intent.
|
||||
|
||||
[Badge]: https://img.shields.io/travis/stephencelis/SQLite.swift/master.svg?style=flat
|
||||
[Travis]: https://travis-ci.org/stephencelis/SQLite.swift
|
||||
[Swift]: https://developer.apple.com/swift/
|
||||
[SQLite3]: http://www.sqlite.org
|
||||
[SQLite.swift]: https://github.com/stephencelis/SQLite.swift
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- A pure-Swift interface
|
||||
- A type-safe, optional-aware SQL expression builder
|
||||
- A flexible, chainable, lazy-executing query layer
|
||||
- Automatically-typed data access
|
||||
- A lightweight, uncomplicated query and parameter binding interface
|
||||
- Developer-friendly error handling and debugging
|
||||
- [Full-text search][] support
|
||||
- [Well-documented][See Documentation]
|
||||
- Extensively tested
|
||||
- SQLCipher support via CocoaPods
|
||||
- Active support at [StackOverflow](http://stackoverflow.com/questions/tagged/sqlite.swift), and [Gitter Chat Room](https://gitter.im/stephencelis/SQLite.swift) (_experimental_)
|
||||
|
||||
[Full-text search]: Documentation/Index.md#full-text-search
|
||||
[See Documentation]: Documentation/Index.md#sqliteswift-documentation
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
``` swift
|
||||
import SQLite
|
||||
|
||||
let db = try Connection("path/to/db.sqlite3")
|
||||
|
||||
let users = Table("users")
|
||||
let id = Expression<Int64>("id")
|
||||
let name = Expression<String?>("name")
|
||||
let email = Expression<String>("email")
|
||||
|
||||
try db.run(users.create { t in
|
||||
t.column(id, primaryKey: true)
|
||||
t.column(name)
|
||||
t.column(email, unique: true)
|
||||
})
|
||||
// CREATE TABLE "users" (
|
||||
// "id" INTEGER PRIMARY KEY NOT NULL,
|
||||
// "name" TEXT,
|
||||
// "email" TEXT NOT NULL UNIQUE
|
||||
// )
|
||||
|
||||
let insert = users.insert(name <- "Alice", email <- "alice@mac.com")
|
||||
let rowid = try db.run(insert)
|
||||
// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com')
|
||||
|
||||
for user in try db.prepare(users) {
|
||||
print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
|
||||
// id: 1, name: Optional("Alice"), email: alice@mac.com
|
||||
}
|
||||
// SELECT * FROM "users"
|
||||
|
||||
let alice = users.filter(id == rowid)
|
||||
|
||||
try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
|
||||
// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
|
||||
// WHERE ("id" = 1)
|
||||
|
||||
try db.run(alice.delete())
|
||||
// DELETE FROM "users" WHERE ("id" = 1)
|
||||
|
||||
db.scalar(users.count) // 0
|
||||
// SELECT count(*) FROM "users"
|
||||
```
|
||||
|
||||
SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C
|
||||
API.
|
||||
|
||||
``` swift
|
||||
let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)")
|
||||
for email in ["betty@icloud.com", "cathy@icloud.com"] {
|
||||
try stmt.run(email)
|
||||
}
|
||||
|
||||
db.totalChanges // 3
|
||||
db.changes // 1
|
||||
db.lastInsertRowid // 3
|
||||
|
||||
for row in try db.prepare("SELECT id, email FROM users") {
|
||||
print("id: \(row[0]), email: \(row[1])")
|
||||
// id: Optional(2), email: Optional("betty@icloud.com")
|
||||
// id: Optional(3), email: Optional("cathy@icloud.com")
|
||||
}
|
||||
|
||||
db.scalar("SELECT count(*) FROM users") // 2
|
||||
```
|
||||
|
||||
[Read the documentation][See Documentation] or explore more,
|
||||
interactively, from the Xcode project’s playground.
|
||||
|
||||

|
||||
|
||||
For a more comprehensive example, see [this article](http://masteringswift.blogspot.com/2015/09/create-data-access-layer-with.html) and the [companion repository](https://github.com/hoffmanjon/SQLiteDataAccessLayer2/tree/master).
|
||||
|
||||
## Installation
|
||||
|
||||
> _Note:_ SQLite.swift requires Swift 3 (and [Xcode][] 8) or greater. If you absolutely
|
||||
> need compatibility with Swift 2.3 you can use the [swift-2.3][] branch or older
|
||||
> released versions. New development will happen exclusively on the master/Swift 3 branch.
|
||||
|
||||
### Carthage
|
||||
|
||||
[Carthage][] is a simple, decentralized dependency manager for Cocoa. To
|
||||
install SQLite.swift with Carthage:
|
||||
|
||||
1. Make sure Carthage is [installed][Carthage Installation].
|
||||
|
||||
2. Update your Cartfile to include the following:
|
||||
|
||||
```
|
||||
github "stephencelis/SQLite.swift" ~> 0.11.2
|
||||
```
|
||||
|
||||
3. Run `carthage update` and [add the appropriate framework][Carthage Usage].
|
||||
|
||||
|
||||
[Carthage]: https://github.com/Carthage/Carthage
|
||||
[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage
|
||||
[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
|
||||
|
||||
|
||||
### CocoaPods
|
||||
|
||||
[CocoaPods][] is a dependency manager for Cocoa projects. To install
|
||||
SQLite.swift with CocoaPods:
|
||||
|
||||
1. Verify that your copy of Xcode is installed and active in the default location (`/Applications/Xcode.app`).
|
||||
|
||||
```sh
|
||||
sudo xcode-select --switch /Applications/Xcode.app
|
||||
```
|
||||
|
||||
2. Make sure CocoaPods is [installed][CocoaPods Installation]. (SQLite.swift requires version 1.0.0 or greater.)
|
||||
|
||||
``` sh
|
||||
# Using the default Ruby install will require you to use sudo when
|
||||
# installing and updating gems.
|
||||
[sudo] gem install cocoapods
|
||||
```
|
||||
|
||||
3. Update your Podfile to include the following:
|
||||
|
||||
``` ruby
|
||||
use_frameworks!
|
||||
|
||||
target 'YourAppTargetName' do
|
||||
pod 'SQLite.swift', '~> 0.11.2'
|
||||
end
|
||||
```
|
||||
|
||||
4. Run `pod install --repo-update`.
|
||||
|
||||
[CocoaPods]: https://cocoapods.org
|
||||
[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started
|
||||
|
||||
### Swift Package Manager
|
||||
|
||||
The [Swift Package Manager][] is a tool for managing the distribution of Swift code.
|
||||
|
||||
1. Add the following to your `Package.swift` file:
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.Package(url: "https://github.com/stephencelis/SQLite.swift.git", majorVersion: 0, minor: 11)
|
||||
]
|
||||
```
|
||||
|
||||
[Swift Package Manager]: https://swift.org/package-manager
|
||||
|
||||
### Manual
|
||||
|
||||
To install SQLite.swift as an Xcode sub-project:
|
||||
|
||||
1. Drag the **SQLite.xcodeproj** file into your own project.
|
||||
([Submodule][], clone, or [download][] the project first.)
|
||||
|
||||

|
||||
|
||||
2. In your target’s **General** tab, click the **+** button under **Linked
|
||||
Frameworks and Libraries**.
|
||||
|
||||
3. Select the appropriate **SQLite.framework** for your platform.
|
||||
|
||||
4. **Add**.
|
||||
|
||||
Some additional steps are required to install the application on an actual device:
|
||||
|
||||
5. In the **General** tab, click the **+** button under **Embedded Binaries**.
|
||||
|
||||
6. Select the appropriate **SQLite.framework** for your platform.
|
||||
|
||||
7. **Add**.
|
||||
|
||||
|
||||
[Xcode]: https://developer.apple.com/xcode/downloads/
|
||||
[Submodule]: http://git-scm.com/book/en/Git-Tools-Submodules
|
||||
[download]: https://github.com/stephencelis/SQLite.swift/archive/master.zip
|
||||
|
||||
|
||||
## Communication
|
||||
|
||||
[See the planning document] for a roadmap and existing feature requests.
|
||||
|
||||
[Read the contributing guidelines][]. The _TL;DR_ (but please; _R_):
|
||||
|
||||
- Need **help** or have a **general question**? [Ask on Stack
|
||||
Overflow][] (tag `sqlite.swift`).
|
||||
- Found a **bug** or have a **feature request**? [Open an issue][].
|
||||
- Want to **contribute**? [Submit a pull request][].
|
||||
|
||||
[See the planning document]: /Documentation/Planning.md
|
||||
[Read the contributing guidelines]: ./CONTRIBUTING.md#contributing
|
||||
[Ask on Stack Overflow]: http://stackoverflow.com/questions/tagged/sqlite.swift
|
||||
[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new
|
||||
[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork
|
||||
|
||||
|
||||
## Author
|
||||
|
||||
- [Stephen Celis](mailto:stephen@stephencelis.com)
|
||||
([@stephencelis](https://twitter.com/stephencelis))
|
||||
|
||||
|
||||
## License
|
||||
|
||||
SQLite.swift is available under the MIT license. See [the LICENSE
|
||||
file](./LICENSE.txt) for more information.
|
||||
|
||||
## Related
|
||||
|
||||
These projects enhance or use SQLite.swift:
|
||||
|
||||
- [SQLiteMigrationManager.swift](https://github.com/garriguv/SQLiteMigrationManager.swift) (inspired by [FMDBMigrationManager](https://github.com/layerhq/FMDBMigrationManager))
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
Looking for something else? Try another Swift wrapper (or [FMDB][]):
|
||||
|
||||
- [Camembert](https://github.com/remirobert/Camembert)
|
||||
- [GRDB](https://github.com/groue/GRDB.swift)
|
||||
- [SQLiteDB](https://github.com/FahimF/SQLiteDB)
|
||||
- [Squeal](https://github.com/nerdyc/Squeal)
|
||||
- [SwiftData](https://github.com/ryanfowler/SwiftData)
|
||||
- [SwiftSQLite](https://github.com/chrismsimpson/SwiftSQLite)
|
||||
|
||||
[FMDB]: https://github.com/ccgus/fmdb
|
||||
[swift-2.3]: https://github.com/stephencelis/SQLite.swift/tree/swift-2.3
|
||||
43
mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/Contents.swift
vendored
Normal file
43
mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/Contents.swift
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import SQLite
|
||||
|
||||
let db = try! Connection()
|
||||
|
||||
db.trace { print($0) }
|
||||
|
||||
let users = Table("users")
|
||||
|
||||
let id = Expression<Int64>("id")
|
||||
let email = Expression<String>("email")
|
||||
let name = Expression<String?>("name")
|
||||
|
||||
try! db.run(users.create { t in
|
||||
t.column(id, primaryKey: true)
|
||||
t.column(email, unique: true, check: email.like("%@%"))
|
||||
t.column(name)
|
||||
})
|
||||
|
||||
let rowid = try! db.run(users.insert(email <- "alice@mac.com"))
|
||||
let alice = users.filter(id == rowid)
|
||||
|
||||
for user in try! db.prepare(users) {
|
||||
print("id: \(user[id]), email: \(user[email])")
|
||||
}
|
||||
|
||||
let emails = VirtualTable("emails")
|
||||
|
||||
let subject = Expression<String?>("subject")
|
||||
let body = Expression<String?>("body")
|
||||
|
||||
try! db.run(emails.create(.FTS4(subject, body)))
|
||||
|
||||
try! db.run(emails.insert(
|
||||
subject <- "Hello, world!",
|
||||
body <- "This is a hello world message."
|
||||
))
|
||||
|
||||
let row = try! db.pluck(emails.match("hello"))
|
||||
|
||||
let query = try! db.prepare(emails.match("hello"))
|
||||
for row in query {
|
||||
print(row[subject])
|
||||
}
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/contents.xcplayground
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/SQLite.playground/contents.xcplayground
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='5.0' target-platform='osx' display-mode='raw'>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
70
mobile/ios/ThirdParty/SQLite.swift/SQLite.swift.podspec
vendored
Normal file
70
mobile/ios/ThirdParty/SQLite.swift/SQLite.swift.podspec
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "SQLite.swift"
|
||||
s.version = "0.11.2"
|
||||
s.summary = "A type-safe, Swift-language layer over SQLite3 for iOS and OS X."
|
||||
|
||||
s.description = <<-DESC
|
||||
SQLite.swift provides compile-time confidence in SQL statement syntax and
|
||||
intent.
|
||||
DESC
|
||||
|
||||
s.homepage = "https://github.com/stephencelis/SQLite.swift"
|
||||
s.license = 'MIT'
|
||||
s.author = { "Stephen Celis" => "stephen@stephencelis.com" }
|
||||
s.source = { :git => "https://github.com/stephencelis/SQLite.swift.git", :tag => s.version.to_s }
|
||||
s.social_media_url = 'https://twitter.com/stephencelis'
|
||||
|
||||
s.module_name = 'SQLite'
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
s.osx.deployment_target = "10.9"
|
||||
s.watchos.deployment_target = "2.0"
|
||||
s.default_subspec = 'standard'
|
||||
s.pod_target_xcconfig = {
|
||||
'SWIFT_VERSION' => '3.0',
|
||||
}
|
||||
|
||||
s.subspec 'standard' do |ss|
|
||||
ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}'
|
||||
ss.exclude_files = 'Sources/**/Cipher.swift'
|
||||
ss.private_header_files = 'Sources/SQLiteObjc/*.h'
|
||||
|
||||
ss.library = 'sqlite3'
|
||||
ss.preserve_paths = 'CocoaPods/**/*'
|
||||
ss.pod_target_xcconfig = {
|
||||
'SWIFT_INCLUDE_PATHS[sdk=macosx*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=macosx10.11]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx-10.11',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=macosx10.12]' => '$(SRCROOT)/SQLite.swift/CocoaPods/macosx-10.12',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=iphoneos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphoneos',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=iphoneos10.0]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphoneos-10.0',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphonesimulator',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator10.0]' => '$(SRCROOT)/SQLite.swift/CocoaPods/iphonesimulator-10.0',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=appletvos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/appletvos',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=appletvsimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/appletvsimulator',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=watchos*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/watchos',
|
||||
'SWIFT_INCLUDE_PATHS[sdk=watchsimulator*]' => '$(SRCROOT)/SQLite.swift/CocoaPods/watchsimulator'
|
||||
}
|
||||
end
|
||||
|
||||
s.subspec 'standalone' do |ss|
|
||||
ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}'
|
||||
ss.exclude_files = 'Sources/**/Cipher.swift'
|
||||
ss.private_header_files = 'Sources/SQLiteObjc/*.h'
|
||||
ss.xcconfig = {
|
||||
'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_STANDALONE'
|
||||
}
|
||||
|
||||
ss.dependency 'sqlite3', '>= 3.14.0'
|
||||
end
|
||||
|
||||
s.subspec 'SQLCipher' do |ss|
|
||||
ss.source_files = 'Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}'
|
||||
ss.private_header_files = 'Sources/SQLiteObjc/*.h'
|
||||
ss.xcconfig = {
|
||||
'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLITE_SWIFT_SQLCIPHER',
|
||||
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SQLITE_HAS_CODEC=1'
|
||||
}
|
||||
|
||||
ss.dependency 'SQLCipher', '>= 3.4.0'
|
||||
end
|
||||
end
|
||||
1513
mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.pbxproj
vendored
Normal file
1513
mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.pbxproj
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
vendored
Normal file
7
mobile/ios/ThirdParty/SQLite.swift/SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:SQLite.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
60
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Blob.swift
vendored
Normal file
60
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Blob.swift
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
public struct Blob {
|
||||
|
||||
public let bytes: [UInt8]
|
||||
|
||||
public init(bytes: [UInt8]) {
|
||||
self.bytes = bytes
|
||||
}
|
||||
|
||||
public init(bytes: UnsafeRawPointer, length: Int) {
|
||||
let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length)
|
||||
self.init(bytes: [UInt8](i8bufptr))
|
||||
}
|
||||
|
||||
public func toHex() -> String {
|
||||
return bytes.map {
|
||||
($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false)
|
||||
}.joined(separator: "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Blob : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return "x'\(toHex())'"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Blob : Equatable {
|
||||
|
||||
}
|
||||
|
||||
public func ==(lhs: Blob, rhs: Blob) -> Bool {
|
||||
return lhs.bytes == rhs.bytes
|
||||
}
|
||||
756
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Connection.swift
vendored
Normal file
756
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Connection.swift
vendored
Normal file
|
|
@ -0,0 +1,756 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation.NSUUID
|
||||
import Dispatch
|
||||
#if SQLITE_SWIFT_STANDALONE
|
||||
import sqlite3
|
||||
#elseif SQLITE_SWIFT_SQLCIPHER
|
||||
import SQLCipher
|
||||
#else
|
||||
import SQLite3
|
||||
#endif
|
||||
|
||||
/// A connection to SQLite.
|
||||
public final class Connection {
|
||||
|
||||
/// The location of a SQLite database.
|
||||
public enum Location {
|
||||
|
||||
/// An in-memory database (equivalent to `.URI(":memory:")`).
|
||||
///
|
||||
/// See: <https://www.sqlite.org/inmemorydb.html#sharedmemdb>
|
||||
case inMemory
|
||||
|
||||
/// A temporary, file-backed database (equivalent to `.URI("")`).
|
||||
///
|
||||
/// See: <https://www.sqlite.org/inmemorydb.html#temp_db>
|
||||
case temporary
|
||||
|
||||
/// A database located at the given URI filename (or path).
|
||||
///
|
||||
/// See: <https://www.sqlite.org/uri.html>
|
||||
///
|
||||
/// - Parameter filename: A URI filename
|
||||
case uri(String)
|
||||
}
|
||||
|
||||
/// An SQL operation passed to update callbacks.
|
||||
public enum Operation {
|
||||
|
||||
/// An INSERT operation.
|
||||
case insert
|
||||
|
||||
/// An UPDATE operation.
|
||||
case update
|
||||
|
||||
/// A DELETE operation.
|
||||
case delete
|
||||
|
||||
fileprivate init(rawValue:Int32) {
|
||||
switch rawValue {
|
||||
case SQLITE_INSERT:
|
||||
self = .insert
|
||||
case SQLITE_UPDATE:
|
||||
self = .update
|
||||
case SQLITE_DELETE:
|
||||
self = .delete
|
||||
default:
|
||||
fatalError("unhandled operation code: \(rawValue)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var handle: OpaquePointer { return _handle! }
|
||||
|
||||
fileprivate var _handle: OpaquePointer? = nil
|
||||
|
||||
/// Initializes a new SQLite connection.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - location: The location of the database. Creates a new database if it
|
||||
/// doesn’t already exist (unless in read-only mode).
|
||||
///
|
||||
/// Default: `.InMemory`.
|
||||
///
|
||||
/// - readonly: Whether or not to open the database in a read-only state.
|
||||
///
|
||||
/// Default: `false`.
|
||||
///
|
||||
/// - Returns: A new database connection.
|
||||
public init(_ location: Location = .inMemory, readonly: Bool = false) throws {
|
||||
let flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
|
||||
try check(sqlite3_open_v2(location.description, &_handle, flags | SQLITE_OPEN_FULLMUTEX, nil))
|
||||
queue.setSpecific(key: Connection.queueKey, value: queueContext)
|
||||
}
|
||||
|
||||
/// Initializes a new connection to a database.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - filename: The location of the database. Creates a new database if
|
||||
/// it doesn’t already exist (unless in read-only mode).
|
||||
///
|
||||
/// - readonly: Whether or not to open the database in a read-only state.
|
||||
///
|
||||
/// Default: `false`.
|
||||
///
|
||||
/// - Throws: `Result.Error` iff a connection cannot be established.
|
||||
///
|
||||
/// - Returns: A new database connection.
|
||||
public convenience init(_ filename: String, readonly: Bool = false) throws {
|
||||
try self.init(.uri(filename), readonly: readonly)
|
||||
}
|
||||
|
||||
deinit {
|
||||
sqlite3_close(handle)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
/// Whether or not the database was opened in a read-only state.
|
||||
public var readonly: Bool { return sqlite3_db_readonly(handle, nil) == 1 }
|
||||
|
||||
/// The last rowid inserted into the database via this connection.
|
||||
public var lastInsertRowid: Int64 {
|
||||
return sqlite3_last_insert_rowid(handle)
|
||||
}
|
||||
|
||||
/// The last number of changes (inserts, updates, or deletes) made to the
|
||||
/// database via this connection.
|
||||
public var changes: Int {
|
||||
return Int(sqlite3_changes(handle))
|
||||
}
|
||||
|
||||
/// The total number of changes (inserts, updates, or deletes) made to the
|
||||
/// database via this connection.
|
||||
public var totalChanges: Int {
|
||||
return Int(sqlite3_total_changes(handle))
|
||||
}
|
||||
|
||||
// MARK: - Execute
|
||||
|
||||
/// Executes a batch of SQL statements.
|
||||
///
|
||||
/// - Parameter SQL: A batch of zero or more semicolon-separated SQL
|
||||
/// statements.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
public func execute(_ SQL: String) throws {
|
||||
_ = try sync { try self.check(sqlite3_exec(self.handle, SQL, nil, nil, nil)) }
|
||||
}
|
||||
|
||||
// MARK: - Prepare
|
||||
|
||||
/// Prepares a single SQL statement (with optional parameter bindings).
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: A prepared statement.
|
||||
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement {
|
||||
if !bindings.isEmpty { return try prepare(statement, bindings) }
|
||||
return try Statement(self, statement)
|
||||
}
|
||||
|
||||
/// Prepares a single SQL statement and binds parameters to it.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: A prepared statement.
|
||||
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
|
||||
return try prepare(statement).bind(bindings)
|
||||
}
|
||||
|
||||
/// Prepares a single SQL statement and binds parameters to it.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A dictionary of named parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: A prepared statement.
|
||||
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
|
||||
return try prepare(statement).bind(bindings)
|
||||
}
|
||||
|
||||
// MARK: - Run
|
||||
|
||||
/// Runs a single SQL statement (with optional parameter bindings).
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement.
|
||||
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement {
|
||||
return try run(statement, bindings)
|
||||
}
|
||||
|
||||
/// Prepares, binds, and runs a single SQL statement.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement.
|
||||
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
|
||||
return try prepare(statement).run(bindings)
|
||||
}
|
||||
|
||||
/// Prepares, binds, and runs a single SQL statement.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A dictionary of named parameters to bind to the statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement.
|
||||
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
|
||||
return try prepare(statement).run(bindings)
|
||||
}
|
||||
|
||||
// MARK: - Scalar
|
||||
|
||||
/// Runs a single SQL statement (with optional parameter bindings),
|
||||
/// returning the first value of the first row.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? {
|
||||
return try scalar(statement, bindings)
|
||||
}
|
||||
|
||||
/// Runs a single SQL statement (with optional parameter bindings),
|
||||
/// returning the first value of the first row.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? {
|
||||
return try prepare(statement).scalar(bindings)
|
||||
}
|
||||
|
||||
/// Runs a single SQL statement (with optional parameter bindings),
|
||||
/// returning the first value of the first row.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - statement: A single SQL statement.
|
||||
///
|
||||
/// - bindings: A dictionary of named parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? {
|
||||
return try prepare(statement).scalar(bindings)
|
||||
}
|
||||
|
||||
// MARK: - Transactions
|
||||
|
||||
/// The mode in which a transaction acquires a lock.
|
||||
public enum TransactionMode : String {
|
||||
|
||||
/// Defers locking the database till the first read/write executes.
|
||||
case deferred = "DEFERRED"
|
||||
|
||||
/// Immediately acquires a reserved lock on the database.
|
||||
case immediate = "IMMEDIATE"
|
||||
|
||||
/// Immediately acquires an exclusive lock on all databases.
|
||||
case exclusive = "EXCLUSIVE"
|
||||
|
||||
}
|
||||
|
||||
// TODO: Consider not requiring a throw to roll back?
|
||||
/// Runs a transaction with the given mode.
|
||||
///
|
||||
/// - Note: Transactions cannot be nested. To nest transactions, see
|
||||
/// `savepoint()`, instead.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - mode: The mode in which a transaction acquires a lock.
|
||||
///
|
||||
/// Default: `.Deferred`
|
||||
///
|
||||
/// - block: A closure to run SQL statements within the transaction.
|
||||
/// The transaction will be committed when the block returns. The block
|
||||
/// must throw to roll the transaction back.
|
||||
///
|
||||
/// - Throws: `Result.Error`, and rethrows.
|
||||
public func transaction(_ mode: TransactionMode = .deferred, block: @escaping () throws -> Void) throws {
|
||||
try transaction("BEGIN \(mode.rawValue) TRANSACTION", block, "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION")
|
||||
}
|
||||
|
||||
// TODO: Consider not requiring a throw to roll back?
|
||||
// TODO: Consider removing ability to set a name?
|
||||
/// Runs a transaction with the given savepoint name (if omitted, it will
|
||||
/// generate a UUID).
|
||||
///
|
||||
/// - SeeAlso: `transaction()`.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - savepointName: A unique identifier for the savepoint (optional).
|
||||
///
|
||||
/// - block: A closure to run SQL statements within the transaction.
|
||||
/// The savepoint will be released (committed) when the block returns.
|
||||
/// The block must throw to roll the savepoint back.
|
||||
///
|
||||
/// - Throws: `SQLite.Result.Error`, and rethrows.
|
||||
public func savepoint(_ name: String = UUID().uuidString, block: @escaping () throws -> Void) throws {
|
||||
let name = name.quote("'")
|
||||
let savepoint = "SAVEPOINT \(name)"
|
||||
|
||||
try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)")
|
||||
}
|
||||
|
||||
fileprivate func transaction(_ begin: String, _ block: @escaping () throws -> Void, _ commit: String, or rollback: String) throws {
|
||||
return try sync {
|
||||
try self.run(begin)
|
||||
do {
|
||||
try block()
|
||||
} catch {
|
||||
try self.run(rollback)
|
||||
throw error
|
||||
}
|
||||
try self.run(commit)
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupts any long-running queries.
|
||||
public func interrupt() {
|
||||
sqlite3_interrupt(handle)
|
||||
}
|
||||
|
||||
// MARK: - Handlers
|
||||
|
||||
/// The number of seconds a connection will attempt to retry a statement
|
||||
/// after encountering a busy signal (lock).
|
||||
public var busyTimeout: Double = 0 {
|
||||
didSet {
|
||||
sqlite3_busy_timeout(handle, Int32(busyTimeout * 1_000))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a handler to call after encountering a busy signal (lock).
|
||||
///
|
||||
/// - Parameter callback: This block is executed during a lock in which a
|
||||
/// busy error would otherwise be returned. It’s passed the number of
|
||||
/// times it’s been called for this lock. If it returns `true`, it will
|
||||
/// try again. If it returns `false`, no further attempts will be made.
|
||||
public func busyHandler(_ callback: ((_ tries: Int) -> Bool)?) {
|
||||
guard let callback = callback else {
|
||||
sqlite3_busy_handler(handle, nil, nil)
|
||||
busyHandler = nil
|
||||
return
|
||||
}
|
||||
|
||||
let box: BusyHandler = { callback(Int($0)) ? 1 : 0 }
|
||||
sqlite3_busy_handler(handle, { callback, tries in
|
||||
unsafeBitCast(callback, to: BusyHandler.self)(tries)
|
||||
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
|
||||
busyHandler = box
|
||||
}
|
||||
fileprivate typealias BusyHandler = @convention(block) (Int32) -> Int32
|
||||
fileprivate var busyHandler: BusyHandler?
|
||||
|
||||
/// Sets a handler to call when a statement is executed with the compiled
|
||||
/// SQL.
|
||||
///
|
||||
/// - Parameter callback: This block is invoked when a statement is executed
|
||||
/// with the compiled SQL as its argument.
|
||||
///
|
||||
/// db.trace { SQL in print(SQL) }
|
||||
public func trace(_ callback: ((String) -> Void)?) {
|
||||
#if SQLITE_SWIFT_SQLCIPHER
|
||||
trace_v1(callback)
|
||||
#else
|
||||
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
|
||||
trace_v2(callback)
|
||||
} else {
|
||||
trace_v1(callback)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fileprivate func trace_v1(_ callback: ((String) -> Void)?) {
|
||||
guard let callback = callback else {
|
||||
sqlite3_trace(handle, nil /* xCallback */, nil /* pCtx */)
|
||||
trace = nil
|
||||
return
|
||||
}
|
||||
let box: Trace = { (pointer: UnsafeRawPointer) in
|
||||
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
|
||||
}
|
||||
sqlite3_trace(handle,
|
||||
{
|
||||
(C: UnsafeMutableRawPointer?, SQL: UnsafePointer<Int8>?) in
|
||||
if let C = C, let SQL = SQL {
|
||||
unsafeBitCast(C, to: Trace.self)(SQL)
|
||||
}
|
||||
},
|
||||
unsafeBitCast(box, to: UnsafeMutableRawPointer.self)
|
||||
)
|
||||
trace = box
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fileprivate typealias Trace = @convention(block) (UnsafeRawPointer) -> Void
|
||||
fileprivate var trace: Trace?
|
||||
|
||||
/// Registers a callback to be invoked whenever a row is inserted, updated,
|
||||
/// or deleted in a rowid table.
|
||||
///
|
||||
/// - Parameter callback: A callback invoked with the `Operation` (one of
|
||||
/// `.Insert`, `.Update`, or `.Delete`), database name, table name, and
|
||||
/// rowid.
|
||||
public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) {
|
||||
guard let callback = callback else {
|
||||
sqlite3_update_hook(handle, nil, nil)
|
||||
updateHook = nil
|
||||
return
|
||||
}
|
||||
|
||||
let box: UpdateHook = {
|
||||
callback(
|
||||
Operation(rawValue: $0),
|
||||
String(cString: $1),
|
||||
String(cString: $2),
|
||||
$3
|
||||
)
|
||||
}
|
||||
sqlite3_update_hook(handle, { callback, operation, db, table, rowid in
|
||||
unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid)
|
||||
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
|
||||
updateHook = box
|
||||
}
|
||||
fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer<Int8>, UnsafePointer<Int8>, Int64) -> Void
|
||||
fileprivate var updateHook: UpdateHook?
|
||||
|
||||
/// Registers a callback to be invoked whenever a transaction is committed.
|
||||
///
|
||||
/// - Parameter callback: A callback invoked whenever a transaction is
|
||||
/// committed. If this callback throws, the transaction will be rolled
|
||||
/// back.
|
||||
public func commitHook(_ callback: (() throws -> Void)?) {
|
||||
guard let callback = callback else {
|
||||
sqlite3_commit_hook(handle, nil, nil)
|
||||
commitHook = nil
|
||||
return
|
||||
}
|
||||
|
||||
let box: CommitHook = {
|
||||
do {
|
||||
try callback()
|
||||
} catch {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
sqlite3_commit_hook(handle, { callback in
|
||||
unsafeBitCast(callback, to: CommitHook.self)()
|
||||
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
|
||||
commitHook = box
|
||||
}
|
||||
fileprivate typealias CommitHook = @convention(block) () -> Int32
|
||||
fileprivate var commitHook: CommitHook?
|
||||
|
||||
/// Registers a callback to be invoked whenever a transaction rolls back.
|
||||
///
|
||||
/// - Parameter callback: A callback invoked when a transaction is rolled
|
||||
/// back.
|
||||
public func rollbackHook(_ callback: (() -> Void)?) {
|
||||
guard let callback = callback else {
|
||||
sqlite3_rollback_hook(handle, nil, nil)
|
||||
rollbackHook = nil
|
||||
return
|
||||
}
|
||||
|
||||
let box: RollbackHook = { callback() }
|
||||
sqlite3_rollback_hook(handle, { callback in
|
||||
unsafeBitCast(callback, to: RollbackHook.self)()
|
||||
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
|
||||
rollbackHook = box
|
||||
}
|
||||
fileprivate typealias RollbackHook = @convention(block) () -> Void
|
||||
fileprivate var rollbackHook: RollbackHook?
|
||||
|
||||
/// Creates or redefines a custom SQL function.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - function: The name of the function to create or redefine.
|
||||
///
|
||||
/// - argumentCount: The number of arguments that the function takes. If
|
||||
/// `nil`, the function may take any number of arguments.
|
||||
///
|
||||
/// Default: `nil`
|
||||
///
|
||||
/// - deterministic: Whether or not the function is deterministic (_i.e._
|
||||
/// the function always returns the same result for a given input).
|
||||
///
|
||||
/// Default: `false`
|
||||
///
|
||||
/// - block: A block of code to run when the function is called. The block
|
||||
/// is called with an array of raw SQL values mapped to the function’s
|
||||
/// parameters and should return a raw SQL value (or nil).
|
||||
public func createFunction(_ function: String, argumentCount: UInt? = nil, deterministic: Bool = false, _ block: @escaping (_ args: [Binding?]) -> Binding?) {
|
||||
let argc = argumentCount.map { Int($0) } ?? -1
|
||||
let box: Function = { context, argc, argv in
|
||||
let arguments: [Binding?] = (0..<Int(argc)).map { idx in
|
||||
let value = argv![idx]
|
||||
switch sqlite3_value_type(value) {
|
||||
case SQLITE_BLOB:
|
||||
return Blob(bytes: sqlite3_value_blob(value), length: Int(sqlite3_value_bytes(value)))
|
||||
case SQLITE_FLOAT:
|
||||
return sqlite3_value_double(value)
|
||||
case SQLITE_INTEGER:
|
||||
return sqlite3_value_int64(value)
|
||||
case SQLITE_NULL:
|
||||
return nil
|
||||
case SQLITE_TEXT:
|
||||
return String(cString: UnsafePointer(sqlite3_value_text(value)))
|
||||
case let type:
|
||||
fatalError("unsupported value type: \(type)")
|
||||
}
|
||||
}
|
||||
let result = block(arguments)
|
||||
if let result = result as? Blob {
|
||||
sqlite3_result_blob(context, result.bytes, Int32(result.bytes.count), nil)
|
||||
} else if let result = result as? Double {
|
||||
sqlite3_result_double(context, result)
|
||||
} else if let result = result as? Int64 {
|
||||
sqlite3_result_int64(context, result)
|
||||
} else if let result = result as? String {
|
||||
sqlite3_result_text(context, result, Int32(result.characters.count), SQLITE_TRANSIENT)
|
||||
} else if result == nil {
|
||||
sqlite3_result_null(context)
|
||||
} else {
|
||||
fatalError("unsupported result type: \(result)")
|
||||
}
|
||||
}
|
||||
var flags = SQLITE_UTF8
|
||||
if deterministic {
|
||||
flags |= SQLITE_DETERMINISTIC
|
||||
}
|
||||
sqlite3_create_function_v2(handle, function, Int32(argc), flags, unsafeBitCast(box, to: UnsafeMutableRawPointer.self), { context, argc, value in
|
||||
let function = unsafeBitCast(sqlite3_user_data(context), to: Function.self)
|
||||
function(context, argc, value)
|
||||
}, nil, nil, nil)
|
||||
if functions[function] == nil { self.functions[function] = [:] }
|
||||
functions[function]?[argc] = box
|
||||
}
|
||||
fileprivate typealias Function = @convention(block) (OpaquePointer?, Int32, UnsafeMutablePointer<OpaquePointer?>?) -> Void
|
||||
fileprivate var functions = [String: [Int: Function]]()
|
||||
|
||||
/// Defines a new collating sequence.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - collation: The name of the collation added.
|
||||
///
|
||||
/// - block: A collation function that takes two strings and returns the
|
||||
/// comparison result.
|
||||
public func createCollation(_ collation: String, _ block: @escaping (_ lhs: String, _ rhs: String) -> ComparisonResult) throws {
|
||||
let box: Collation = { (lhs: UnsafeRawPointer, rhs: UnsafeRawPointer) in
|
||||
let lstr = String(cString: lhs.assumingMemoryBound(to: UInt8.self))
|
||||
let rstr = String(cString: rhs.assumingMemoryBound(to: UInt8.self))
|
||||
return Int32(block(lstr, rstr).rawValue)
|
||||
}
|
||||
try check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8,
|
||||
unsafeBitCast(box, to: UnsafeMutableRawPointer.self),
|
||||
{ (callback: UnsafeMutableRawPointer?, _, lhs: UnsafeRawPointer?, _, rhs: UnsafeRawPointer?) in /* xCompare */
|
||||
if let lhs = lhs, let rhs = rhs {
|
||||
return unsafeBitCast(callback, to: Collation.self)(lhs, rhs)
|
||||
} else {
|
||||
fatalError("sqlite3_create_collation_v2 callback called with NULL pointer")
|
||||
}
|
||||
}, nil /* xDestroy */))
|
||||
collations[collation] = box
|
||||
}
|
||||
fileprivate typealias Collation = @convention(block) (UnsafeRawPointer, UnsafeRawPointer) -> Int32
|
||||
fileprivate var collations = [String: Collation]()
|
||||
|
||||
// MARK: - Error Handling
|
||||
|
||||
func sync<T>(_ block: @escaping () throws -> T) rethrows -> T {
|
||||
var success: T?
|
||||
var failure: Error?
|
||||
|
||||
let box: () -> Void = {
|
||||
do {
|
||||
success = try block()
|
||||
} catch {
|
||||
failure = error
|
||||
}
|
||||
}
|
||||
|
||||
if DispatchQueue.getSpecific(key: Connection.queueKey) == queueContext {
|
||||
box()
|
||||
} else {
|
||||
queue.sync(execute: box) // FIXME: rdar://problem/21389236
|
||||
}
|
||||
|
||||
if let failure = failure {
|
||||
try { () -> Void in throw failure }()
|
||||
}
|
||||
|
||||
return success!
|
||||
}
|
||||
|
||||
@discardableResult func check(_ resultCode: Int32, statement: Statement? = nil) throws -> Int32 {
|
||||
guard let error = Result(errorCode: resultCode, connection: self, statement: statement) else {
|
||||
return resultCode
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
|
||||
fileprivate var queue = DispatchQueue(label: "SQLite.Database", attributes: [])
|
||||
|
||||
fileprivate static let queueKey = DispatchSpecificKey<Int>()
|
||||
|
||||
fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self)
|
||||
|
||||
}
|
||||
|
||||
extension Connection : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return String(cString: sqlite3_db_filename(handle, nil))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Connection.Location : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .inMemory:
|
||||
return ":memory:"
|
||||
case .temporary:
|
||||
return ""
|
||||
case .uri(let URI):
|
||||
return URI
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum Result : Error {
|
||||
|
||||
fileprivate static let successCodes: Set = [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]
|
||||
|
||||
case error(message: String, code: Int32, statement: Statement?)
|
||||
|
||||
init?(errorCode: Int32, connection: Connection, statement: Statement? = nil) {
|
||||
guard !Result.successCodes.contains(errorCode) else { return nil }
|
||||
|
||||
let message = String(cString: sqlite3_errmsg(connection.handle))
|
||||
self = .error(message: message, code: errorCode, statement: statement)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Result : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case let .error(message, errorCode, statement):
|
||||
if let statement = statement {
|
||||
return "\(message) (\(statement)) (code: \(errorCode))"
|
||||
} else {
|
||||
return "\(message) (code: \(errorCode))"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !SQLITE_SWIFT_SQLCIPHER
|
||||
@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)
|
||||
extension Connection {
|
||||
fileprivate func trace_v2(_ callback: ((String) -> Void)?) {
|
||||
guard let callback = callback else {
|
||||
// If the X callback is NULL or if the M mask is zero, then tracing is disabled.
|
||||
sqlite3_trace_v2(handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */)
|
||||
trace = nil
|
||||
return
|
||||
}
|
||||
|
||||
let box: Trace = { (pointer: UnsafeRawPointer) in
|
||||
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
|
||||
}
|
||||
sqlite3_trace_v2(handle,
|
||||
UInt32(SQLITE_TRACE_STMT) /* mask */,
|
||||
{
|
||||
// A trace callback is invoked with four arguments: callback(T,C,P,X).
|
||||
// The T argument is one of the SQLITE_TRACE constants to indicate why the
|
||||
// callback was invoked. The C argument is a copy of the context pointer.
|
||||
// The P and X arguments are pointers whose meanings depend on T.
|
||||
(T: UInt32, C: UnsafeMutableRawPointer?, P: UnsafeMutableRawPointer?, X: UnsafeMutableRawPointer?) in
|
||||
if let P = P,
|
||||
let expandedSQL = sqlite3_expanded_sql(OpaquePointer(P)) {
|
||||
unsafeBitCast(C, to: Trace.self)(expandedSQL)
|
||||
sqlite3_free(expandedSQL)
|
||||
}
|
||||
return Int32(0) // currently ignored
|
||||
},
|
||||
unsafeBitCast(box, to: UnsafeMutableRawPointer.self) /* pCtx */
|
||||
)
|
||||
trace = box
|
||||
}
|
||||
}
|
||||
#endif
|
||||
297
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Statement.swift
vendored
Normal file
297
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Statement.swift
vendored
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#if SQLITE_SWIFT_STANDALONE
|
||||
import sqlite3
|
||||
#elseif SQLITE_SWIFT_SQLCIPHER
|
||||
import SQLCipher
|
||||
#else
|
||||
import SQLite3
|
||||
#endif
|
||||
|
||||
/// A single SQL statement.
|
||||
public final class Statement {
|
||||
|
||||
fileprivate var handle: OpaquePointer? = nil
|
||||
|
||||
fileprivate let connection: Connection
|
||||
|
||||
init(_ connection: Connection, _ SQL: String) throws {
|
||||
self.connection = connection
|
||||
try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil))
|
||||
}
|
||||
|
||||
deinit {
|
||||
sqlite3_finalize(handle)
|
||||
}
|
||||
|
||||
public lazy var columnCount: Int = Int(sqlite3_column_count(self.handle))
|
||||
|
||||
public lazy var columnNames: [String] = (0..<Int32(self.columnCount)).map {
|
||||
String(cString: sqlite3_column_name(self.handle, $0))
|
||||
}
|
||||
|
||||
/// A cursor pointing to the current row.
|
||||
public lazy var row: Cursor = Cursor(self)
|
||||
|
||||
/// Binds a list of parameters to a statement.
|
||||
///
|
||||
/// - Parameter values: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
public func bind(_ values: Binding?...) -> Statement {
|
||||
return bind(values)
|
||||
}
|
||||
|
||||
/// Binds a list of parameters to a statement.
|
||||
///
|
||||
/// - Parameter values: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
public func bind(_ values: [Binding?]) -> Statement {
|
||||
if values.isEmpty { return self }
|
||||
reset()
|
||||
guard values.count == Int(sqlite3_bind_parameter_count(handle)) else {
|
||||
fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed")
|
||||
}
|
||||
for idx in 1...values.count { bind(values[idx - 1], atIndex: idx) }
|
||||
return self
|
||||
}
|
||||
|
||||
/// Binds a dictionary of named parameters to a statement.
|
||||
///
|
||||
/// - Parameter values: A dictionary of named parameters to bind to the
|
||||
/// statement.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
public func bind(_ values: [String: Binding?]) -> Statement {
|
||||
reset()
|
||||
for (name, value) in values {
|
||||
let idx = sqlite3_bind_parameter_index(handle, name)
|
||||
guard idx > 0 else {
|
||||
fatalError("parameter not found: \(name)")
|
||||
}
|
||||
bind(value, atIndex: Int(idx))
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
fileprivate func bind(_ value: Binding?, atIndex idx: Int) {
|
||||
if value == nil {
|
||||
sqlite3_bind_null(handle, Int32(idx))
|
||||
} else if let value = value as? Blob {
|
||||
sqlite3_bind_blob(handle, Int32(idx), value.bytes, Int32(value.bytes.count), SQLITE_TRANSIENT)
|
||||
} else if let value = value as? Double {
|
||||
sqlite3_bind_double(handle, Int32(idx), value)
|
||||
} else if let value = value as? Int64 {
|
||||
sqlite3_bind_int64(handle, Int32(idx), value)
|
||||
} else if let value = value as? String {
|
||||
sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT)
|
||||
} else if let value = value as? Int {
|
||||
self.bind(value.datatypeValue, atIndex: idx)
|
||||
} else if let value = value as? Bool {
|
||||
self.bind(value.datatypeValue, atIndex: idx)
|
||||
} else if let value = value {
|
||||
fatalError("tried to bind unexpected value \(value)")
|
||||
}
|
||||
}
|
||||
|
||||
/// - Parameter bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement {
|
||||
guard bindings.isEmpty else {
|
||||
return try run(bindings)
|
||||
}
|
||||
|
||||
reset(clearBindings: false)
|
||||
repeat {} while try step()
|
||||
return self
|
||||
}
|
||||
|
||||
/// - Parameter bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement {
|
||||
return try bind(bindings).run()
|
||||
}
|
||||
|
||||
/// - Parameter bindings: A dictionary of named parameters to bind to the
|
||||
/// statement.
|
||||
///
|
||||
/// - Throws: `Result.Error` if query execution fails.
|
||||
///
|
||||
/// - Returns: The statement object (useful for chaining).
|
||||
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement {
|
||||
return try bind(bindings).run()
|
||||
}
|
||||
|
||||
/// - Parameter bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ bindings: Binding?...) throws -> Binding? {
|
||||
guard bindings.isEmpty else {
|
||||
return try scalar(bindings)
|
||||
}
|
||||
|
||||
reset(clearBindings: false)
|
||||
_ = try step()
|
||||
return row[0]
|
||||
}
|
||||
|
||||
/// - Parameter bindings: A list of parameters to bind to the statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ bindings: [Binding?]) throws -> Binding? {
|
||||
return try bind(bindings).scalar()
|
||||
}
|
||||
|
||||
|
||||
/// - Parameter bindings: A dictionary of named parameters to bind to the
|
||||
/// statement.
|
||||
///
|
||||
/// - Returns: The first value of the first row returned.
|
||||
public func scalar(_ bindings: [String: Binding?]) throws -> Binding? {
|
||||
return try bind(bindings).scalar()
|
||||
}
|
||||
|
||||
public func step() throws -> Bool {
|
||||
return try connection.sync { try self.connection.check(sqlite3_step(self.handle)) == SQLITE_ROW }
|
||||
}
|
||||
|
||||
fileprivate func reset(clearBindings shouldClear: Bool = true) {
|
||||
sqlite3_reset(handle)
|
||||
if (shouldClear) { sqlite3_clear_bindings(handle) }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Statement : Sequence {
|
||||
|
||||
public func makeIterator() -> Statement {
|
||||
reset(clearBindings: false)
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Statement : IteratorProtocol {
|
||||
|
||||
public func next() -> [Binding?]? {
|
||||
return try! step() ? Array(row) : nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Statement : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return String(cString: sqlite3_sql(handle))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct Cursor {
|
||||
|
||||
fileprivate let handle: OpaquePointer
|
||||
|
||||
fileprivate let columnCount: Int
|
||||
|
||||
fileprivate init(_ statement: Statement) {
|
||||
handle = statement.handle!
|
||||
columnCount = statement.columnCount
|
||||
}
|
||||
|
||||
public subscript(idx: Int) -> Double {
|
||||
return sqlite3_column_double(handle, Int32(idx))
|
||||
}
|
||||
|
||||
public subscript(idx: Int) -> Int64 {
|
||||
return sqlite3_column_int64(handle, Int32(idx))
|
||||
}
|
||||
|
||||
public subscript(idx: Int) -> String {
|
||||
return String(cString: UnsafePointer(sqlite3_column_text(handle, Int32(idx))))
|
||||
}
|
||||
|
||||
public subscript(idx: Int) -> Blob {
|
||||
if let pointer = sqlite3_column_blob(handle, Int32(idx)) {
|
||||
let length = Int(sqlite3_column_bytes(handle, Int32(idx)))
|
||||
return Blob(bytes: pointer, length: length)
|
||||
} else {
|
||||
// The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
||||
// https://www.sqlite.org/c3ref/column_blob.html
|
||||
return Blob(bytes: [])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public subscript(idx: Int) -> Bool {
|
||||
return Bool.fromDatatypeValue(self[idx])
|
||||
}
|
||||
|
||||
public subscript(idx: Int) -> Int {
|
||||
return Int.fromDatatypeValue(self[idx])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Cursors provide direct access to a statement’s current row.
|
||||
extension Cursor : Sequence {
|
||||
|
||||
public subscript(idx: Int) -> Binding? {
|
||||
switch sqlite3_column_type(handle, Int32(idx)) {
|
||||
case SQLITE_BLOB:
|
||||
return self[idx] as Blob
|
||||
case SQLITE_FLOAT:
|
||||
return self[idx] as Double
|
||||
case SQLITE_INTEGER:
|
||||
return self[idx] as Int64
|
||||
case SQLITE_NULL:
|
||||
return nil
|
||||
case SQLITE_TEXT:
|
||||
return self[idx] as String
|
||||
case let type:
|
||||
fatalError("unsupported column type: \(type)")
|
||||
}
|
||||
}
|
||||
|
||||
public func makeIterator() -> AnyIterator<Binding?> {
|
||||
var idx = 0
|
||||
return AnyIterator {
|
||||
if idx >= self.columnCount {
|
||||
return Optional<Binding?>.none
|
||||
} else {
|
||||
idx += 1
|
||||
return self[idx - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
132
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Value.swift
vendored
Normal file
132
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Core/Value.swift
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
/// - Warning: `Binding` is a protocol that SQLite.swift uses internally to
|
||||
/// directly map SQLite types to Swift types.
|
||||
///
|
||||
/// Do not conform custom types to the Binding protocol. See the `Value`
|
||||
/// protocol, instead.
|
||||
public protocol Binding {}
|
||||
|
||||
public protocol Number : Binding {}
|
||||
|
||||
public protocol Value : Expressible { // extensions cannot have inheritance clauses
|
||||
|
||||
associatedtype ValueType = Self
|
||||
|
||||
associatedtype Datatype : Binding
|
||||
|
||||
static var declaredDatatype: String { get }
|
||||
|
||||
static func fromDatatypeValue(_ datatypeValue: Datatype) -> ValueType
|
||||
|
||||
var datatypeValue: Datatype { get }
|
||||
|
||||
}
|
||||
|
||||
extension Double : Number, Value {
|
||||
|
||||
public static let declaredDatatype = "REAL"
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: Double) -> Double {
|
||||
return datatypeValue
|
||||
}
|
||||
|
||||
public var datatypeValue: Double {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Int64 : Number, Value {
|
||||
|
||||
public static let declaredDatatype = "INTEGER"
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 {
|
||||
return datatypeValue
|
||||
}
|
||||
|
||||
public var datatypeValue: Int64 {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension String : Binding, Value {
|
||||
|
||||
public static let declaredDatatype = "TEXT"
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: String) -> String {
|
||||
return datatypeValue
|
||||
}
|
||||
|
||||
public var datatypeValue: String {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Blob : Binding, Value {
|
||||
|
||||
public static let declaredDatatype = "BLOB"
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob {
|
||||
return datatypeValue
|
||||
}
|
||||
|
||||
public var datatypeValue: Blob {
|
||||
return self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
extension Bool : Binding, Value {
|
||||
|
||||
public static var declaredDatatype = Int64.declaredDatatype
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool {
|
||||
return datatypeValue != 0
|
||||
}
|
||||
|
||||
public var datatypeValue: Int64 {
|
||||
return self ? 1 : 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Int : Number, Value {
|
||||
|
||||
public static var declaredDatatype = Int64.declaredDatatype
|
||||
|
||||
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int {
|
||||
return Int(datatypeValue)
|
||||
}
|
||||
|
||||
public var datatypeValue: Int64 {
|
||||
return Int64(self)
|
||||
}
|
||||
|
||||
}
|
||||
61
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift
vendored
Normal file
61
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#if SQLITE_SWIFT_SQLCIPHER
|
||||
import SQLCipher
|
||||
|
||||
|
||||
/// Extension methods for [SQLCipher](https://www.zetetic.net/sqlcipher/).
|
||||
/// @see [sqlcipher api](https://www.zetetic.net/sqlcipher/sqlcipher-api/)
|
||||
extension Connection {
|
||||
|
||||
/// Specify the key for an encrypted database. This routine should be
|
||||
/// called right after sqlite3_open().
|
||||
///
|
||||
/// @param key The key to use.The key itself can be a passphrase, which is converted to a key
|
||||
/// using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) key derivation. The result
|
||||
/// is used as the encryption key for the database.
|
||||
///
|
||||
/// Alternatively, it is possible to specify an exact byte sequence using a blob literal.
|
||||
/// With this method, it is the calling application's responsibility to ensure that the data
|
||||
/// provided is a 64 character hex string, which will be converted directly to 32 bytes (256 bits)
|
||||
/// of key data.
|
||||
/// e.g. x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'
|
||||
/// @param db name of the database, defaults to 'main'
|
||||
public func key(_ key: String, db: String = "main") throws {
|
||||
try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count)
|
||||
}
|
||||
|
||||
public func key(_ key: Blob, db: String = "main") throws {
|
||||
try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
|
||||
}
|
||||
|
||||
|
||||
/// Change the key on an open database. If the current database is not encrypted, this routine
|
||||
/// will encrypt it.
|
||||
/// To change the key on an existing encrypted database, it must first be unlocked with the
|
||||
/// current encryption key. Once the database is readable and writeable, rekey can be used
|
||||
/// to re-encrypt every page in the database with a new key.
|
||||
public func rekey(_ key: String, db: String = "main") throws {
|
||||
try _rekey_v2(db: db, keyPointer: key, keySize: key.utf8.count)
|
||||
}
|
||||
|
||||
public func rekey(_ key: Blob, db: String = "main") throws {
|
||||
try _rekey_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
|
||||
}
|
||||
|
||||
// MARK: - private
|
||||
private func _key_v2(db: String, keyPointer: UnsafePointer<UInt8>, keySize: Int) throws {
|
||||
try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize)))
|
||||
try cipher_key_check()
|
||||
}
|
||||
|
||||
private func _rekey_v2(db: String, keyPointer: UnsafePointer<UInt8>, keySize: Int) throws {
|
||||
try check(sqlite3_rekey_v2(handle, db, keyPointer, Int32(keySize)))
|
||||
}
|
||||
|
||||
// When opening an existing database, sqlite3_key_v2 will not immediately throw an error if
|
||||
// the key provided is incorrect. To test that the database can be successfully opened with the
|
||||
// provided key, it is necessary to perform some operation on the database (i.e. read from it).
|
||||
private func cipher_key_check() throws {
|
||||
try scalar("SELECT count(*) FROM sqlite_master;")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
346
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS4.swift
vendored
Normal file
346
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS4.swift
vendored
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#if SWIFT_PACKAGE
|
||||
import SQLiteObjc
|
||||
#endif
|
||||
|
||||
extension Module {
|
||||
|
||||
public static func FTS4(_ column: Expressible, _ more: Expressible...) -> Module {
|
||||
return FTS4([column] + more)
|
||||
}
|
||||
|
||||
public static func FTS4(_ columns: [Expressible] = [], tokenize tokenizer: Tokenizer? = nil) -> Module {
|
||||
return FTS4(FTS4Config().columns(columns).tokenizer(tokenizer))
|
||||
}
|
||||
|
||||
public static func FTS4(_ config: FTS4Config) -> Module {
|
||||
return Module(name: "fts4", arguments: config.arguments())
|
||||
}
|
||||
}
|
||||
|
||||
extension VirtualTable {
|
||||
|
||||
/// Builds an expression appended with a `MATCH` query against the given
|
||||
/// pattern.
|
||||
///
|
||||
/// let emails = VirtualTable("emails")
|
||||
///
|
||||
/// emails.filter(emails.match("Hello"))
|
||||
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: An expression appended with a `MATCH` query against the given
|
||||
/// pattern.
|
||||
public func match(_ pattern: String) -> Expression<Bool> {
|
||||
return "MATCH".infix(tableName(), pattern)
|
||||
}
|
||||
|
||||
public func match(_ pattern: Expression<String>) -> Expression<Bool> {
|
||||
return "MATCH".infix(tableName(), pattern)
|
||||
}
|
||||
|
||||
public func match(_ pattern: Expression<String?>) -> Expression<Bool?> {
|
||||
return "MATCH".infix(tableName(), pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the query with a `WHERE … MATCH` clause.
|
||||
///
|
||||
/// let emails = VirtualTable("emails")
|
||||
///
|
||||
/// emails.match("Hello")
|
||||
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A query with the given `WHERE … MATCH` clause applied.
|
||||
public func match(_ pattern: String) -> QueryType {
|
||||
return filter(match(pattern))
|
||||
}
|
||||
|
||||
public func match(_ pattern: Expression<String>) -> QueryType {
|
||||
return filter(match(pattern))
|
||||
}
|
||||
|
||||
public func match(_ pattern: Expression<String?>) -> QueryType {
|
||||
return filter(match(pattern))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct Tokenizer {
|
||||
|
||||
public static let Simple = Tokenizer("simple")
|
||||
|
||||
public static let Porter = Tokenizer("porter")
|
||||
|
||||
public static func Unicode61(removeDiacritics: Bool? = nil, tokenchars: Set<Character> = [], separators: Set<Character> = []) -> Tokenizer {
|
||||
var arguments = [String]()
|
||||
|
||||
if let removeDiacritics = removeDiacritics {
|
||||
arguments.append("removeDiacritics=\(removeDiacritics ? 1 : 0)".quote())
|
||||
}
|
||||
|
||||
if !tokenchars.isEmpty {
|
||||
let joined = tokenchars.map { String($0) }.joined(separator: "")
|
||||
arguments.append("tokenchars=\(joined)".quote())
|
||||
}
|
||||
|
||||
if !separators.isEmpty {
|
||||
let joined = separators.map { String($0) }.joined(separator: "")
|
||||
arguments.append("separators=\(joined)".quote())
|
||||
}
|
||||
|
||||
return Tokenizer("unicode61", arguments)
|
||||
}
|
||||
|
||||
public static func Custom(_ name: String) -> Tokenizer {
|
||||
return Tokenizer(Tokenizer.moduleName.quote(), [name.quote()])
|
||||
}
|
||||
|
||||
public let name: String
|
||||
|
||||
public let arguments: [String]
|
||||
|
||||
fileprivate init(_ name: String, _ arguments: [String] = []) {
|
||||
self.name = name
|
||||
self.arguments = arguments
|
||||
}
|
||||
|
||||
fileprivate static let moduleName = "SQLite.swift"
|
||||
|
||||
}
|
||||
|
||||
extension Tokenizer : CustomStringConvertible {
|
||||
|
||||
public var description: String {
|
||||
return ([name] + arguments).joined(separator: " ")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Connection {
|
||||
|
||||
public func registerTokenizer(_ submoduleName: String, next: @escaping (String) -> (String, Range<String.Index>)?) throws {
|
||||
try check(_SQLiteRegisterTokenizer(handle, Tokenizer.moduleName, submoduleName) { input, offset, length in
|
||||
let string = String(cString: input)
|
||||
|
||||
guard let (token, range) = next(string) else { return nil }
|
||||
|
||||
let view = string.utf8
|
||||
offset.pointee += string.substring(to: range.lowerBound).utf8.count
|
||||
length.pointee = Int32(view.distance(from: range.lowerBound.samePosition(in: view), to: range.upperBound.samePosition(in: view)))
|
||||
return token
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Configuration options shared between the [FTS4](https://www.sqlite.org/fts3.html) and
|
||||
/// [FTS5](https://www.sqlite.org/fts5.html) extensions.
|
||||
open class FTSConfig {
|
||||
public enum ColumnOption {
|
||||
/// [The notindexed= option](https://www.sqlite.org/fts3.html#section_6_5)
|
||||
case unindexed
|
||||
}
|
||||
|
||||
typealias ColumnDefinition = (Expressible, options: [ColumnOption])
|
||||
var columnDefinitions = [ColumnDefinition]()
|
||||
var tokenizer: Tokenizer?
|
||||
var prefixes = [Int]()
|
||||
var externalContentSchema: SchemaType?
|
||||
var isContentless: Bool = false
|
||||
|
||||
/// Adds a column definition
|
||||
@discardableResult open func column(_ column: Expressible, _ options: [ColumnOption] = []) -> Self {
|
||||
self.columnDefinitions.append((column, options))
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult open func columns(_ columns: [Expressible]) -> Self {
|
||||
for column in columns {
|
||||
self.column(column)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
/// [Tokenizers](https://www.sqlite.org/fts3.html#tokenizer)
|
||||
open func tokenizer(_ tokenizer: Tokenizer?) -> Self {
|
||||
self.tokenizer = tokenizer
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The prefix= option](https://www.sqlite.org/fts3.html#section_6_6)
|
||||
open func prefix(_ prefix: [Int]) -> Self {
|
||||
self.prefixes += prefix
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The content= option](https://www.sqlite.org/fts3.html#section_6_2)
|
||||
open func externalContent(_ schema: SchemaType) -> Self {
|
||||
self.externalContentSchema = schema
|
||||
return self
|
||||
}
|
||||
|
||||
/// [Contentless FTS4 Tables](https://www.sqlite.org/fts3.html#section_6_2_1)
|
||||
open func contentless() -> Self {
|
||||
self.isContentless = true
|
||||
return self
|
||||
}
|
||||
|
||||
func formatColumnDefinitions() -> [Expressible] {
|
||||
return columnDefinitions.map { $0.0 }
|
||||
}
|
||||
|
||||
func arguments() -> [Expressible] {
|
||||
return options().arguments
|
||||
}
|
||||
|
||||
func options() -> Options {
|
||||
var options = Options()
|
||||
options.append(formatColumnDefinitions())
|
||||
if let tokenizer = tokenizer {
|
||||
options.append("tokenize", value: Expression<Void>(literal: tokenizer.description))
|
||||
}
|
||||
options.appendCommaSeparated("prefix", values:prefixes.sorted().map { String($0) })
|
||||
if isContentless {
|
||||
options.append("content", value: "")
|
||||
} else if let externalContentSchema = externalContentSchema {
|
||||
options.append("content", value: externalContentSchema.tableName())
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
struct Options {
|
||||
var arguments = [Expressible]()
|
||||
|
||||
@discardableResult mutating func append(_ columns: [Expressible]) -> Options {
|
||||
arguments.append(contentsOf: columns)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult mutating func appendCommaSeparated(_ key: String, values: [String]) -> Options {
|
||||
if values.isEmpty {
|
||||
return self
|
||||
} else {
|
||||
return append(key, value: values.joined(separator: ","))
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult mutating func append(_ key: String, value: CustomStringConvertible?) -> Options {
|
||||
return append(key, value: value?.description)
|
||||
}
|
||||
|
||||
@discardableResult mutating func append(_ key: String, value: String?) -> Options {
|
||||
return append(key, value: value.map { Expression<String>($0) })
|
||||
}
|
||||
|
||||
@discardableResult mutating func append(_ key: String, value: Expressible?) -> Options {
|
||||
if let value = value {
|
||||
arguments.append("=".join([Expression<Void>(literal: key), value]))
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for the [FTS4](https://www.sqlite.org/fts3.html) extension.
|
||||
open class FTS4Config : FTSConfig {
|
||||
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
|
||||
public enum MatchInfo : CustomStringConvertible {
|
||||
case fts3
|
||||
public var description: String {
|
||||
return "fts3"
|
||||
}
|
||||
}
|
||||
|
||||
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
|
||||
public enum Order : CustomStringConvertible {
|
||||
/// Data structures are optimized for returning results in ascending order by docid (default)
|
||||
case asc
|
||||
/// FTS4 stores its data in such a way as to optimize returning results in descending order by docid.
|
||||
case desc
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .asc: return "asc"
|
||||
case .desc: return "desc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var compressFunction: String?
|
||||
var uncompressFunction: String?
|
||||
var languageId: String?
|
||||
var matchInfo: MatchInfo?
|
||||
var order: Order?
|
||||
|
||||
override public init() {
|
||||
}
|
||||
|
||||
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
|
||||
open func compress(_ functionName: String) -> Self {
|
||||
self.compressFunction = functionName
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
|
||||
open func uncompress(_ functionName: String) -> Self {
|
||||
self.uncompressFunction = functionName
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The languageid= option](https://www.sqlite.org/fts3.html#section_6_3)
|
||||
open func languageId(_ columnName: String) -> Self {
|
||||
self.languageId = columnName
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
|
||||
open func matchInfo(_ matchInfo: MatchInfo) -> Self {
|
||||
self.matchInfo = matchInfo
|
||||
return self
|
||||
}
|
||||
|
||||
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
|
||||
open func order(_ order: Order) -> Self {
|
||||
self.order = order
|
||||
return self
|
||||
}
|
||||
|
||||
override func options() -> Options {
|
||||
var options = super.options()
|
||||
for (column, _) in (columnDefinitions.filter { $0.options.contains(.unindexed) }) {
|
||||
options.append("notindexed", value: column)
|
||||
}
|
||||
options.append("languageid", value: languageId)
|
||||
options.append("compress", value: compressFunction)
|
||||
options.append("uncompress", value: uncompressFunction)
|
||||
options.append("matchinfo", value: matchInfo)
|
||||
options.append("order", value: order)
|
||||
return options
|
||||
}
|
||||
}
|
||||
97
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift
vendored
Normal file
97
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
extension Module {
|
||||
public static func FTS5(_ config: FTS5Config) -> Module {
|
||||
return Module(name: "fts5", arguments: config.arguments())
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension.
|
||||
///
|
||||
/// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version
|
||||
/// of SQLite.
|
||||
open class FTS5Config : FTSConfig {
|
||||
public enum Detail : CustomStringConvertible {
|
||||
/// store rowid, column number, term offset
|
||||
case full
|
||||
/// store rowid, column number
|
||||
case column
|
||||
/// store rowid
|
||||
case none
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .full: return "full"
|
||||
case .column: return "column"
|
||||
case .none: return "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var detail: Detail?
|
||||
var contentRowId: Expressible?
|
||||
var columnSize: Int?
|
||||
|
||||
override public init() {
|
||||
}
|
||||
|
||||
/// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2)
|
||||
open func contentRowId(_ column: Expressible) -> Self {
|
||||
self.contentRowId = column
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5)
|
||||
open func columnSize(_ size: Int) -> Self {
|
||||
self.columnSize = size
|
||||
return self
|
||||
}
|
||||
|
||||
/// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6)
|
||||
open func detail(_ detail: Detail) -> Self {
|
||||
self.detail = detail
|
||||
return self
|
||||
}
|
||||
|
||||
override func options() -> Options {
|
||||
var options = super.options()
|
||||
options.append("content_rowid", value: contentRowId)
|
||||
if let columnSize = columnSize {
|
||||
options.append("columnsize", value: Expression<Int>(value: columnSize))
|
||||
}
|
||||
options.append("detail", value: detail)
|
||||
return options
|
||||
}
|
||||
|
||||
override func formatColumnDefinitions() -> [Expressible] {
|
||||
return columnDefinitions.map { definition in
|
||||
if definition.options.contains(.unindexed) {
|
||||
return " ".join([definition.0, Expression<Void>(literal: "UNINDEXED")])
|
||||
} else {
|
||||
return definition.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/RTree.swift
vendored
Normal file
37
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Extensions/RTree.swift
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
extension Module {
|
||||
|
||||
public static func RTree<T : Value, U : Value>(_ primaryKey: Expression<T>, _ pairs: (Expression<U>, Expression<U>)...) -> Module where T.Datatype == Int64, U.Datatype == Double {
|
||||
var arguments: [Expressible] = [primaryKey]
|
||||
|
||||
for pair in pairs {
|
||||
arguments.append(contentsOf: [pair.0, pair.1] as [Expressible])
|
||||
}
|
||||
|
||||
return Module(name: "rtree", arguments: arguments)
|
||||
}
|
||||
|
||||
}
|
||||
108
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Foundation.swift
vendored
Normal file
108
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Foundation.swift
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Data : Value {
|
||||
|
||||
public static var declaredDatatype: String {
|
||||
return Blob.declaredDatatype
|
||||
}
|
||||
|
||||
public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
|
||||
return Data(bytes: dataValue.bytes)
|
||||
}
|
||||
|
||||
public var datatypeValue: Blob {
|
||||
return withUnsafeBytes { (pointer: UnsafePointer<UInt8>) -> Blob in
|
||||
return Blob(bytes: pointer, length: count)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Date : Value {
|
||||
|
||||
public static var declaredDatatype: String {
|
||||
return String.declaredDatatype
|
||||
}
|
||||
|
||||
public static func fromDatatypeValue(_ stringValue: String) -> Date {
|
||||
return dateFormatter.date(from: stringValue)!
|
||||
}
|
||||
|
||||
public var datatypeValue: String {
|
||||
return dateFormatter.string(from: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A global date formatter used to serialize and deserialize `NSDate` objects.
|
||||
/// If multiple date formats are used in an application’s database(s), use a
|
||||
/// custom `Value` type per additional format.
|
||||
public var dateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
return formatter
|
||||
}()
|
||||
|
||||
// FIXME: rdar://problem/18673897 // subscript<T>…
|
||||
|
||||
extension QueryType {
|
||||
|
||||
public subscript(column: Expression<Data>) -> Expression<Data> {
|
||||
return namespace(column)
|
||||
}
|
||||
public subscript(column: Expression<Data?>) -> Expression<Data?> {
|
||||
return namespace(column)
|
||||
}
|
||||
|
||||
public subscript(column: Expression<Date>) -> Expression<Date> {
|
||||
return namespace(column)
|
||||
}
|
||||
public subscript(column: Expression<Date?>) -> Expression<Date?> {
|
||||
return namespace(column)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Row {
|
||||
|
||||
public subscript(column: Expression<Data>) -> Data {
|
||||
return get(column)
|
||||
}
|
||||
public subscript(column: Expression<Data?>) -> Data? {
|
||||
return get(column)
|
||||
}
|
||||
|
||||
public subscript(column: Expression<Date>) -> Date {
|
||||
return get(column)
|
||||
}
|
||||
public subscript(column: Expression<Date?>) -> Date? {
|
||||
return get(column)
|
||||
}
|
||||
|
||||
}
|
||||
130
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Helpers.swift
vendored
Normal file
130
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Helpers.swift
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#if SQLITE_SWIFT_STANDALONE
|
||||
import sqlite3
|
||||
#elseif SQLITE_SWIFT_SQLCIPHER
|
||||
import SQLCipher
|
||||
#else
|
||||
import SQLite3
|
||||
#endif
|
||||
|
||||
public typealias Star = (Expression<Binding>?, Expression<Binding>?) -> Expression<Void>
|
||||
|
||||
public func *(_: Expression<Binding>?, _: Expression<Binding>?) -> Expression<Void> {
|
||||
return Expression(literal: "*")
|
||||
}
|
||||
|
||||
public protocol _OptionalType {
|
||||
|
||||
associatedtype WrappedType
|
||||
|
||||
}
|
||||
|
||||
extension Optional : _OptionalType {
|
||||
|
||||
public typealias WrappedType = Wrapped
|
||||
|
||||
}
|
||||
|
||||
// let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)
|
||||
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
|
||||
|
||||
extension String {
|
||||
|
||||
func quote(_ mark: Character = "\"") -> String {
|
||||
let escaped = characters.reduce("") { string, character in
|
||||
string + (character == mark ? "\(mark)\(mark)" : "\(character)")
|
||||
}
|
||||
return "\(mark)\(escaped)\(mark)"
|
||||
}
|
||||
|
||||
func join(_ expressions: [Expressible]) -> Expressible {
|
||||
var (template, bindings) = ([String](), [Binding?]())
|
||||
for expressible in expressions {
|
||||
let expression = expressible.expression
|
||||
template.append(expression.template)
|
||||
bindings.append(contentsOf: expression.bindings)
|
||||
}
|
||||
return Expression<Void>(template.joined(separator: self), bindings)
|
||||
}
|
||||
|
||||
func infix<T>(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression<T> {
|
||||
let expression = Expression<T>(" \(self) ".join([lhs, rhs]).expression)
|
||||
guard wrap else {
|
||||
return expression
|
||||
}
|
||||
return "".wrap(expression)
|
||||
}
|
||||
|
||||
func prefix(_ expressions: Expressible) -> Expressible {
|
||||
return "\(self) ".wrap(expressions) as Expression<Void>
|
||||
}
|
||||
|
||||
func prefix(_ expressions: [Expressible]) -> Expressible {
|
||||
return "\(self) ".wrap(expressions) as Expression<Void>
|
||||
}
|
||||
|
||||
func wrap<T>(_ expression: Expressible) -> Expression<T> {
|
||||
return Expression("\(self)(\(expression.expression.template))", expression.expression.bindings)
|
||||
}
|
||||
|
||||
func wrap<T>(_ expressions: [Expressible]) -> Expression<T> {
|
||||
return wrap(", ".join(expressions))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func infix<T>(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true, function: String = #function) -> Expression<T> {
|
||||
return function.infix(lhs, rhs, wrap: wrap)
|
||||
}
|
||||
|
||||
func wrap<T>(_ expression: Expressible, function: String = #function) -> Expression<T> {
|
||||
return function.wrap(expression)
|
||||
}
|
||||
|
||||
func wrap<T>(_ expressions: [Expressible], function: String = #function) -> Expression<T> {
|
||||
return function.wrap(", ".join(expressions))
|
||||
}
|
||||
|
||||
func transcode(_ literal: Binding?) -> String {
|
||||
guard let literal = literal else { return "NULL" }
|
||||
|
||||
switch literal {
|
||||
case let blob as Blob:
|
||||
return blob.description
|
||||
case let string as String:
|
||||
return string.quote("'")
|
||||
case let binding:
|
||||
return "\(binding)"
|
||||
}
|
||||
}
|
||||
|
||||
func value<A: Value>(_ v: Binding) -> A {
|
||||
return A.fromDatatypeValue(v as! A.Datatype) as! A
|
||||
}
|
||||
|
||||
func value<A: Value>(_ v: Binding?) -> A {
|
||||
return value(v!)
|
||||
}
|
||||
26
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Info.plist
vendored
Normal file
26
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Info.plist
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.11.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
6
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/SQLite.h
vendored
Normal file
6
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/SQLite.h
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
@import Foundation;
|
||||
|
||||
FOUNDATION_EXPORT double SQLiteVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char SQLiteVersionString[];
|
||||
|
||||
#import <SQLite/SQLite-Bridging.h>
|
||||
251
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift
vendored
Normal file
251
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
extension ExpressionType where UnderlyingType : Value {
|
||||
|
||||
/// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.distinct
|
||||
/// // DISTINCT "name"
|
||||
///
|
||||
/// - Returns: A copy of the expression prefixed with the `DISTINCT`
|
||||
/// keyword.
|
||||
public var distinct: Expression<UnderlyingType> {
|
||||
return Expression("DISTINCT \(template)", bindings)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `count` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.count
|
||||
/// // count("name")
|
||||
/// name.distinct.count
|
||||
/// // count(DISTINCT "name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `count` aggregate
|
||||
/// function.
|
||||
public var count: Expression<Int> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
|
||||
|
||||
/// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.distinct
|
||||
/// // DISTINCT "name"
|
||||
///
|
||||
/// - Returns: A copy of the expression prefixed with the `DISTINCT`
|
||||
/// keyword.
|
||||
public var distinct: Expression<UnderlyingType> {
|
||||
return Expression("DISTINCT \(template)", bindings)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `count` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.count
|
||||
/// // count("name")
|
||||
/// name.distinct.count
|
||||
/// // count(DISTINCT "name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `count` aggregate
|
||||
/// function.
|
||||
public var count: Expression<Int> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Comparable {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `max` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let age = Expression<Int>("age")
|
||||
/// age.max
|
||||
/// // max("age")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `max` aggregate
|
||||
/// function.
|
||||
public var max: Expression<UnderlyingType?> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let age = Expression<Int>("age")
|
||||
/// age.min
|
||||
/// // min("age")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var min: Expression<UnderlyingType?> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Comparable {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `max` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let age = Expression<Int?>("age")
|
||||
/// age.max
|
||||
/// // max("age")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `max` aggregate
|
||||
/// function.
|
||||
public var max: Expression<UnderlyingType> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let age = Expression<Int?>("age")
|
||||
/// age.min
|
||||
/// // min("age")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var min: Expression<UnderlyingType> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Number {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `avg` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double>("salary")
|
||||
/// salary.average
|
||||
/// // avg("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var average: Expression<Double?> {
|
||||
return "avg".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `sum` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double>("salary")
|
||||
/// salary.sum
|
||||
/// // sum("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var sum: Expression<UnderlyingType?> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `total` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double>("salary")
|
||||
/// salary.total
|
||||
/// // total("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var total: Expression<Double> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Number {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `avg` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double?>("salary")
|
||||
/// salary.average
|
||||
/// // avg("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var average: Expression<Double?> {
|
||||
return "avg".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `sum` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double?>("salary")
|
||||
/// salary.sum
|
||||
/// // sum("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var sum: Expression<UnderlyingType> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `total` aggregate
|
||||
/// function.
|
||||
///
|
||||
/// let salary = Expression<Double?>("salary")
|
||||
/// salary.total
|
||||
/// // total("salary")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `min` aggregate
|
||||
/// function.
|
||||
public var total: Expression<Double> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == Int {
|
||||
|
||||
static func count(_ star: Star) -> Expression<UnderlyingType> {
|
||||
return wrap(star(nil, nil))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Builds an expression representing `count(*)` (when called with the `*`
|
||||
/// function literal).
|
||||
///
|
||||
/// count(*)
|
||||
/// // count(*)
|
||||
///
|
||||
/// - Returns: An expression returning `count(*)` (when called with the `*`
|
||||
/// function literal).
|
||||
public func count(_ star: Star) -> Expression<Int> {
|
||||
return Expression.count(star)
|
||||
}
|
||||
69
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Collation.swift
vendored
Normal file
69
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Collation.swift
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
/// A collating function used to compare to strings.
|
||||
///
|
||||
/// - SeeAlso: <https://www.sqlite.org/datatype3.html#collation>
|
||||
public enum Collation {
|
||||
|
||||
/// Compares string by raw data.
|
||||
case binary
|
||||
|
||||
/// Like binary, but folds uppercase ASCII letters into their lowercase
|
||||
/// equivalents.
|
||||
case nocase
|
||||
|
||||
/// Like binary, but strips trailing space.
|
||||
case rtrim
|
||||
|
||||
/// A custom collating sequence identified by the given string, registered
|
||||
/// using `Database.create(collation:…)`
|
||||
case custom(String)
|
||||
|
||||
}
|
||||
|
||||
extension Collation : Expressible {
|
||||
|
||||
public var expression: Expression<Void> {
|
||||
return Expression(literal: description)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Collation : CustomStringConvertible {
|
||||
|
||||
public var description : String {
|
||||
switch self {
|
||||
case .binary:
|
||||
return "BINARY"
|
||||
case .nocase:
|
||||
return "NOCASE"
|
||||
case .rtrim:
|
||||
return "RTRIM"
|
||||
case .custom(let collation):
|
||||
return collation.quote()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
683
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CoreFunctions.swift
vendored
Normal file
683
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CoreFunctions.swift
vendored
Normal file
|
|
@ -0,0 +1,683 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation.NSData
|
||||
|
||||
|
||||
extension ExpressionType where UnderlyingType : Number {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `abs` function.
|
||||
///
|
||||
/// let x = Expression<Int>("x")
|
||||
/// x.absoluteValue
|
||||
/// // abs("x")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `abs` function.
|
||||
public var absoluteValue : Expression<UnderlyingType> {
|
||||
return "abs".wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Number {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `abs` function.
|
||||
///
|
||||
/// let x = Expression<Int?>("x")
|
||||
/// x.absoluteValue
|
||||
/// // abs("x")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `abs` function.
|
||||
public var absoluteValue : Expression<UnderlyingType> {
|
||||
return "abs".wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == Double {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `round` function.
|
||||
///
|
||||
/// let salary = Expression<Double>("salary")
|
||||
/// salary.round()
|
||||
/// // round("salary")
|
||||
/// salary.round(2)
|
||||
/// // round("salary", 2)
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `round` function.
|
||||
public func round(_ precision: Int? = nil) -> Expression<UnderlyingType> {
|
||||
guard let precision = precision else {
|
||||
return wrap([self])
|
||||
}
|
||||
return wrap([self, Int(precision)])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == Double? {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `round` function.
|
||||
///
|
||||
/// let salary = Expression<Double>("salary")
|
||||
/// salary.round()
|
||||
/// // round("salary")
|
||||
/// salary.round(2)
|
||||
/// // round("salary", 2)
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `round` function.
|
||||
public func round(_ precision: Int? = nil) -> Expression<UnderlyingType> {
|
||||
guard let precision = precision else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, Int(precision)])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype == Int64 {
|
||||
|
||||
/// Builds an expression representing the `random` function.
|
||||
///
|
||||
/// Expression<Int>.random()
|
||||
/// // random()
|
||||
///
|
||||
/// - Returns: An expression calling the `random` function.
|
||||
public static func random() -> Expression<UnderlyingType> {
|
||||
return "random".wrap([])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == Data {
|
||||
|
||||
/// Builds an expression representing the `randomblob` function.
|
||||
///
|
||||
/// Expression<Int>.random(16)
|
||||
/// // randomblob(16)
|
||||
///
|
||||
/// - Parameter length: Length in bytes.
|
||||
///
|
||||
/// - Returns: An expression calling the `randomblob` function.
|
||||
public static func random(_ length: Int) -> Expression<UnderlyingType> {
|
||||
return "randomblob".wrap([])
|
||||
}
|
||||
|
||||
/// Builds an expression representing the `zeroblob` function.
|
||||
///
|
||||
/// Expression<Int>.allZeros(16)
|
||||
/// // zeroblob(16)
|
||||
///
|
||||
/// - Parameter length: Length in bytes.
|
||||
///
|
||||
/// - Returns: An expression calling the `zeroblob` function.
|
||||
public static func allZeros(_ length: Int) -> Expression<UnderlyingType> {
|
||||
return "zeroblob".wrap([])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `length` function.
|
||||
///
|
||||
/// let data = Expression<NSData>("data")
|
||||
/// data.length
|
||||
/// // length("data")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `length` function.
|
||||
public var length: Expression<Int> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == Data? {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `length` function.
|
||||
///
|
||||
/// let data = Expression<NSData?>("data")
|
||||
/// data.length
|
||||
/// // length("data")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `length` function.
|
||||
public var length: Expression<Int?> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == String {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `length` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.length
|
||||
/// // length("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `length` function.
|
||||
public var length: Expression<Int> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `lower` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.lowercaseString
|
||||
/// // lower("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `lower` function.
|
||||
public var lowercaseString: Expression<UnderlyingType> {
|
||||
return "lower".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `upper` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.uppercaseString
|
||||
/// // lower("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `upper` function.
|
||||
public var uppercaseString: Expression<UnderlyingType> {
|
||||
return "upper".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `LIKE` query against the
|
||||
/// given pattern.
|
||||
///
|
||||
/// let email = Expression<String>("email")
|
||||
/// email.like("%@example.com")
|
||||
/// // "email" LIKE '%@example.com'
|
||||
/// email.like("99\\%@%", escape: "\\")
|
||||
/// // "email" LIKE '99\%@%' ESCAPE '\'
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - pattern: A pattern to match.
|
||||
///
|
||||
/// - escape: An (optional) character designated for escaping
|
||||
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `LIKE` query against
|
||||
/// the given pattern.
|
||||
public func like(_ pattern: String, escape character: Character? = nil) -> Expression<Bool> {
|
||||
guard let character = character else {
|
||||
return "LIKE".infix(self, pattern)
|
||||
}
|
||||
return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `GLOB` query against the
|
||||
/// given pattern.
|
||||
///
|
||||
/// let path = Expression<String>("path")
|
||||
/// path.glob("*.png")
|
||||
/// // "path" GLOB '*.png'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `GLOB` query against
|
||||
/// the given pattern.
|
||||
public func glob(_ pattern: String) -> Expression<Bool> {
|
||||
return "GLOB".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `MATCH` query against
|
||||
/// the given pattern.
|
||||
///
|
||||
/// let title = Expression<String>("title")
|
||||
/// title.match("swift AND programming")
|
||||
/// // "title" MATCH 'swift AND programming'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `MATCH` query
|
||||
/// against the given pattern.
|
||||
public func match(_ pattern: String) -> Expression<Bool> {
|
||||
return "MATCH".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `REGEXP` query against
|
||||
/// the given pattern.
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `REGEXP` query
|
||||
/// against the given pattern.
|
||||
public func regexp(_ pattern: String) -> Expression<Bool> {
|
||||
return "REGEXP".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `COLLATE` clause with
|
||||
/// the given sequence.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.collate(.Nocase)
|
||||
/// // "name" COLLATE NOCASE
|
||||
///
|
||||
/// - Parameter collation: A collating sequence.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `COLLATE` clause
|
||||
/// with the given sequence.
|
||||
public func collate(_ collation: Collation) -> Expression<UnderlyingType> {
|
||||
return "COLLATE".infix(self, collation)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `ltrim` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.ltrim()
|
||||
/// // ltrim("name")
|
||||
/// name.ltrim([" ", "\t"])
|
||||
/// // ltrim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `ltrim` function.
|
||||
public func ltrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `rtrim` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.rtrim()
|
||||
/// // rtrim("name")
|
||||
/// name.rtrim([" ", "\t"])
|
||||
/// // rtrim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `rtrim` function.
|
||||
public func rtrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `trim` function.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// name.trim()
|
||||
/// // trim("name")
|
||||
/// name.trim([" ", "\t"])
|
||||
/// // trim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `trim` function.
|
||||
public func trim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap([self])
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `replace` function.
|
||||
///
|
||||
/// let email = Expression<String>("email")
|
||||
/// email.replace("@mac.com", with: "@icloud.com")
|
||||
/// // replace("email", '@mac.com', '@icloud.com')
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - pattern: A pattern to match.
|
||||
///
|
||||
/// - replacement: The replacement string.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `replace` function.
|
||||
public func replace(_ pattern: String, with replacement: String) -> Expression<UnderlyingType> {
|
||||
return "replace".wrap([self, pattern, replacement])
|
||||
}
|
||||
|
||||
public func substring(_ location: Int, length: Int? = nil) -> Expression<UnderlyingType> {
|
||||
guard let length = length else {
|
||||
return "substr".wrap([self, location])
|
||||
}
|
||||
return "substr".wrap([self, location, length])
|
||||
}
|
||||
|
||||
public subscript(range: Range<Int>) -> Expression<UnderlyingType> {
|
||||
return substring(range.lowerBound, length: range.upperBound - range.lowerBound)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType == String? {
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `length` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.length
|
||||
/// // length("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `length` function.
|
||||
public var length: Expression<Int?> {
|
||||
return wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `lower` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.lowercaseString
|
||||
/// // lower("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `lower` function.
|
||||
public var lowercaseString: Expression<UnderlyingType> {
|
||||
return "lower".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `upper` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.uppercaseString
|
||||
/// // lower("name")
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `upper` function.
|
||||
public var uppercaseString: Expression<UnderlyingType> {
|
||||
return "upper".wrap(self)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `LIKE` query against the
|
||||
/// given pattern.
|
||||
///
|
||||
/// let email = Expression<String?>("email")
|
||||
/// email.like("%@example.com")
|
||||
/// // "email" LIKE '%@example.com'
|
||||
/// email.like("99\\%@%", escape: "\\")
|
||||
/// // "email" LIKE '99\%@%' ESCAPE '\'
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - pattern: A pattern to match.
|
||||
///
|
||||
/// - escape: An (optional) character designated for escaping
|
||||
/// pattern-matching characters (*i.e.*, the `%` and `_` characters).
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `LIKE` query against
|
||||
/// the given pattern.
|
||||
public func like(_ pattern: String, escape character: Character? = nil) -> Expression<Bool?> {
|
||||
guard let character = character else {
|
||||
return "LIKE".infix(self, pattern)
|
||||
}
|
||||
return Expression("(\(template) LIKE ? ESCAPE ?)", bindings + [pattern, String(character)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `GLOB` query against the
|
||||
/// given pattern.
|
||||
///
|
||||
/// let path = Expression<String?>("path")
|
||||
/// path.glob("*.png")
|
||||
/// // "path" GLOB '*.png'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `GLOB` query against
|
||||
/// the given pattern.
|
||||
public func glob(_ pattern: String) -> Expression<Bool?> {
|
||||
return "GLOB".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `MATCH` query against
|
||||
/// the given pattern.
|
||||
///
|
||||
/// let title = Expression<String?>("title")
|
||||
/// title.match("swift AND programming")
|
||||
/// // "title" MATCH 'swift AND programming'
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `MATCH` query
|
||||
/// against the given pattern.
|
||||
public func match(_ pattern: String) -> Expression<Bool> {
|
||||
return "MATCH".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `REGEXP` query against
|
||||
/// the given pattern.
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `REGEXP` query
|
||||
/// against the given pattern.
|
||||
public func regexp(_ pattern: String) -> Expression<Bool?> {
|
||||
return "REGEXP".infix(self, pattern)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression appended with a `COLLATE` clause with
|
||||
/// the given sequence.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.collate(.Nocase)
|
||||
/// // "name" COLLATE NOCASE
|
||||
///
|
||||
/// - Parameter collation: A collating sequence.
|
||||
///
|
||||
/// - Returns: A copy of the expression appended with a `COLLATE` clause
|
||||
/// with the given sequence.
|
||||
public func collate(_ collation: Collation) -> Expression<UnderlyingType> {
|
||||
return "COLLATE".infix(self, collation)
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `ltrim` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.ltrim()
|
||||
/// // ltrim("name")
|
||||
/// name.ltrim([" ", "\t"])
|
||||
/// // ltrim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `ltrim` function.
|
||||
public func ltrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `rtrim` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.rtrim()
|
||||
/// // rtrim("name")
|
||||
/// name.rtrim([" ", "\t"])
|
||||
/// // rtrim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `rtrim` function.
|
||||
public func rtrim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `trim` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name.trim()
|
||||
/// // trim("name")
|
||||
/// name.trim([" ", "\t"])
|
||||
/// // trim("name", ' \t')
|
||||
///
|
||||
/// - Parameter characters: A set of characters to trim.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `trim` function.
|
||||
public func trim(_ characters: Set<Character>? = nil) -> Expression<UnderlyingType> {
|
||||
guard let characters = characters else {
|
||||
return wrap(self)
|
||||
}
|
||||
return wrap([self, String(characters)])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `replace` function.
|
||||
///
|
||||
/// let email = Expression<String?>("email")
|
||||
/// email.replace("@mac.com", with: "@icloud.com")
|
||||
/// // replace("email", '@mac.com', '@icloud.com')
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - pattern: A pattern to match.
|
||||
///
|
||||
/// - replacement: The replacement string.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `replace` function.
|
||||
public func replace(_ pattern: String, with replacement: String) -> Expression<UnderlyingType> {
|
||||
return "replace".wrap([self, pattern, replacement])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `substr` function.
|
||||
///
|
||||
/// let title = Expression<String?>("title")
|
||||
/// title.substr(-100)
|
||||
/// // substr("title", -100)
|
||||
/// title.substr(0, length: 100)
|
||||
/// // substr("title", 0, 100)
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - location: The substring’s start index.
|
||||
///
|
||||
/// - length: An optional substring length.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `substr` function.
|
||||
public func substring(_ location: Int, length: Int? = nil) -> Expression<UnderlyingType> {
|
||||
guard let length = length else {
|
||||
return "substr".wrap([self, location])
|
||||
}
|
||||
return "substr".wrap([self, location, length])
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression wrapped with the `substr` function.
|
||||
///
|
||||
/// let title = Expression<String?>("title")
|
||||
/// title[0..<100]
|
||||
/// // substr("title", 0, 100)
|
||||
///
|
||||
/// - Parameter range: The character index range of the substring.
|
||||
///
|
||||
/// - Returns: A copy of the expression wrapped with the `substr` function.
|
||||
public subscript(range: Range<Int>) -> Expression<UnderlyingType> {
|
||||
return substring(range.lowerBound, length: range.upperBound - range.lowerBound)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Collection where Iterator.Element : Value, IndexDistance == Int {
|
||||
|
||||
/// Builds a copy of the expression prepended with an `IN` check against the
|
||||
/// collection.
|
||||
///
|
||||
/// let name = Expression<String>("name")
|
||||
/// ["alice", "betty"].contains(name)
|
||||
/// // "name" IN ('alice', 'betty')
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression prepended with an `IN` check against
|
||||
/// the collection.
|
||||
public func contains(_ expression: Expression<Iterator.Element>) -> Expression<Bool> {
|
||||
let templates = [String](repeating: "?", count: count).joined(separator: ", ")
|
||||
return "IN".infix(expression, Expression<Void>("(\(templates))", map { $0.datatypeValue }))
|
||||
}
|
||||
|
||||
/// Builds a copy of the expression prepended with an `IN` check against the
|
||||
/// collection.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// ["alice", "betty"].contains(name)
|
||||
/// // "name" IN ('alice', 'betty')
|
||||
///
|
||||
/// - Parameter pattern: A pattern to match.
|
||||
///
|
||||
/// - Returns: A copy of the expression prepended with an `IN` check against
|
||||
/// the collection.
|
||||
public func contains(_ expression: Expression<Iterator.Element?>) -> Expression<Bool?> {
|
||||
let templates = [String](repeating: "?", count: count).joined(separator: ", ")
|
||||
return "IN".infix(expression, Expression<Void>("(\(templates))", map { $0.datatypeValue }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
|
||||
///
|
||||
/// let name = Expression<String?>("name")
|
||||
/// name ?? "An Anonymous Coward"
|
||||
/// // ifnull("name", 'An Anonymous Coward')
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - optional: An optional expression.
|
||||
///
|
||||
/// - defaultValue: A fallback value for when the optional expression is
|
||||
/// `nil`.
|
||||
///
|
||||
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
|
||||
/// function.
|
||||
public func ??<V : Value>(optional: Expression<V?>, defaultValue: V) -> Expression<V> {
|
||||
return "ifnull".wrap([optional, defaultValue])
|
||||
}
|
||||
|
||||
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
|
||||
///
|
||||
/// let nick = Expression<String?>("nick")
|
||||
/// let name = Expression<String>("name")
|
||||
/// nick ?? name
|
||||
/// // ifnull("nick", "name")
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - optional: An optional expression.
|
||||
///
|
||||
/// - defaultValue: A fallback expression for when the optional expression is
|
||||
/// `nil`.
|
||||
///
|
||||
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
|
||||
/// function.
|
||||
public func ??<V : Value>(optional: Expression<V?>, defaultValue: Expression<V>) -> Expression<V> {
|
||||
return "ifnull".wrap([optional, defaultValue])
|
||||
}
|
||||
|
||||
/// Builds a copy of the given expressions wrapped with the `ifnull` function.
|
||||
///
|
||||
/// let nick = Expression<String?>("nick")
|
||||
/// let name = Expression<String?>("name")
|
||||
/// nick ?? name
|
||||
/// // ifnull("nick", "name")
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - optional: An optional expression.
|
||||
///
|
||||
/// - defaultValue: A fallback expression for when the optional expression is
|
||||
/// `nil`.
|
||||
///
|
||||
/// - Returns: A copy of the given expressions wrapped with the `ifnull`
|
||||
/// function.
|
||||
public func ??<V : Value>(optional: Expression<V?>, defaultValue: Expression<V?>) -> Expression<V> {
|
||||
return "ifnull".wrap([optional, defaultValue])
|
||||
}
|
||||
136
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift
vendored
Normal file
136
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
public extension Connection {
|
||||
|
||||
/// Creates or redefines a custom SQL function.
|
||||
///
|
||||
/// - Parameters:
|
||||
///
|
||||
/// - function: The name of the function to create or redefine.
|
||||
///
|
||||
/// - deterministic: Whether or not the function is deterministic (_i.e._
|
||||
/// the function always returns the same result for a given input).
|
||||
///
|
||||
/// Default: `false`
|
||||
///
|
||||
/// - block: A block of code to run when the function is called.
|
||||
/// The assigned types must be explicit.
|
||||
///
|
||||
/// - Returns: A closure returning an SQL expression to call the function.
|
||||
public func createFunction<Z : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z) throws -> (() -> Expression<Z>) {
|
||||
let fn = try createFunction(function, 0, deterministic) { _ in block() }
|
||||
return { fn([]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z?) throws -> (() -> Expression<Z?>) {
|
||||
let fn = try createFunction(function, 0, deterministic) { _ in block() }
|
||||
return { fn([]) }
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func createFunction<Z : Value, A : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z) throws -> ((Expression<A>) -> Expression<Z>) {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
|
||||
return { arg in fn([arg]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value>(function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z) throws -> ((Expression<A?>) -> Expression<Z>) {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
|
||||
return { arg in fn([arg]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value>(function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z?) throws -> ((Expression<A>) -> Expression<Z?>) {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
|
||||
return { arg in fn([arg]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value>(function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z?) throws -> ((Expression<A?>) -> Expression<Z?>) {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
|
||||
return { arg in fn([arg]) }
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z) throws -> (Expression<A>, Expression<B>) -> Expression<Z> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), value(args[1])) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z) throws -> (Expression<A?>, Expression<B>) -> Expression<Z> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), value(args[1])) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z) throws -> (Expression<A>, Expression<B?>) -> Expression<Z> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), args[1].map(value)) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z?) throws -> (Expression<A>, Expression<B>) -> Expression<Z?> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), value(args[1])) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z) throws -> (Expression<A?>, Expression<B?>) -> Expression<Z> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z?) throws -> (Expression<A?>, Expression<B>) -> Expression<Z?> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), value(args[1])) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z?) throws -> (Expression<A>, Expression<B?>) -> Expression<Z?> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0]), args[1].map(value)) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
public func createFunction<Z : Value, A : Value, B : Value>(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z?) throws -> (Expression<A?>, Expression<B?>) -> Expression<Z?> {
|
||||
let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
|
||||
return { a, b in fn([a, b]) }
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
fileprivate func createFunction<Z : Value>(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z) throws -> (([Expressible]) -> Expression<Z>) {
|
||||
createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
|
||||
block(arguments).datatypeValue
|
||||
}
|
||||
return { arguments in
|
||||
function.quote().wrap(", ".join(arguments))
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func createFunction<Z : Value>(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z?) throws -> (([Expressible]) -> Expression<Z?>) {
|
||||
createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
|
||||
block(arguments)?.datatypeValue
|
||||
}
|
||||
return { arguments in
|
||||
function.quote().wrap(", ".join(arguments))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
147
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Expression.swift
vendored
Normal file
147
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Expression.swift
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
public protocol ExpressionType : Expressible { // extensions cannot have inheritance clauses
|
||||
|
||||
associatedtype UnderlyingType = Void
|
||||
|
||||
var template: String { get }
|
||||
var bindings: [Binding?] { get }
|
||||
|
||||
init(_ template: String, _ bindings: [Binding?])
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType {
|
||||
|
||||
public init(literal: String) {
|
||||
self.init(literal, [])
|
||||
}
|
||||
|
||||
public init(_ identifier: String) {
|
||||
self.init(literal: identifier.quote())
|
||||
}
|
||||
|
||||
public init<U : ExpressionType>(_ expression: U) {
|
||||
self.init(expression.template, expression.bindings)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// An `Expression` represents a raw SQL fragment and any associated bindings.
|
||||
public struct Expression<Datatype> : ExpressionType {
|
||||
|
||||
public typealias UnderlyingType = Datatype
|
||||
|
||||
public var template: String
|
||||
public var bindings: [Binding?]
|
||||
|
||||
public init(_ template: String, _ bindings: [Binding?]) {
|
||||
self.template = template
|
||||
self.bindings = bindings
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public protocol Expressible {
|
||||
|
||||
var expression: Expression<Void> { get }
|
||||
|
||||
}
|
||||
|
||||
extension Expressible {
|
||||
|
||||
// naïve compiler for statements that can’t be bound, e.g., CREATE TABLE
|
||||
// FIXME: use @testable and make internal
|
||||
public func asSQL() -> String {
|
||||
let expressed = expression
|
||||
var idx = 0
|
||||
return expressed.template.characters.reduce("") { template, character in
|
||||
let transcoded: String
|
||||
|
||||
if character == "?" {
|
||||
transcoded = transcode(expressed.bindings[idx])
|
||||
idx += 1
|
||||
} else {
|
||||
transcoded = String(character)
|
||||
}
|
||||
return template + transcoded
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType {
|
||||
|
||||
public var expression: Expression<Void> {
|
||||
return Expression(template, bindings)
|
||||
}
|
||||
|
||||
public var asc: Expressible {
|
||||
return " ".join([self, Expression<Void>(literal: "ASC")])
|
||||
}
|
||||
|
||||
public var desc: Expressible {
|
||||
return " ".join([self, Expression<Void>(literal: "DESC")])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : Value {
|
||||
|
||||
public init(value: UnderlyingType) {
|
||||
self.init("?", [value.datatypeValue])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
|
||||
|
||||
public static var null: Self {
|
||||
return self.init(value: nil)
|
||||
}
|
||||
|
||||
public init(value: UnderlyingType.WrappedType?) {
|
||||
self.init("?", [value?.datatypeValue])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Value {
|
||||
|
||||
public var expression: Expression<Void> {
|
||||
return Expression(value: self).expression
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public let rowid = Expression<Int64>("ROWID")
|
||||
|
||||
public func cast<T: Value, U: Value>(_ expression: Expression<T>) -> Expression<U> {
|
||||
return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
|
||||
}
|
||||
|
||||
public func cast<T: Value, U: Value>(_ expression: Expression<T?>) -> Expression<U?> {
|
||||
return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
|
||||
}
|
||||
541
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Operators.swift
vendored
Normal file
541
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Operators.swift
vendored
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
// TODO: use `@warn_unused_result` by the time operator functions support it
|
||||
|
||||
public func +(lhs: Expression<String>, rhs: Expression<String>) -> Expression<String> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func +(lhs: Expression<String>, rhs: Expression<String?>) -> Expression<String?> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: Expression<String?>, rhs: Expression<String>) -> Expression<String?> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: Expression<String?>, rhs: Expression<String?>) -> Expression<String?> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: Expression<String>, rhs: String) -> Expression<String> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: Expression<String?>, rhs: String) -> Expression<String?> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: String, rhs: Expression<String>) -> Expression<String> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
public func +(lhs: String, rhs: Expression<String?>) -> Expression<String?> {
|
||||
return "||".infix(lhs, rhs)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func +<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func +<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func -<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func -<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func *<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func *<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func /<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func /<V: Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public prefix func -<V : Value>(rhs: Expression<V>) -> Expression<V> where V.Datatype : Number {
|
||||
return wrap(rhs)
|
||||
}
|
||||
public prefix func -<V : Value>(rhs: Expression<V?>) -> Expression<V?> where V.Datatype : Number {
|
||||
return wrap(rhs)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func %<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func %<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func <<<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func >><V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >><V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func &<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func &<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func |<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func |<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func ^<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<V> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
public func ^<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return (~(lhs & rhs)) & (lhs | rhs)
|
||||
}
|
||||
|
||||
public prefix func ~<V : Value>(rhs: Expression<V>) -> Expression<V> where V.Datatype == Int64 {
|
||||
return wrap(rhs)
|
||||
}
|
||||
public prefix func ~<V : Value>(rhs: Expression<V?>) -> Expression<V?> where V.Datatype == Int64 {
|
||||
return wrap(rhs)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func ==<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: Expression<V?>, rhs: V?) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
guard let rhs = rhs else { return "IS".infix(lhs, Expression<V?>(value: nil)) }
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
public func ==<V : Value>(lhs: V?, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
guard let lhs = lhs else { return "IS".infix(Expression<V?>(value: nil), rhs) }
|
||||
return "=".infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func !=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: Expression<V?>, rhs: V?) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
guard let rhs = rhs else { return "IS NOT".infix(lhs, Expression<V?>(value: nil)) }
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Equatable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func !=<V : Value>(lhs: V?, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Equatable {
|
||||
guard let lhs = lhs else { return "IS NOT".infix(Expression<V?>(value: nil), rhs) }
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func ><V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func ><V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func >=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func >=<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func <<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func <=<V : Value>(lhs: Expression<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: Expression<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: Expression<V?>, rhs: Expression<V>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: Expression<V?>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: Expression<V>, rhs: V) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: Expression<V?>, rhs: V) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: V, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
public func <=<V : Value>(lhs: V, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Comparable {
|
||||
return infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func ~=<V : Value>(lhs: ClosedRange<V>, rhs: Expression<V>) -> Expression<Bool> where V.Datatype : Binding & Comparable {
|
||||
return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound as? Binding, lhs.upperBound as? Binding])
|
||||
}
|
||||
public func ~=<V : Value>(lhs: ClosedRange<V>, rhs: Expression<V?>) -> Expression<Bool?> where V.Datatype : Binding & Comparable {
|
||||
return Expression("\(rhs.template) BETWEEN ? AND ?", rhs.bindings + [lhs.lowerBound as? Binding, lhs.upperBound as? Binding])
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func &&(lhs: Expression<Bool>, rhs: Expression<Bool>) -> Expression<Bool> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Expression<Bool>, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Expression<Bool?>, rhs: Expression<Bool>) -> Expression<Bool?> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Expression<Bool?>, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Expression<Bool>, rhs: Bool) -> Expression<Bool> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Expression<Bool?>, rhs: Bool) -> Expression<Bool?> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Bool, rhs: Expression<Bool>) -> Expression<Bool> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
public func &&(lhs: Bool, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "AND".infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public func ||(lhs: Expression<Bool>, rhs: Expression<Bool>) -> Expression<Bool> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Expression<Bool>, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Expression<Bool?>, rhs: Expression<Bool>) -> Expression<Bool?> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Expression<Bool?>, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Expression<Bool>, rhs: Bool) -> Expression<Bool> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Expression<Bool?>, rhs: Bool) -> Expression<Bool?> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Bool, rhs: Expression<Bool>) -> Expression<Bool> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
public func ||(lhs: Bool, rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "OR".infix(lhs, rhs)
|
||||
}
|
||||
|
||||
public prefix func !(rhs: Expression<Bool>) -> Expression<Bool> {
|
||||
return "NOT ".wrap(rhs)
|
||||
}
|
||||
public prefix func !(rhs: Expression<Bool?>) -> Expression<Bool?> {
|
||||
return "NOT ".wrap(rhs)
|
||||
}
|
||||
1162
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Query.swift
vendored
Normal file
1162
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Query.swift
vendored
Normal file
File diff suppressed because it is too large
Load diff
519
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Schema.swift
vendored
Normal file
519
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Schema.swift
vendored
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
extension SchemaType {
|
||||
|
||||
// MARK: - DROP TABLE / VIEW / VIRTUAL TABLE
|
||||
|
||||
public func drop(ifExists: Bool = false) -> String {
|
||||
return drop("TABLE", tableName(), ifExists)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Table {
|
||||
|
||||
// MARK: - CREATE TABLE
|
||||
|
||||
public func create(temporary: Bool = false, ifNotExists: Bool = false, block: (TableBuilder) -> Void) -> String {
|
||||
let builder = TableBuilder()
|
||||
|
||||
block(builder)
|
||||
|
||||
let clauses: [Expressible?] = [
|
||||
create(Table.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists),
|
||||
"".wrap(builder.definitions) as Expression<Void>
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String {
|
||||
let clauses: [Expressible?] = [
|
||||
create(Table.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists),
|
||||
Expression<Void>(literal: "AS"),
|
||||
query
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
// MARK: - ALTER TABLE … ADD COLUMN
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool>? = nil, defaultValue: V) -> String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool?>, defaultValue: V) -> String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool>? = nil, defaultValue: V? = nil) -> String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool?>, defaultValue: V? = nil) -> String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) -> String where V.Datatype == Int64 {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) -> String where V.Datatype == String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V>, check: Expression<Bool?>, defaultValue: V, collate: Collation) -> String where V.Datatype == String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, false, false, check, defaultValue, nil, collate))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool>? = nil, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate))
|
||||
}
|
||||
|
||||
public func addColumn<V : Value>(_ name: Expression<V?>, check: Expression<Bool?>, defaultValue: V? = nil, collate: Collation) -> String where V.Datatype == String {
|
||||
return addColumn(definition(name, V.declaredDatatype, nil, true, false, check, defaultValue, nil, collate))
|
||||
}
|
||||
|
||||
fileprivate func addColumn(_ expression: Expressible) -> String {
|
||||
return " ".join([
|
||||
Expression<Void>(literal: "ALTER TABLE"),
|
||||
tableName(),
|
||||
Expression<Void>(literal: "ADD COLUMN"),
|
||||
expression
|
||||
]).asSQL()
|
||||
}
|
||||
|
||||
// MARK: - ALTER TABLE … RENAME TO
|
||||
|
||||
public func rename(_ to: Table) -> String {
|
||||
return rename(to: to)
|
||||
}
|
||||
|
||||
// MARK: - CREATE INDEX
|
||||
|
||||
public func createIndex(_ columns: Expressible...) -> String {
|
||||
return createIndex(columns)
|
||||
}
|
||||
|
||||
public func createIndex(_ columns: [Expressible], unique: Bool = false, ifNotExists: Bool = false) -> String {
|
||||
let clauses: [Expressible?] = [
|
||||
create("INDEX", indexName(columns), unique ? .Unique : nil, ifNotExists),
|
||||
Expression<Void>(literal: "ON"),
|
||||
tableName(qualified: false),
|
||||
"".wrap(columns) as Expression<Void>
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
// MARK: - DROP INDEX
|
||||
|
||||
public func dropIndex(_ columns: Expressible...) -> String {
|
||||
return dropIndex(columns)
|
||||
}
|
||||
|
||||
public func dropIndex(_ columns: [Expressible], ifExists: Bool = false) -> String {
|
||||
return drop("INDEX", indexName(columns), ifExists)
|
||||
}
|
||||
|
||||
fileprivate func indexName(_ columns: [Expressible]) -> Expressible {
|
||||
let string = (["index", clauses.from.name, "on"] + columns.map { $0.expression.template }).joined(separator: " ").lowercased()
|
||||
|
||||
let index = string.characters.reduce("") { underscored, character in
|
||||
guard character != "\"" else {
|
||||
return underscored
|
||||
}
|
||||
guard "a"..."z" ~= character || "0"..."9" ~= character else {
|
||||
return underscored + "_"
|
||||
}
|
||||
return underscored + String(character)
|
||||
}
|
||||
|
||||
return database(namespace: index)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension View {
|
||||
|
||||
// MARK: - CREATE VIEW
|
||||
|
||||
public func create(_ query: QueryType, temporary: Bool = false, ifNotExists: Bool = false) -> String {
|
||||
let clauses: [Expressible?] = [
|
||||
create(View.identifier, tableName(), temporary ? .Temporary : nil, ifNotExists),
|
||||
Expression<Void>(literal: "AS"),
|
||||
query
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
// MARK: - DROP VIEW
|
||||
|
||||
public func drop(ifExists: Bool = false) -> String {
|
||||
return drop("VIEW", tableName(), ifExists)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VirtualTable {
|
||||
|
||||
// MARK: - CREATE VIRTUAL TABLE
|
||||
|
||||
public func create(_ using: Module, ifNotExists: Bool = false) -> String {
|
||||
let clauses: [Expressible?] = [
|
||||
create(VirtualTable.identifier, tableName(), nil, ifNotExists),
|
||||
Expression<Void>(literal: "USING"),
|
||||
using
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
// MARK: - ALTER TABLE … RENAME TO
|
||||
|
||||
public func rename(_ to: VirtualTable) -> String {
|
||||
return rename(to: to)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class TableBuilder {
|
||||
|
||||
fileprivate var definitions = [Expressible]()
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V) {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V) {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V?>) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V?>) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V) {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, primaryKey: Bool, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, primaryKey: Bool, check: Expression<Bool?>, defaultValue: Expression<V>? = nil) {
|
||||
column(name, V.declaredDatatype, primaryKey ? .default : nil, false, false, check, defaultValue, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, primaryKey: PrimaryKey, check: Expression<Bool>? = nil) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, primaryKey: PrimaryKey, check: Expression<Bool?>) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, primaryKey, false, false, check, nil, nil, nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, nil, (table, other), nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, references table: QueryType, _ other: Expression<V>) where V.Datatype == Int64 {
|
||||
column(name, V.declaredDatatype, nil, true, unique, check, nil, (table, other), nil)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: Expression<V?>, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool>? = nil, defaultValue: V, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V>? = nil, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: Expression<V?>, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
public func column<V : Value>(_ name: Expression<V?>, unique: Bool = false, check: Expression<Bool?>, defaultValue: V, collate: Collation) where V.Datatype == String {
|
||||
column(name, V.declaredDatatype, nil, false, unique, check, defaultValue, nil, collate)
|
||||
}
|
||||
|
||||
fileprivate func column(_ name: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) {
|
||||
definitions.append(definition(name, datatype, primaryKey, null, unique, check, defaultValue, references, collate))
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func primaryKey<T : Value>(_ column: Expression<T>) {
|
||||
primaryKey([column])
|
||||
}
|
||||
|
||||
public func primaryKey<T : Value, U : Value>(_ compositeA: Expression<T>, _ b: Expression<U>) {
|
||||
primaryKey([compositeA, b])
|
||||
}
|
||||
|
||||
public func primaryKey<T : Value, U : Value, V : Value>(_ compositeA: Expression<T>, _ b: Expression<U>, _ c: Expression<V>) {
|
||||
primaryKey([compositeA, b, c])
|
||||
}
|
||||
|
||||
fileprivate func primaryKey(_ composite: [Expressible]) {
|
||||
definitions.append("PRIMARY KEY".prefix(composite))
|
||||
}
|
||||
|
||||
public func unique(_ columns: Expressible...) {
|
||||
unique(columns)
|
||||
}
|
||||
|
||||
public func unique(_ columns: [Expressible]) {
|
||||
definitions.append("UNIQUE".prefix(columns))
|
||||
}
|
||||
|
||||
public func check(_ condition: Expression<Bool>) {
|
||||
check(Expression<Bool?>(condition))
|
||||
}
|
||||
|
||||
public func check(_ condition: Expression<Bool?>) {
|
||||
definitions.append("CHECK".prefix(condition))
|
||||
}
|
||||
|
||||
public enum Dependency: String {
|
||||
|
||||
case noAction = "NO ACTION"
|
||||
|
||||
case restrict = "RESTRICT"
|
||||
|
||||
case setNull = "SET NULL"
|
||||
|
||||
case setDefault = "SET DEFAULT"
|
||||
|
||||
case cascade = "CASCADE"
|
||||
|
||||
}
|
||||
|
||||
public func foreignKey<T : Value>(_ column: Expression<T>, references table: QueryType, _ other: Expression<T>, update: Dependency? = nil, delete: Dependency? = nil) {
|
||||
foreignKey(column, (table, other), update, delete)
|
||||
}
|
||||
|
||||
public func foreignKey<T : Value>(_ column: Expression<T?>, references table: QueryType, _ other: Expression<T>, update: Dependency? = nil, delete: Dependency? = nil) {
|
||||
foreignKey(column, (table, other), update, delete)
|
||||
}
|
||||
|
||||
public func foreignKey<T : Value, U : Value>(_ composite: (Expression<T>, Expression<U>), references table: QueryType, _ other: (Expression<T>, Expression<U>), update: Dependency? = nil, delete: Dependency? = nil) {
|
||||
let composite = ", ".join([composite.0, composite.1])
|
||||
let references = (table, ", ".join([other.0, other.1]))
|
||||
|
||||
foreignKey(composite, references, update, delete)
|
||||
}
|
||||
|
||||
public func foreignKey<T : Value, U : Value, V : Value>(_ composite: (Expression<T>, Expression<U>, Expression<V>), references table: QueryType, _ other: (Expression<T>, Expression<U>, Expression<V>), update: Dependency? = nil, delete: Dependency? = nil) {
|
||||
let composite = ", ".join([composite.0, composite.1, composite.2])
|
||||
let references = (table, ", ".join([other.0, other.1, other.2]))
|
||||
|
||||
foreignKey(composite, references, update, delete)
|
||||
}
|
||||
|
||||
fileprivate func foreignKey(_ column: Expressible, _ references: (QueryType, Expressible), _ update: Dependency?, _ delete: Dependency?) {
|
||||
let clauses: [Expressible?] = [
|
||||
"FOREIGN KEY".prefix(column),
|
||||
reference(references),
|
||||
update.map { Expression<Void>(literal: "ON UPDATE \($0.rawValue)") },
|
||||
delete.map { Expression<Void>(literal: "ON DELETE \($0.rawValue)") }
|
||||
]
|
||||
|
||||
definitions.append(" ".join(clauses.flatMap { $0 }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum PrimaryKey {
|
||||
|
||||
case `default`
|
||||
|
||||
case autoincrement
|
||||
|
||||
}
|
||||
|
||||
public struct Module {
|
||||
|
||||
fileprivate let name: String
|
||||
|
||||
fileprivate let arguments: [Expressible]
|
||||
|
||||
public init(_ name: String, _ arguments: [Expressible]) {
|
||||
self.init(name: name.quote(), arguments: arguments)
|
||||
}
|
||||
|
||||
init(name: String, arguments: [Expressible]) {
|
||||
self.name = name
|
||||
self.arguments = arguments
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Module : Expressible {
|
||||
|
||||
public var expression: Expression<Void> {
|
||||
return name.wrap(arguments)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private extension QueryType {
|
||||
|
||||
func create(_ identifier: String, _ name: Expressible, _ modifier: Modifier?, _ ifNotExists: Bool) -> Expressible {
|
||||
let clauses: [Expressible?] = [
|
||||
Expression<Void>(literal: "CREATE"),
|
||||
modifier.map { Expression<Void>(literal: $0.rawValue) },
|
||||
Expression<Void>(literal: identifier),
|
||||
ifNotExists ? Expression<Void>(literal: "IF NOT EXISTS") : nil,
|
||||
name
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 })
|
||||
}
|
||||
|
||||
func rename(to: Self) -> String {
|
||||
return " ".join([
|
||||
Expression<Void>(literal: "ALTER TABLE"),
|
||||
tableName(),
|
||||
Expression<Void>(literal: "RENAME TO"),
|
||||
Expression<Void>(to.clauses.from.name)
|
||||
]).asSQL()
|
||||
}
|
||||
|
||||
func drop(_ identifier: String, _ name: Expressible, _ ifExists: Bool) -> String {
|
||||
let clauses: [Expressible?] = [
|
||||
Expression<Void>(literal: "DROP \(identifier)"),
|
||||
ifExists ? Expression<Void>(literal: "IF EXISTS") : nil,
|
||||
name
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 }).asSQL()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func definition(_ column: Expressible, _ datatype: String, _ primaryKey: PrimaryKey?, _ null: Bool, _ unique: Bool, _ check: Expressible?, _ defaultValue: Expressible?, _ references: (QueryType, Expressible)?, _ collate: Collation?) -> Expressible {
|
||||
let clauses: [Expressible?] = [
|
||||
column,
|
||||
Expression<Void>(literal: datatype),
|
||||
primaryKey.map { Expression<Void>(literal: $0 == .autoincrement ? "PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY") },
|
||||
null ? nil : Expression<Void>(literal: "NOT NULL"),
|
||||
unique ? Expression<Void>(literal: "UNIQUE") : nil,
|
||||
check.map { " ".join([Expression<Void>(literal: "CHECK"), $0]) },
|
||||
defaultValue.map { "DEFAULT".prefix($0) },
|
||||
references.map(reference),
|
||||
collate.map { " ".join([Expression<Void>(literal: "COLLATE"), $0]) }
|
||||
]
|
||||
|
||||
return " ".join(clauses.flatMap { $0 })
|
||||
}
|
||||
|
||||
private func reference(_ primary: (QueryType, Expressible)) -> Expressible {
|
||||
return " ".join([
|
||||
Expression<Void>(literal: "REFERENCES"),
|
||||
primary.0.tableName(qualified: false),
|
||||
"".wrap(primary.1) as Expression<Void>
|
||||
])
|
||||
}
|
||||
|
||||
private enum Modifier : String {
|
||||
|
||||
case Unique = "UNIQUE"
|
||||
|
||||
case Temporary = "TEMPORARY"
|
||||
|
||||
}
|
||||
277
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Setter.swift
vendored
Normal file
277
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLite/Typed/Setter.swift
vendored
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
precedencegroup ColumnAssignment {
|
||||
associativity: left
|
||||
assignment: true
|
||||
lowerThan: AssignmentPrecedence
|
||||
}
|
||||
|
||||
infix operator <- : ColumnAssignment
|
||||
|
||||
public struct Setter {
|
||||
|
||||
let column: Expressible
|
||||
let value: Expressible
|
||||
|
||||
fileprivate init<V : Value>(column: Expression<V>, value: Expression<V>) {
|
||||
self.column = column
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init<V : Value>(column: Expression<V>, value: V) {
|
||||
self.column = column
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init<V : Value>(column: Expression<V?>, value: Expression<V>) {
|
||||
self.column = column
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init<V : Value>(column: Expression<V?>, value: Expression<V?>) {
|
||||
self.column = column
|
||||
self.value = value
|
||||
}
|
||||
|
||||
fileprivate init<V : Value>(column: Expression<V?>, value: V?) {
|
||||
self.column = column
|
||||
self.value = Expression<V?>(value: value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Setter : Expressible {
|
||||
|
||||
public var expression: Expression<Void> {
|
||||
return "=".infix(column, value, wrap: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func <-<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter {
|
||||
return Setter(column: column, value: value)
|
||||
}
|
||||
public func <-<V : Value>(column: Expression<V>, value: V) -> Setter {
|
||||
return Setter(column: column, value: value)
|
||||
}
|
||||
public func <-<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter {
|
||||
return Setter(column: column, value: value)
|
||||
}
|
||||
public func <-<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter {
|
||||
return Setter(column: column, value: value)
|
||||
}
|
||||
public func <-<V : Value>(column: Expression<V?>, value: V?) -> Setter {
|
||||
return Setter(column: column, value: value)
|
||||
}
|
||||
|
||||
public func +=(column: Expression<String>, value: Expression<String>) -> Setter {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=(column: Expression<String>, value: String) -> Setter {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=(column: Expression<String?>, value: Expression<String>) -> Setter {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=(column: Expression<String?>, value: Expression<String?>) -> Setter {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=(column: Expression<String?>, value: String) -> Setter {
|
||||
return column <- column + value
|
||||
}
|
||||
|
||||
public func +=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
|
||||
return column <- column + value
|
||||
}
|
||||
public func +=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column + value
|
||||
}
|
||||
|
||||
public func -=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column - value
|
||||
}
|
||||
public func -=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column - value
|
||||
}
|
||||
public func -=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column - value
|
||||
}
|
||||
public func -=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
|
||||
return column <- column - value
|
||||
}
|
||||
public func -=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column - value
|
||||
}
|
||||
|
||||
public func *=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column * value
|
||||
}
|
||||
public func *=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column * value
|
||||
}
|
||||
public func *=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column * value
|
||||
}
|
||||
public func *=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
|
||||
return column <- column * value
|
||||
}
|
||||
public func *=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column * value
|
||||
}
|
||||
|
||||
public func /=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column / value
|
||||
}
|
||||
public func /=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column / value
|
||||
}
|
||||
public func /=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype : Number {
|
||||
return column <- column / value
|
||||
}
|
||||
public func /=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype : Number {
|
||||
return column <- column / value
|
||||
}
|
||||
public func /=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype : Number {
|
||||
return column <- column / value
|
||||
}
|
||||
|
||||
public func %=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column % value
|
||||
}
|
||||
public func %=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column % value
|
||||
}
|
||||
public func %=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column % value
|
||||
}
|
||||
public func %=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column % value
|
||||
}
|
||||
public func %=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column % value
|
||||
}
|
||||
|
||||
public func <<=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column << value
|
||||
}
|
||||
public func <<=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column << value
|
||||
}
|
||||
public func <<=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column << value
|
||||
}
|
||||
public func <<=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column << value
|
||||
}
|
||||
public func <<=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column << value
|
||||
}
|
||||
|
||||
public func >>=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column >> value
|
||||
}
|
||||
public func >>=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column >> value
|
||||
}
|
||||
public func >>=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column >> value
|
||||
}
|
||||
public func >>=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column >> value
|
||||
}
|
||||
public func >>=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column >> value
|
||||
}
|
||||
|
||||
public func &=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column & value
|
||||
}
|
||||
public func &=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column & value
|
||||
}
|
||||
public func &=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column & value
|
||||
}
|
||||
public func &=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column & value
|
||||
}
|
||||
public func &=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column & value
|
||||
}
|
||||
|
||||
public func |=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column | value
|
||||
}
|
||||
public func |=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column | value
|
||||
}
|
||||
public func |=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column | value
|
||||
}
|
||||
public func |=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column | value
|
||||
}
|
||||
public func |=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column | value
|
||||
}
|
||||
|
||||
public func ^=<V : Value>(column: Expression<V>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column ^ value
|
||||
}
|
||||
public func ^=<V : Value>(column: Expression<V>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column ^ value
|
||||
}
|
||||
public func ^=<V : Value>(column: Expression<V?>, value: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column ^ value
|
||||
}
|
||||
public func ^=<V : Value>(column: Expression<V?>, value: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column ^ value
|
||||
}
|
||||
public func ^=<V : Value>(column: Expression<V?>, value: V) -> Setter where V.Datatype == Int64 {
|
||||
return column <- column ^ value
|
||||
}
|
||||
|
||||
public postfix func ++<V : Value>(column: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return Expression<Int>(column) += 1
|
||||
}
|
||||
public postfix func ++<V : Value>(column: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return Expression<Int>(column) += 1
|
||||
}
|
||||
|
||||
public postfix func --<V : Value>(column: Expression<V>) -> Setter where V.Datatype == Int64 {
|
||||
return Expression<Int>(column) -= 1
|
||||
}
|
||||
public postfix func --<V : Value>(column: Expression<V?>) -> Setter where V.Datatype == Int64 {
|
||||
return Expression<Int>(column) -= 1
|
||||
}
|
||||
138
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m
vendored
Normal file
138
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#import "SQLite-Bridging.h"
|
||||
#import "fts3_tokenizer.h"
|
||||
|
||||
#pragma mark - FTS
|
||||
|
||||
typedef struct __SQLiteTokenizer {
|
||||
sqlite3_tokenizer base;
|
||||
__unsafe_unretained _SQLiteTokenizerNextCallback callback;
|
||||
} __SQLiteTokenizer;
|
||||
|
||||
typedef struct __SQLiteTokenizerCursor {
|
||||
void * base;
|
||||
const char * input;
|
||||
int inputOffset;
|
||||
int inputLength;
|
||||
int idx;
|
||||
} __SQLiteTokenizerCursor;
|
||||
|
||||
static NSMutableDictionary * __SQLiteTokenizerMap;
|
||||
|
||||
static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) {
|
||||
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer));
|
||||
if (!tokenizer) {
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(tokenizer, 0, sizeof(* tokenizer));
|
||||
|
||||
NSString * key = [NSString stringWithUTF8String:argv[0]];
|
||||
tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key];
|
||||
if (!tokenizer->callback) {
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
*ppTokenizer = &tokenizer->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) {
|
||||
sqlite3_free(pTokenizer);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) {
|
||||
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor));
|
||||
if (!cursor) {
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
cursor->input = pInput;
|
||||
cursor->inputOffset = 0;
|
||||
cursor->inputLength = 0;
|
||||
cursor->idx = 0;
|
||||
|
||||
*ppCursor = (sqlite3_tokenizer_cursor *)cursor;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) {
|
||||
sqlite3_free(pCursor);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) {
|
||||
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor;
|
||||
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base;
|
||||
|
||||
cursor->inputOffset += cursor->inputLength;
|
||||
const char * input = cursor->input + cursor->inputOffset;
|
||||
const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
if (!token) {
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
|
||||
*ppToken = token;
|
||||
*pnBytes = (int)strlen(token);
|
||||
*piStartOffset = cursor->inputOffset;
|
||||
*piEndOffset = cursor->inputOffset + cursor->inputLength;
|
||||
*piPosition = cursor->idx++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static const sqlite3_tokenizer_module __SQLiteTokenizerModule = {
|
||||
0,
|
||||
__SQLiteTokenizerCreate,
|
||||
__SQLiteTokenizerDestroy,
|
||||
__SQLiteTokenizerOpen,
|
||||
__SQLiteTokenizerClose,
|
||||
__SQLiteTokenizerNext
|
||||
};
|
||||
|
||||
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
__SQLiteTokenizerMap = [NSMutableDictionary new];
|
||||
});
|
||||
|
||||
sqlite3_stmt * stmt;
|
||||
int status = sqlite3_prepare_v2((sqlite3 *)db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0);
|
||||
if (status != SQLITE_OK ){
|
||||
return status;
|
||||
}
|
||||
const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule;
|
||||
sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC);
|
||||
sqlite3_step(stmt);
|
||||
status = sqlite3_finalize(stmt);
|
||||
if (status != SQLITE_OK ){
|
||||
return status;
|
||||
}
|
||||
|
||||
[__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]];
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
161
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h
vendored
Normal file
161
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
** 2006 July 10
|
||||
**
|
||||
** The author disclaims copyright to this source code.
|
||||
**
|
||||
*************************************************************************
|
||||
** Defines the interface to tokenizers used by fulltext-search. There
|
||||
** are three basic components:
|
||||
**
|
||||
** sqlite3_tokenizer_module is a singleton defining the tokenizer
|
||||
** interface functions. This is essentially the class structure for
|
||||
** tokenizers.
|
||||
**
|
||||
** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
|
||||
** including customization information defined at creation time.
|
||||
**
|
||||
** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
|
||||
** tokens from a particular input.
|
||||
*/
|
||||
#ifndef _FTS3_TOKENIZER_H_
|
||||
#define _FTS3_TOKENIZER_H_
|
||||
|
||||
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
|
||||
** If tokenizers are to be allowed to call sqlite3_*() functions, then
|
||||
** we will need a way to register the API consistently.
|
||||
*/
|
||||
#import "sqlite3.h"
|
||||
|
||||
/*
|
||||
** Structures used by the tokenizer interface. When a new tokenizer
|
||||
** implementation is registered, the caller provides a pointer to
|
||||
** an sqlite3_tokenizer_module containing pointers to the callback
|
||||
** functions that make up an implementation.
|
||||
**
|
||||
** When an fts3 table is created, it passes any arguments passed to
|
||||
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
|
||||
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
|
||||
** implementation. The xCreate() function in turn returns an
|
||||
** sqlite3_tokenizer structure representing the specific tokenizer to
|
||||
** be used for the fts3 table (customized by the tokenizer clause arguments).
|
||||
**
|
||||
** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
|
||||
** method is called. It returns an sqlite3_tokenizer_cursor object
|
||||
** that may be used to tokenize a specific input buffer based on
|
||||
** the tokenization rules supplied by a specific sqlite3_tokenizer
|
||||
** object.
|
||||
*/
|
||||
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
|
||||
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
|
||||
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
|
||||
|
||||
struct sqlite3_tokenizer_module {
|
||||
|
||||
/*
|
||||
** Structure version. Should always be set to 0 or 1.
|
||||
*/
|
||||
int iVersion;
|
||||
|
||||
/*
|
||||
** Create a new tokenizer. The values in the argv[] array are the
|
||||
** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
|
||||
** TABLE statement that created the fts3 table. For example, if
|
||||
** the following SQL is executed:
|
||||
**
|
||||
** CREATE .. USING fts3( ... , tokenizer <tokenizer-name> arg1 arg2)
|
||||
**
|
||||
** then argc is set to 2, and the argv[] array contains pointers
|
||||
** to the strings "arg1" and "arg2".
|
||||
**
|
||||
** This method should return either SQLITE_OK (0), or an SQLite error
|
||||
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
|
||||
** to point at the newly created tokenizer structure. The generic
|
||||
** sqlite3_tokenizer.pModule variable should not be initialized by
|
||||
** this callback. The caller will do so.
|
||||
*/
|
||||
int (*xCreate)(
|
||||
int argc, /* Size of argv array */
|
||||
const char *const*argv, /* Tokenizer argument strings */
|
||||
sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
|
||||
);
|
||||
|
||||
/*
|
||||
** Destroy an existing tokenizer. The fts3 module calls this method
|
||||
** exactly once for each successful call to xCreate().
|
||||
*/
|
||||
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
|
||||
|
||||
/*
|
||||
** Create a tokenizer cursor to tokenize an input buffer. The caller
|
||||
** is responsible for ensuring that the input buffer remains valid
|
||||
** until the cursor is closed (using the xClose() method).
|
||||
*/
|
||||
int (*xOpen)(
|
||||
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
|
||||
const char *pInput, int nBytes, /* Input buffer */
|
||||
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
|
||||
);
|
||||
|
||||
/*
|
||||
** Destroy an existing tokenizer cursor. The fts3 module calls this
|
||||
** method exactly once for each successful call to xOpen().
|
||||
*/
|
||||
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
|
||||
|
||||
/*
|
||||
** Retrieve the next token from the tokenizer cursor pCursor. This
|
||||
** method should either return SQLITE_OK and set the values of the
|
||||
** "OUT" variables identified below, or SQLITE_DONE to indicate that
|
||||
** the end of the buffer has been reached, or an SQLite error code.
|
||||
**
|
||||
** *ppToken should be set to point at a buffer containing the
|
||||
** normalized version of the token (i.e. after any case-folding and/or
|
||||
** stemming has been performed). *pnBytes should be set to the length
|
||||
** of this buffer in bytes. The input text that generated the token is
|
||||
** identified by the byte offsets returned in *piStartOffset and
|
||||
** *piEndOffset. *piStartOffset should be set to the index of the first
|
||||
** byte of the token in the input buffer. *piEndOffset should be set
|
||||
** to the index of the first byte just past the end of the token in
|
||||
** the input buffer.
|
||||
**
|
||||
** The buffer *ppToken is set to point at is managed by the tokenizer
|
||||
** implementation. It is only required to be valid until the next call
|
||||
** to xNext() or xClose().
|
||||
*/
|
||||
/* TODO(shess) current implementation requires pInput to be
|
||||
** nul-terminated. This should either be fixed, or pInput/nBytes
|
||||
** should be converted to zInput.
|
||||
*/
|
||||
int (*xNext)(
|
||||
sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
|
||||
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
|
||||
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
|
||||
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
|
||||
int *piPosition /* OUT: Number of tokens returned before this one */
|
||||
);
|
||||
|
||||
/***********************************************************************
|
||||
** Methods below this point are only available if iVersion>=1.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Configure the language id of a tokenizer cursor.
|
||||
*/
|
||||
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
|
||||
};
|
||||
|
||||
struct sqlite3_tokenizer {
|
||||
const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
|
||||
/* Tokenizer implementations will typically add additional fields */
|
||||
};
|
||||
|
||||
struct sqlite3_tokenizer_cursor {
|
||||
sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
|
||||
/* Tokenizer implementations will typically add additional fields */
|
||||
};
|
||||
|
||||
int fts3_global_term_cnt(int iTerm, int iCol);
|
||||
int fts3_term_cnt(int iTerm, int iCol);
|
||||
|
||||
|
||||
#endif /* _FTS3_TOKENIZER_H_ */
|
||||
37
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h
vendored
Normal file
37
mobile/ios/ThirdParty/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// SQLite.swift
|
||||
// https://github.com/stephencelis/SQLite.swift
|
||||
// Copyright © 2014-2015 Stephen Celis.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
#ifndef COCOAPODS
|
||||
#import "sqlite3.h"
|
||||
#endif
|
||||
|
||||
typedef struct SQLiteHandle SQLiteHandle; // CocoaPods workaround
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char * input, int * inputOffset, int * inputLength);
|
||||
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * module, const char * tokenizer, _Nullable _SQLiteTokenizerNextCallback callback);
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
1
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/.gitignore
vendored
Normal file
1
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
gems/
|
||||
4
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile
vendored
Normal file
4
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'cocoapods', '~> 1.1.0'
|
||||
gem 'minitest'
|
||||
74
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile.lock
vendored
Normal file
74
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Gemfile.lock
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.3)
|
||||
activesupport (4.2.7.1)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
claide (1.0.1)
|
||||
cocoapods (1.1.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
claide (>= 1.0.1, < 2.0)
|
||||
cocoapods-core (= 1.1.1)
|
||||
cocoapods-deintegrate (>= 1.0.1, < 2.0)
|
||||
cocoapods-downloader (>= 1.1.2, < 2.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
cocoapods-search (>= 1.0.0, < 2.0)
|
||||
cocoapods-stats (>= 1.0.0, < 2.0)
|
||||
cocoapods-trunk (>= 1.1.1, < 2.0)
|
||||
cocoapods-try (>= 1.1.0, < 2.0)
|
||||
colored (~> 1.2)
|
||||
escape (~> 0.0.4)
|
||||
fourflusher (~> 2.0.1)
|
||||
gh_inspector (~> 1.0)
|
||||
molinillo (~> 0.5.1)
|
||||
nap (~> 1.0)
|
||||
xcodeproj (>= 1.3.3, < 2.0)
|
||||
cocoapods-core (1.1.1)
|
||||
activesupport (>= 4.0.2, < 5)
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.1)
|
||||
cocoapods-downloader (1.1.2)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-trunk (1.1.1)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (= 0.7.8)
|
||||
cocoapods-try (1.1.0)
|
||||
colored (1.2)
|
||||
escape (0.0.4)
|
||||
fourflusher (2.0.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.0.2)
|
||||
i18n (0.7.0)
|
||||
json (1.8.3)
|
||||
minitest (5.9.1)
|
||||
molinillo (0.5.4)
|
||||
nanaimo (0.2.2)
|
||||
nap (1.1.0)
|
||||
netrc (0.7.8)
|
||||
thread_safe (0.3.5)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
xcodeproj (1.4.1)
|
||||
CFPropertyList (~> 2.3.3)
|
||||
activesupport (>= 3)
|
||||
claide (>= 1.0.1, < 2.0)
|
||||
colored (~> 1.2)
|
||||
nanaimo (~> 0.2.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods (~> 1.1.0)
|
||||
minitest
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.3
|
||||
13
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Makefile
vendored
Normal file
13
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/Makefile
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
test: install repo_update
|
||||
@set -e; \
|
||||
for test in *_test.rb; do \
|
||||
bundle exec ./$$test; \
|
||||
done
|
||||
|
||||
repo_update:
|
||||
@bundle exec pod repo update --silent
|
||||
|
||||
install:
|
||||
@bundle install --path gems
|
||||
|
||||
.PHONY: test install
|
||||
43
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/integration_test.rb
vendored
Normal file
43
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/integration_test.rb
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'minitest/autorun'
|
||||
require_relative 'test_running_validator'
|
||||
|
||||
class IntegrationTest < Minitest::Test
|
||||
|
||||
def test_validate_project
|
||||
assert validator.validate, "validation failed: #{validator.failure_reason}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validator
|
||||
@validator ||= TestRunningValidator.new(podspec, []).tap do |validator|
|
||||
validator.test_files = Dir["#{project_test_dir}/**/*.swift"]
|
||||
validator.test_resources = Dir["#{project_test_dir}/fixtures"]
|
||||
validator.config.verbose = true
|
||||
validator.no_clean = true
|
||||
validator.use_frameworks = true
|
||||
validator.fail_fast = true
|
||||
validator.local = true
|
||||
validator.allow_warnings = true
|
||||
subspec = ENV['VALIDATOR_SUBSPEC']
|
||||
if subspec == 'none'
|
||||
validator.no_subspecs = true
|
||||
else
|
||||
validator.only_subspec = subspec
|
||||
end
|
||||
if ENV['IOS_SIMULATOR']
|
||||
validator.ios_simulator = ENV['IOS_SIMULATOR']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def podspec
|
||||
File.expand_path(File.dirname(__FILE__) + '/../../SQLite.swift.podspec')
|
||||
end
|
||||
|
||||
def project_test_dir
|
||||
File.expand_path(File.dirname(__FILE__) + '/../SQLiteTests')
|
||||
end
|
||||
end
|
||||
120
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/test_running_validator.rb
vendored
Normal file
120
mobile/ios/ThirdParty/SQLite.swift/Tests/CocoaPods/test_running_validator.rb
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
require 'cocoapods'
|
||||
require 'cocoapods/validator'
|
||||
require 'fileutils'
|
||||
|
||||
class TestRunningValidator < Pod::Validator
|
||||
APP_TARGET = 'App'
|
||||
TEST_TARGET = 'Tests'
|
||||
|
||||
attr_accessor :test_files
|
||||
attr_accessor :test_resources
|
||||
attr_accessor :ios_simulator
|
||||
attr_accessor :tvos_simulator
|
||||
attr_accessor :watchos_simulator
|
||||
|
||||
def initialize(spec_or_path, source_urls)
|
||||
super(spec_or_path, source_urls)
|
||||
self.test_files = []
|
||||
self.test_resources = []
|
||||
self.ios_simulator = :oldest
|
||||
self.tvos_simulator = :oldest
|
||||
self.watchos_simulator = :oldest
|
||||
end
|
||||
|
||||
def create_app_project
|
||||
super
|
||||
project = Xcodeproj::Project.open(validation_dir + "#{APP_TARGET}.xcodeproj")
|
||||
create_test_target(project)
|
||||
project.save
|
||||
end
|
||||
|
||||
def add_app_project_import
|
||||
super
|
||||
project = Xcodeproj::Project.open(validation_dir + 'App.xcodeproj')
|
||||
group = project.new_group(TEST_TARGET)
|
||||
test_target = project.targets.last
|
||||
test_target.add_resources(test_resources.map { |resource| group.new_file(resource) })
|
||||
test_target.add_file_references(test_files.map { |file| group.new_file(file) })
|
||||
add_swift_version(test_target)
|
||||
project.save
|
||||
end
|
||||
|
||||
def install_pod
|
||||
super
|
||||
if local?
|
||||
FileUtils.ln_s file.dirname, validation_dir + "Pods/#{spec.name}"
|
||||
end
|
||||
end
|
||||
|
||||
def podfile_from_spec(*args)
|
||||
super(*args).tap do |pod_file|
|
||||
add_test_target(pod_file)
|
||||
end
|
||||
end
|
||||
|
||||
def build_pod
|
||||
super
|
||||
Pod::UI.message "\Testing with xcodebuild.\n".yellow do
|
||||
run_tests
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def create_test_target(project)
|
||||
test_target = project.new_target(:unit_test_bundle, TEST_TARGET, consumer.platform_name, deployment_target)
|
||||
create_test_scheme(project, test_target)
|
||||
end
|
||||
|
||||
def create_test_scheme(project, test_target)
|
||||
project.recreate_user_schemes
|
||||
test_scheme = Xcodeproj::XCScheme.new(test_scheme_path(project))
|
||||
test_scheme.add_test_target(test_target)
|
||||
test_scheme.save!
|
||||
end
|
||||
|
||||
def test_scheme_path(project)
|
||||
Xcodeproj::XCScheme.user_data_dir(project.path) + "#{TEST_TARGET}.xcscheme"
|
||||
end
|
||||
|
||||
def add_test_target(pod_file)
|
||||
app_target = pod_file.target_definitions[APP_TARGET]
|
||||
Pod::Podfile::TargetDefinition.new(TEST_TARGET, app_target)
|
||||
end
|
||||
|
||||
def run_tests
|
||||
command = [
|
||||
'clean', 'build', 'build-for-testing', 'test-without-building',
|
||||
'-workspace', File.join(validation_dir, "#{APP_TARGET}.xcworkspace"),
|
||||
'-scheme', TEST_TARGET,
|
||||
'-configuration', 'Debug'
|
||||
]
|
||||
case consumer.platform_name
|
||||
when :ios
|
||||
command += %w(CODE_SIGN_IDENTITY=- -sdk iphonesimulator)
|
||||
command += Fourflusher::SimControl.new.destination(ios_simulator, 'iOS', deployment_target)
|
||||
when :osx
|
||||
command += %w(LD_RUNPATH_SEARCH_PATHS=@loader_path/../Frameworks)
|
||||
when :tvos
|
||||
command += %w(CODE_SIGN_IDENTITY=- -sdk appletvsimulator)
|
||||
command += Fourflusher::SimControl.new.destination(tvos_simulator, 'tvOS', deployment_target)
|
||||
when :watchos
|
||||
# there's no XCTest on watchOS (https://openradar.appspot.com/21760513)
|
||||
return
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
output, status = _xcodebuild(command)
|
||||
|
||||
unless status.success?
|
||||
message = 'Returned an unsuccessful exit code.'
|
||||
if config.verbose?
|
||||
message += "\nXcode output: \n#{output}\n"
|
||||
else
|
||||
message += ' You can use `--verbose` for more information.'
|
||||
end
|
||||
error('xcodebuild', message)
|
||||
end
|
||||
output
|
||||
end
|
||||
end
|
||||
68
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/AggregateFunctionsTests.swift
vendored
Normal file
68
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/AggregateFunctionsTests.swift
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class AggregateFunctionsTests : XCTestCase {
|
||||
|
||||
func test_distinct_prependsExpressionsWithDistinctKeyword() {
|
||||
AssertSQL("DISTINCT \"int\"", int.distinct)
|
||||
AssertSQL("DISTINCT \"intOptional\"", intOptional.distinct)
|
||||
AssertSQL("DISTINCT \"double\"", double.distinct)
|
||||
AssertSQL("DISTINCT \"doubleOptional\"", doubleOptional.distinct)
|
||||
AssertSQL("DISTINCT \"string\"", string.distinct)
|
||||
AssertSQL("DISTINCT \"stringOptional\"", stringOptional.distinct)
|
||||
}
|
||||
|
||||
func test_count_wrapsOptionalExpressionsWithCountFunction() {
|
||||
AssertSQL("count(\"intOptional\")", intOptional.count)
|
||||
AssertSQL("count(\"doubleOptional\")", doubleOptional.count)
|
||||
AssertSQL("count(\"stringOptional\")", stringOptional.count)
|
||||
}
|
||||
|
||||
func test_max_wrapsComparableExpressionsWithMaxFunction() {
|
||||
AssertSQL("max(\"int\")", int.max)
|
||||
AssertSQL("max(\"intOptional\")", intOptional.max)
|
||||
AssertSQL("max(\"double\")", double.max)
|
||||
AssertSQL("max(\"doubleOptional\")", doubleOptional.max)
|
||||
AssertSQL("max(\"string\")", string.max)
|
||||
AssertSQL("max(\"stringOptional\")", stringOptional.max)
|
||||
AssertSQL("max(\"date\")", date.max)
|
||||
AssertSQL("max(\"dateOptional\")", dateOptional.max)
|
||||
}
|
||||
|
||||
func test_min_wrapsComparableExpressionsWithMinFunction() {
|
||||
AssertSQL("min(\"int\")", int.min)
|
||||
AssertSQL("min(\"intOptional\")", intOptional.min)
|
||||
AssertSQL("min(\"double\")", double.min)
|
||||
AssertSQL("min(\"doubleOptional\")", doubleOptional.min)
|
||||
AssertSQL("min(\"string\")", string.min)
|
||||
AssertSQL("min(\"stringOptional\")", stringOptional.min)
|
||||
AssertSQL("min(\"date\")", date.min)
|
||||
AssertSQL("min(\"dateOptional\")", dateOptional.min)
|
||||
}
|
||||
|
||||
func test_average_wrapsNumericExpressionsWithAvgFunction() {
|
||||
AssertSQL("avg(\"int\")", int.average)
|
||||
AssertSQL("avg(\"intOptional\")", intOptional.average)
|
||||
AssertSQL("avg(\"double\")", double.average)
|
||||
AssertSQL("avg(\"doubleOptional\")", doubleOptional.average)
|
||||
}
|
||||
|
||||
func test_sum_wrapsNumericExpressionsWithSumFunction() {
|
||||
AssertSQL("sum(\"int\")", int.sum)
|
||||
AssertSQL("sum(\"intOptional\")", intOptional.sum)
|
||||
AssertSQL("sum(\"double\")", double.sum)
|
||||
AssertSQL("sum(\"doubleOptional\")", doubleOptional.sum)
|
||||
}
|
||||
|
||||
func test_total_wrapsNumericExpressionsWithTotalFunction() {
|
||||
AssertSQL("total(\"int\")", int.total)
|
||||
AssertSQL("total(\"intOptional\")", intOptional.total)
|
||||
AssertSQL("total(\"double\")", double.total)
|
||||
AssertSQL("total(\"doubleOptional\")", doubleOptional.total)
|
||||
}
|
||||
|
||||
func test_count_withStar_wrapsStarWithCountFunction() {
|
||||
AssertSQL("count(*)", count(*))
|
||||
}
|
||||
|
||||
}
|
||||
23
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/BlobTests.swift
vendored
Normal file
23
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/BlobTests.swift
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class BlobTests : XCTestCase {
|
||||
|
||||
func test_toHex() {
|
||||
let blob = Blob(bytes: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 250, 255])
|
||||
|
||||
XCTAssertEqual(blob.toHex(), "000a141e28323c46505a6496faff")
|
||||
}
|
||||
|
||||
func test_init_array() {
|
||||
let blob = Blob(bytes: [42, 42, 42])
|
||||
XCTAssertEqual(blob.bytes, [42, 42, 42])
|
||||
}
|
||||
|
||||
func test_init_unsafeRawPointer() {
|
||||
let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: 3)
|
||||
pointer.initialize(to: 42, count: 3)
|
||||
let blob = Blob(bytes: pointer, length: 3)
|
||||
XCTAssertEqual(blob.bytes, [42, 42, 42])
|
||||
}
|
||||
}
|
||||
98
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CipherTests.swift
vendored
Normal file
98
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CipherTests.swift
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#if SQLITE_SWIFT_SQLCIPHER
|
||||
import XCTest
|
||||
import SQLite
|
||||
import SQLCipher
|
||||
|
||||
class CipherTests: XCTestCase {
|
||||
|
||||
let db1 = try! Connection()
|
||||
let db2 = try! Connection()
|
||||
|
||||
override func setUp() {
|
||||
// db
|
||||
|
||||
try! db1.key("hello")
|
||||
|
||||
try! db1.run("CREATE TABLE foo (bar TEXT)")
|
||||
try! db1.run("INSERT INTO foo (bar) VALUES ('world')")
|
||||
|
||||
// db2
|
||||
let key2 = keyData()
|
||||
try! db2.key(Blob(bytes: key2.bytes, length: key2.length))
|
||||
|
||||
try! db2.run("CREATE TABLE foo (bar TEXT)")
|
||||
try! db2.run("INSERT INTO foo (bar) VALUES ('world')")
|
||||
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
func test_key() {
|
||||
XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64)
|
||||
}
|
||||
|
||||
func test_key_blob_literal() {
|
||||
let db = try! Connection()
|
||||
try! db.key("x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'")
|
||||
}
|
||||
|
||||
func test_rekey() {
|
||||
try! db1.rekey("goodbye")
|
||||
XCTAssertEqual(1, try! db1.scalar("SELECT count(*) FROM foo") as? Int64)
|
||||
}
|
||||
|
||||
func test_data_key() {
|
||||
XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64)
|
||||
}
|
||||
|
||||
func test_data_rekey() {
|
||||
let newKey = keyData()
|
||||
try! db2.rekey(Blob(bytes: newKey.bytes, length: newKey.length))
|
||||
XCTAssertEqual(1, try! db2.scalar("SELECT count(*) FROM foo") as? Int64)
|
||||
}
|
||||
|
||||
func test_keyFailure() {
|
||||
let path = "\(NSTemporaryDirectory())/db.sqlite3"
|
||||
_ = try? FileManager.default.removeItem(atPath: path)
|
||||
|
||||
let connA = try! Connection(path)
|
||||
defer { try! FileManager.default.removeItem(atPath: path) }
|
||||
|
||||
try! connA.key("hello")
|
||||
try! connA.run("CREATE TABLE foo (bar TEXT)")
|
||||
|
||||
let connB = try! Connection(path, readonly: true)
|
||||
|
||||
do {
|
||||
try connB.key("world")
|
||||
XCTFail("expected exception")
|
||||
} catch Result.error(_, let code, _) {
|
||||
XCTAssertEqual(SQLITE_NOTADB, code)
|
||||
} catch {
|
||||
XCTFail("unexpected error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func test_open_db_encrypted_with_sqlcipher() {
|
||||
// $ sqlcipher SQLiteTests/fixtures/encrypted.sqlite
|
||||
// sqlite> pragma key = 'sqlcipher-test';
|
||||
// sqlite> CREATE TABLE foo (bar TEXT);
|
||||
// sqlite> INSERT INTO foo (bar) VALUES ('world');
|
||||
let encryptedFile = fixture("encrypted", withExtension: "sqlite")
|
||||
|
||||
try! FileManager.default.setAttributes([FileAttributeKey.immutable : 1], ofItemAtPath: encryptedFile)
|
||||
XCTAssertFalse(FileManager.default.isWritableFile(atPath: encryptedFile))
|
||||
|
||||
let conn = try! Connection(encryptedFile)
|
||||
try! conn.key("sqlcipher-test")
|
||||
XCTAssertEqual(1, try! conn.scalar("SELECT count(*) FROM foo") as? Int64)
|
||||
}
|
||||
|
||||
private func keyData(length: Int = 64) -> NSMutableData {
|
||||
let keyData = NSMutableData(length: length)!
|
||||
let result = SecRandomCopyBytes(kSecRandomDefault, length,
|
||||
keyData.mutableBytes.assumingMemoryBound(to: UInt8.self))
|
||||
XCTAssertEqual(0, result)
|
||||
return keyData
|
||||
}
|
||||
}
|
||||
#endif
|
||||
384
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ConnectionTests.swift
vendored
Normal file
384
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ConnectionTests.swift
vendored
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
import XCTest
|
||||
@testable import SQLite
|
||||
|
||||
#if SQLITE_SWIFT_STANDALONE
|
||||
import sqlite3
|
||||
#elseif SQLITE_SWIFT_SQLCIPHER
|
||||
import SQLCipher
|
||||
#else
|
||||
import SQLite3
|
||||
#endif
|
||||
|
||||
class ConnectionTests : SQLiteTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
CreateUsersTable()
|
||||
}
|
||||
|
||||
func test_init_withInMemory_returnsInMemoryConnection() {
|
||||
let db = try! Connection(.inMemory)
|
||||
XCTAssertEqual("", db.description)
|
||||
}
|
||||
|
||||
func test_init_returnsInMemoryByDefault() {
|
||||
let db = try! Connection()
|
||||
XCTAssertEqual("", db.description)
|
||||
}
|
||||
|
||||
func test_init_withTemporary_returnsTemporaryConnection() {
|
||||
let db = try! Connection(.temporary)
|
||||
XCTAssertEqual("", db.description)
|
||||
}
|
||||
|
||||
func test_init_withURI_returnsURIConnection() {
|
||||
let db = try! Connection(.uri("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3"))
|
||||
XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description)
|
||||
}
|
||||
|
||||
func test_init_withString_returnsURIConnection() {
|
||||
let db = try! Connection("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3")
|
||||
XCTAssertEqual("\(NSTemporaryDirectory())/SQLite.swift Tests.sqlite3", db.description)
|
||||
}
|
||||
|
||||
func test_readonly_returnsFalseOnReadWriteConnections() {
|
||||
XCTAssertFalse(db.readonly)
|
||||
}
|
||||
|
||||
func test_readonly_returnsTrueOnReadOnlyConnections() {
|
||||
let db = try! Connection(readonly: true)
|
||||
XCTAssertTrue(db.readonly)
|
||||
}
|
||||
|
||||
func test_changes_returnsZeroOnNewConnections() {
|
||||
XCTAssertEqual(0, db.changes)
|
||||
}
|
||||
|
||||
func test_lastInsertRowid_returnsLastIdAfterInserts() {
|
||||
try! InsertUser("alice")
|
||||
XCTAssertEqual(1, db.lastInsertRowid)
|
||||
}
|
||||
|
||||
func test_lastInsertRowid_doesNotResetAfterError() {
|
||||
XCTAssert(db.lastInsertRowid == 0)
|
||||
try! InsertUser("alice")
|
||||
XCTAssertEqual(1, db.lastInsertRowid)
|
||||
XCTAssertThrowsError(
|
||||
try db.run("INSERT INTO \"users\" (email, age, admin) values ('invalid@example.com', 12, 'invalid')")
|
||||
) { error in
|
||||
if case SQLite.Result.error(_, let code, _) = error {
|
||||
XCTAssertEqual(SQLITE_CONSTRAINT, code)
|
||||
} else {
|
||||
XCTFail("expected error")
|
||||
}
|
||||
}
|
||||
XCTAssertEqual(1, db.lastInsertRowid)
|
||||
}
|
||||
|
||||
func test_changes_returnsNumberOfChanges() {
|
||||
try! InsertUser("alice")
|
||||
XCTAssertEqual(1, db.changes)
|
||||
try! InsertUser("betsy")
|
||||
XCTAssertEqual(1, db.changes)
|
||||
}
|
||||
|
||||
func test_totalChanges_returnsTotalNumberOfChanges() {
|
||||
XCTAssertEqual(0, db.totalChanges)
|
||||
try! InsertUser("alice")
|
||||
XCTAssertEqual(1, db.totalChanges)
|
||||
try! InsertUser("betsy")
|
||||
XCTAssertEqual(2, db.totalChanges)
|
||||
}
|
||||
|
||||
func test_prepare_preparesAndReturnsStatements() {
|
||||
_ = try! db.prepare("SELECT * FROM users WHERE admin = 0")
|
||||
_ = try! db.prepare("SELECT * FROM users WHERE admin = ?", 0)
|
||||
_ = try! db.prepare("SELECT * FROM users WHERE admin = ?", [0])
|
||||
_ = try! db.prepare("SELECT * FROM users WHERE admin = $admin", ["$admin": 0])
|
||||
}
|
||||
|
||||
func test_run_preparesRunsAndReturnsStatements() {
|
||||
try! db.run("SELECT * FROM users WHERE admin = 0")
|
||||
try! db.run("SELECT * FROM users WHERE admin = ?", 0)
|
||||
try! db.run("SELECT * FROM users WHERE admin = ?", [0])
|
||||
try! db.run("SELECT * FROM users WHERE admin = $admin", ["$admin": 0])
|
||||
AssertSQL("SELECT * FROM users WHERE admin = 0", 4)
|
||||
}
|
||||
|
||||
func test_scalar_preparesRunsAndReturnsScalarValues() {
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = 0") as? Int64)
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", 0) as? Int64)
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = ?", [0]) as? Int64)
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users WHERE admin = $admin", ["$admin": 0]) as? Int64)
|
||||
AssertSQL("SELECT count(*) FROM users WHERE admin = 0", 4)
|
||||
}
|
||||
|
||||
func test_execute_comment() {
|
||||
try! db.run("-- this is a comment\nSELECT 1")
|
||||
AssertSQL("-- this is a comment", 0)
|
||||
AssertSQL("SELECT 1", 0)
|
||||
}
|
||||
|
||||
func test_transaction_executesBeginDeferred() {
|
||||
try! db.transaction(.deferred) {}
|
||||
|
||||
AssertSQL("BEGIN DEFERRED TRANSACTION")
|
||||
}
|
||||
|
||||
func test_transaction_executesBeginImmediate() {
|
||||
try! db.transaction(.immediate) {}
|
||||
|
||||
AssertSQL("BEGIN IMMEDIATE TRANSACTION")
|
||||
}
|
||||
|
||||
func test_transaction_executesBeginExclusive() {
|
||||
try! db.transaction(.exclusive) {}
|
||||
|
||||
AssertSQL("BEGIN EXCLUSIVE TRANSACTION")
|
||||
}
|
||||
|
||||
func test_transaction_beginsAndCommitsTransactions() {
|
||||
let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
|
||||
|
||||
try! db.transaction {
|
||||
try stmt.run()
|
||||
}
|
||||
|
||||
AssertSQL("BEGIN DEFERRED TRANSACTION")
|
||||
AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')")
|
||||
AssertSQL("COMMIT TRANSACTION")
|
||||
AssertSQL("ROLLBACK TRANSACTION", 0)
|
||||
}
|
||||
|
||||
func test_transaction_beginsAndRollsTransactionsBack() {
|
||||
let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
|
||||
|
||||
do {
|
||||
try db.transaction {
|
||||
try stmt.run()
|
||||
try stmt.run()
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
|
||||
AssertSQL("BEGIN DEFERRED TRANSACTION")
|
||||
AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2)
|
||||
AssertSQL("ROLLBACK TRANSACTION")
|
||||
AssertSQL("COMMIT TRANSACTION", 0)
|
||||
}
|
||||
|
||||
func test_savepoint_beginsAndCommitsSavepoints() {
|
||||
let db = self.db
|
||||
|
||||
try! db.savepoint("1") {
|
||||
try db.savepoint("2") {
|
||||
try db.run("INSERT INTO users (email) VALUES (?)", "alice@example.com")
|
||||
}
|
||||
}
|
||||
|
||||
AssertSQL("SAVEPOINT '1'")
|
||||
AssertSQL("SAVEPOINT '2'")
|
||||
AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')")
|
||||
AssertSQL("RELEASE SAVEPOINT '2'")
|
||||
AssertSQL("RELEASE SAVEPOINT '1'")
|
||||
AssertSQL("ROLLBACK TO SAVEPOINT '2'", 0)
|
||||
AssertSQL("ROLLBACK TO SAVEPOINT '1'", 0)
|
||||
}
|
||||
|
||||
func test_savepoint_beginsAndRollsSavepointsBack() {
|
||||
let db = self.db
|
||||
let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
|
||||
|
||||
do {
|
||||
try db.savepoint("1") {
|
||||
try db.savepoint("2") {
|
||||
try stmt.run()
|
||||
try stmt.run()
|
||||
try stmt.run()
|
||||
}
|
||||
try db.savepoint("2") {
|
||||
try stmt.run()
|
||||
try stmt.run()
|
||||
try stmt.run()
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
|
||||
AssertSQL("SAVEPOINT '1'")
|
||||
AssertSQL("SAVEPOINT '2'")
|
||||
AssertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2)
|
||||
AssertSQL("ROLLBACK TO SAVEPOINT '2'")
|
||||
AssertSQL("ROLLBACK TO SAVEPOINT '1'")
|
||||
AssertSQL("RELEASE SAVEPOINT '2'", 0)
|
||||
AssertSQL("RELEASE SAVEPOINT '1'", 0)
|
||||
}
|
||||
|
||||
func test_updateHook_setsUpdateHook_withInsert() {
|
||||
async { done in
|
||||
db.updateHook { operation, db, table, rowid in
|
||||
XCTAssertEqual(Connection.Operation.insert, operation)
|
||||
XCTAssertEqual("main", db)
|
||||
XCTAssertEqual("users", table)
|
||||
XCTAssertEqual(1, rowid)
|
||||
done()
|
||||
}
|
||||
try! InsertUser("alice")
|
||||
}
|
||||
}
|
||||
|
||||
func test_updateHook_setsUpdateHook_withUpdate() {
|
||||
try! InsertUser("alice")
|
||||
async { done in
|
||||
db.updateHook { operation, db, table, rowid in
|
||||
XCTAssertEqual(Connection.Operation.update, operation)
|
||||
XCTAssertEqual("main", db)
|
||||
XCTAssertEqual("users", table)
|
||||
XCTAssertEqual(1, rowid)
|
||||
done()
|
||||
}
|
||||
try! db.run("UPDATE users SET email = 'alice@example.com'")
|
||||
}
|
||||
}
|
||||
|
||||
func test_updateHook_setsUpdateHook_withDelete() {
|
||||
try! InsertUser("alice")
|
||||
async { done in
|
||||
db.updateHook { operation, db, table, rowid in
|
||||
XCTAssertEqual(Connection.Operation.delete, operation)
|
||||
XCTAssertEqual("main", db)
|
||||
XCTAssertEqual("users", table)
|
||||
XCTAssertEqual(1, rowid)
|
||||
done()
|
||||
}
|
||||
try! db.run("DELETE FROM users WHERE id = 1")
|
||||
}
|
||||
}
|
||||
|
||||
func test_commitHook_setsCommitHook() {
|
||||
async { done in
|
||||
db.commitHook {
|
||||
done()
|
||||
}
|
||||
try! db.transaction {
|
||||
try self.InsertUser("alice")
|
||||
}
|
||||
XCTAssertEqual(1, try! db.scalar("SELECT count(*) FROM users") as? Int64)
|
||||
}
|
||||
}
|
||||
|
||||
func test_rollbackHook_setsRollbackHook() {
|
||||
async { done in
|
||||
db.rollbackHook(done)
|
||||
do {
|
||||
try db.transaction {
|
||||
try self.InsertUser("alice")
|
||||
try self.InsertUser("alice") // throw
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64)
|
||||
}
|
||||
}
|
||||
|
||||
func test_commitHook_withRollback_rollsBack() {
|
||||
async { done in
|
||||
db.commitHook {
|
||||
throw NSError(domain: "com.stephencelis.SQLiteTests", code: 1, userInfo: nil)
|
||||
}
|
||||
db.rollbackHook(done)
|
||||
do {
|
||||
try db.transaction {
|
||||
try self.InsertUser("alice")
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
XCTAssertEqual(0, try! db.scalar("SELECT count(*) FROM users") as? Int64)
|
||||
}
|
||||
}
|
||||
|
||||
func test_createFunction_withArrayArguments() {
|
||||
db.createFunction("hello") { $0[0].map { "Hello, \($0)!" } }
|
||||
|
||||
XCTAssertEqual("Hello, world!", try! db.scalar("SELECT hello('world')") as? String)
|
||||
XCTAssert(try! db.scalar("SELECT hello(NULL)") == nil)
|
||||
}
|
||||
|
||||
func test_createFunction_createsQuotableFunction() {
|
||||
db.createFunction("hello world") { $0[0].map { "Hello, \($0)!" } }
|
||||
|
||||
XCTAssertEqual("Hello, world!", try! db.scalar("SELECT \"hello world\"('world')") as? String)
|
||||
XCTAssert(try! db.scalar("SELECT \"hello world\"(NULL)") == nil)
|
||||
}
|
||||
|
||||
func test_createCollation_createsCollation() {
|
||||
try! db.createCollation("NODIACRITIC") { lhs, rhs in
|
||||
return lhs.compare(rhs, options: .diacriticInsensitive)
|
||||
}
|
||||
XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE NODIACRITIC", "cafe", "café") as? Int64)
|
||||
}
|
||||
|
||||
func test_createCollation_createsQuotableCollation() {
|
||||
try! db.createCollation("NO DIACRITIC") { lhs, rhs in
|
||||
return lhs.compare(rhs, options: .diacriticInsensitive)
|
||||
}
|
||||
XCTAssertEqual(1, try! db.scalar("SELECT ? = ? COLLATE \"NO DIACRITIC\"", "cafe", "café") as? Int64)
|
||||
}
|
||||
|
||||
func test_interrupt_interruptsLongRunningQuery() {
|
||||
try! InsertUsers("abcdefghijklmnopqrstuvwxyz".characters.map { String($0) })
|
||||
db.createFunction("sleep") { args in
|
||||
usleep(UInt32((args[0] as? Double ?? Double(args[0] as? Int64 ?? 1)) * 1_000_000))
|
||||
return nil
|
||||
}
|
||||
|
||||
let stmt = try! db.prepare("SELECT *, sleep(?) FROM users", 0.1)
|
||||
try! stmt.run()
|
||||
|
||||
let deadline = DispatchTime.now() + Double(Int64(10 * NSEC_PER_MSEC)) / Double(NSEC_PER_SEC)
|
||||
_ = DispatchQueue.global(priority: .background).asyncAfter(deadline: deadline, execute: db.interrupt)
|
||||
AssertThrows(try stmt.run())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ResultTests : XCTestCase {
|
||||
let connection = try! Connection(.inMemory)
|
||||
|
||||
func test_init_with_ok_code_returns_nil() {
|
||||
XCTAssertNil(Result(errorCode: SQLITE_OK, connection: connection, statement: nil) as Result?)
|
||||
}
|
||||
|
||||
func test_init_with_row_code_returns_nil() {
|
||||
XCTAssertNil(Result(errorCode: SQLITE_ROW, connection: connection, statement: nil) as Result?)
|
||||
}
|
||||
|
||||
func test_init_with_done_code_returns_nil() {
|
||||
XCTAssertNil(Result(errorCode: SQLITE_DONE, connection: connection, statement: nil) as Result?)
|
||||
}
|
||||
|
||||
func test_init_with_other_code_returns_error() {
|
||||
if case .some(.error(let message, let code, let statement)) =
|
||||
Result(errorCode: SQLITE_MISUSE, connection: connection, statement: nil) {
|
||||
XCTAssertEqual("not an error", message)
|
||||
XCTAssertEqual(SQLITE_MISUSE, code)
|
||||
XCTAssertNil(statement)
|
||||
XCTAssert(self.connection === connection)
|
||||
} else {
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
|
||||
func test_description_contains_error_code() {
|
||||
XCTAssertEqual("not an error (code: 21)",
|
||||
Result(errorCode: SQLITE_MISUSE, connection: connection, statement: nil)?.description)
|
||||
}
|
||||
|
||||
func test_description_contains_statement_and_error_code() {
|
||||
let statement = try! Statement(connection, "SELECT 1")
|
||||
XCTAssertEqual("not an error (SELECT 1) (code: 21)",
|
||||
Result(errorCode: SQLITE_MISUSE, connection: connection, statement: statement)?.description)
|
||||
}
|
||||
}
|
||||
136
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CoreFunctionsTests.swift
vendored
Normal file
136
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CoreFunctionsTests.swift
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class CoreFunctionsTests : XCTestCase {
|
||||
|
||||
func test_round_wrapsDoubleExpressionsWithRoundFunction() {
|
||||
AssertSQL("round(\"double\")", double.round())
|
||||
AssertSQL("round(\"doubleOptional\")", doubleOptional.round())
|
||||
|
||||
AssertSQL("round(\"double\", 1)", double.round(1))
|
||||
AssertSQL("round(\"doubleOptional\", 2)", doubleOptional.round(2))
|
||||
}
|
||||
|
||||
func test_random_generatesExpressionWithRandomFunction() {
|
||||
AssertSQL("random()", Expression<Int64>.random())
|
||||
AssertSQL("random()", Expression<Int>.random())
|
||||
}
|
||||
|
||||
func test_length_wrapsStringExpressionWithLengthFunction() {
|
||||
AssertSQL("length(\"string\")", string.length)
|
||||
AssertSQL("length(\"stringOptional\")", stringOptional.length)
|
||||
}
|
||||
|
||||
func test_lowercaseString_wrapsStringExpressionWithLowerFunction() {
|
||||
AssertSQL("lower(\"string\")", string.lowercaseString)
|
||||
AssertSQL("lower(\"stringOptional\")", stringOptional.lowercaseString)
|
||||
}
|
||||
|
||||
func test_uppercaseString_wrapsStringExpressionWithUpperFunction() {
|
||||
AssertSQL("upper(\"string\")", string.uppercaseString)
|
||||
AssertSQL("upper(\"stringOptional\")", stringOptional.uppercaseString)
|
||||
}
|
||||
|
||||
func test_like_buildsExpressionWithLikeOperator() {
|
||||
AssertSQL("(\"string\" LIKE 'a%')", string.like("a%"))
|
||||
AssertSQL("(\"stringOptional\" LIKE 'b%')", stringOptional.like("b%"))
|
||||
|
||||
AssertSQL("(\"string\" LIKE '%\\%' ESCAPE '\\')", string.like("%\\%", escape: "\\"))
|
||||
AssertSQL("(\"stringOptional\" LIKE '_\\_' ESCAPE '\\')", stringOptional.like("_\\_", escape: "\\"))
|
||||
}
|
||||
|
||||
func test_glob_buildsExpressionWithGlobOperator() {
|
||||
AssertSQL("(\"string\" GLOB 'a*')", string.glob("a*"))
|
||||
AssertSQL("(\"stringOptional\" GLOB 'b*')", stringOptional.glob("b*"))
|
||||
}
|
||||
|
||||
func test_match_buildsExpressionWithMatchOperator() {
|
||||
AssertSQL("(\"string\" MATCH 'a*')", string.match("a*"))
|
||||
AssertSQL("(\"stringOptional\" MATCH 'b*')", stringOptional.match("b*"))
|
||||
}
|
||||
|
||||
func test_regexp_buildsExpressionWithRegexpOperator() {
|
||||
AssertSQL("(\"string\" REGEXP '^.+@.+\\.com$')", string.regexp("^.+@.+\\.com$"))
|
||||
AssertSQL("(\"stringOptional\" REGEXP '^.+@.+\\.net$')", stringOptional.regexp("^.+@.+\\.net$"))
|
||||
}
|
||||
|
||||
func test_collate_buildsExpressionWithCollateOperator() {
|
||||
AssertSQL("(\"string\" COLLATE BINARY)", string.collate(.binary))
|
||||
AssertSQL("(\"string\" COLLATE NOCASE)", string.collate(.nocase))
|
||||
AssertSQL("(\"string\" COLLATE RTRIM)", string.collate(.rtrim))
|
||||
AssertSQL("(\"string\" COLLATE \"CUSTOM\")", string.collate(.custom("CUSTOM")))
|
||||
|
||||
AssertSQL("(\"stringOptional\" COLLATE BINARY)", stringOptional.collate(.binary))
|
||||
AssertSQL("(\"stringOptional\" COLLATE NOCASE)", stringOptional.collate(.nocase))
|
||||
AssertSQL("(\"stringOptional\" COLLATE RTRIM)", stringOptional.collate(.rtrim))
|
||||
AssertSQL("(\"stringOptional\" COLLATE \"CUSTOM\")", stringOptional.collate(.custom("CUSTOM")))
|
||||
}
|
||||
|
||||
func test_ltrim_wrapsStringWithLtrimFunction() {
|
||||
AssertSQL("ltrim(\"string\")", string.ltrim())
|
||||
AssertSQL("ltrim(\"stringOptional\")", stringOptional.ltrim())
|
||||
|
||||
AssertSQL("ltrim(\"string\", ' ')", string.ltrim([" "]))
|
||||
AssertSQL("ltrim(\"stringOptional\", ' ')", stringOptional.ltrim([" "]))
|
||||
}
|
||||
|
||||
func test_ltrim_wrapsStringWithRtrimFunction() {
|
||||
AssertSQL("rtrim(\"string\")", string.rtrim())
|
||||
AssertSQL("rtrim(\"stringOptional\")", stringOptional.rtrim())
|
||||
|
||||
AssertSQL("rtrim(\"string\", ' ')", string.rtrim([" "]))
|
||||
AssertSQL("rtrim(\"stringOptional\", ' ')", stringOptional.rtrim([" "]))
|
||||
}
|
||||
|
||||
func test_ltrim_wrapsStringWithTrimFunction() {
|
||||
AssertSQL("trim(\"string\")", string.trim())
|
||||
AssertSQL("trim(\"stringOptional\")", stringOptional.trim())
|
||||
|
||||
AssertSQL("trim(\"string\", ' ')", string.trim([" "]))
|
||||
AssertSQL("trim(\"stringOptional\", ' ')", stringOptional.trim([" "]))
|
||||
}
|
||||
|
||||
func test_replace_wrapsStringWithReplaceFunction() {
|
||||
AssertSQL("replace(\"string\", '@example.com', '@example.net')", string.replace("@example.com", with: "@example.net"))
|
||||
AssertSQL("replace(\"stringOptional\", '@example.net', '@example.com')", stringOptional.replace("@example.net", with: "@example.com"))
|
||||
}
|
||||
|
||||
func test_substring_wrapsStringWithSubstrFunction() {
|
||||
AssertSQL("substr(\"string\", 1, 2)", string.substring(1, length: 2))
|
||||
AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional.substring(2, length: 1))
|
||||
}
|
||||
|
||||
func test_subscriptWithRange_wrapsStringWithSubstrFunction() {
|
||||
AssertSQL("substr(\"string\", 1, 2)", string[1..<3])
|
||||
AssertSQL("substr(\"stringOptional\", 2, 1)", stringOptional[2..<3])
|
||||
}
|
||||
|
||||
func test_nilCoalescingOperator_wrapsOptionalsWithIfnullFunction() {
|
||||
AssertSQL("ifnull(\"intOptional\", 1)", intOptional ?? 1)
|
||||
// AssertSQL("ifnull(\"doubleOptional\", 1.0)", doubleOptional ?? 1) // rdar://problem/21677256
|
||||
XCTAssertEqual("ifnull(\"doubleOptional\", 1.0)", (doubleOptional ?? 1).asSQL())
|
||||
AssertSQL("ifnull(\"stringOptional\", 'literal')", stringOptional ?? "literal")
|
||||
|
||||
AssertSQL("ifnull(\"intOptional\", \"int\")", intOptional ?? int)
|
||||
AssertSQL("ifnull(\"doubleOptional\", \"double\")", doubleOptional ?? double)
|
||||
AssertSQL("ifnull(\"stringOptional\", \"string\")", stringOptional ?? string)
|
||||
|
||||
AssertSQL("ifnull(\"intOptional\", \"intOptional\")", intOptional ?? intOptional)
|
||||
AssertSQL("ifnull(\"doubleOptional\", \"doubleOptional\")", doubleOptional ?? doubleOptional)
|
||||
AssertSQL("ifnull(\"stringOptional\", \"stringOptional\")", stringOptional ?? stringOptional)
|
||||
}
|
||||
|
||||
func test_absoluteValue_wrapsNumberWithAbsFucntion() {
|
||||
AssertSQL("abs(\"int\")", int.absoluteValue)
|
||||
AssertSQL("abs(\"intOptional\")", intOptional.absoluteValue)
|
||||
|
||||
AssertSQL("abs(\"double\")", double.absoluteValue)
|
||||
AssertSQL("abs(\"doubleOptional\")", doubleOptional.absoluteValue)
|
||||
}
|
||||
|
||||
func test_contains_buildsExpressionWithInOperator() {
|
||||
AssertSQL("(\"string\" IN ('hello', 'world'))", ["hello", "world"].contains(string))
|
||||
AssertSQL("(\"stringOptional\" IN ('hello', 'world'))", ["hello", "world"].contains(stringOptional))
|
||||
}
|
||||
|
||||
}
|
||||
6
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CustomFunctionsTests.swift
vendored
Normal file
6
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/CustomFunctionsTests.swift
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class CustomFunctionsTests : XCTestCase {
|
||||
|
||||
}
|
||||
6
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ExpressionTests.swift
vendored
Normal file
6
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/ExpressionTests.swift
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class ExpressionTests : XCTestCase {
|
||||
|
||||
}
|
||||
208
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS4Tests.swift
vendored
Normal file
208
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS4Tests.swift
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class FTS4Tests : XCTestCase {
|
||||
|
||||
func test_create_onVirtualTable_withFTS4_compilesCreateVirtualTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()",
|
||||
virtualTable.create(.FTS4())
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")",
|
||||
virtualTable.create(.FTS4(string))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)",
|
||||
virtualTable.create(.FTS4(tokenize: .Simple))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", tokenize=porter)",
|
||||
virtualTable.create(.FTS4([string], tokenize: .Porter))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=0\")",
|
||||
virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: false)))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")",
|
||||
virtualTable.create(.FTS4(tokenize: .Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"])))
|
||||
)
|
||||
}
|
||||
|
||||
func test_match_onVirtualTableAsExpression_compilesMatchExpression() {
|
||||
AssertSQL("(\"virtual_table\" MATCH 'string')", virtualTable.match("string") as Expression<Bool>)
|
||||
AssertSQL("(\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as Expression<Bool>)
|
||||
AssertSQL("(\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as Expression<Bool?>)
|
||||
}
|
||||
|
||||
func test_match_onVirtualTableAsQueryType_compilesMatchExpression() {
|
||||
AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH 'string')", virtualTable.match("string") as QueryType)
|
||||
AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"string\")", virtualTable.match(string) as QueryType)
|
||||
AssertSQL("SELECT * FROM \"virtual_table\" WHERE (\"virtual_table\" MATCH \"stringOptional\")", virtualTable.match(stringOptional) as QueryType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FTS4ConfigTests : XCTestCase {
|
||||
var config: FTS4Config!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
config = FTS4Config()
|
||||
}
|
||||
|
||||
func test_empty_config() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4()",
|
||||
sql(config))
|
||||
}
|
||||
|
||||
func test_config_column() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\")",
|
||||
sql(config.column(string)))
|
||||
}
|
||||
|
||||
func test_config_columns() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", \"int\")",
|
||||
sql(config.columns([string, int])))
|
||||
}
|
||||
|
||||
func test_config_unindexed_column() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"string\", notindexed=\"string\")",
|
||||
sql(config.column(string, [.unindexed])))
|
||||
}
|
||||
|
||||
func test_external_content_view() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"view\")",
|
||||
sql(config.externalContent(_view )))
|
||||
}
|
||||
|
||||
func test_external_content_virtual_table() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"virtual_table\")",
|
||||
sql(config.externalContent(virtualTable)))
|
||||
}
|
||||
|
||||
func test_tokenizer_simple() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=simple)",
|
||||
sql(config.tokenizer(.Simple)))
|
||||
}
|
||||
|
||||
func test_tokenizer_porter() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=porter)",
|
||||
sql(config.tokenizer(.Porter)))
|
||||
}
|
||||
|
||||
func test_tokenizer_unicode61() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61)",
|
||||
sql(config.tokenizer(.Unicode61())))
|
||||
}
|
||||
|
||||
func test_tokenizer_unicode61_with_options() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")",
|
||||
sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"]))))
|
||||
}
|
||||
|
||||
func test_content_less() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(content=\"\")",
|
||||
sql(config.contentless()))
|
||||
}
|
||||
|
||||
func test_config_matchinfo() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(matchinfo=\"fts3\")",
|
||||
sql(config.matchInfo(.fts3)))
|
||||
}
|
||||
|
||||
func test_config_order_asc() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"asc\")",
|
||||
sql(config.order(.asc)))
|
||||
}
|
||||
|
||||
func test_config_order_desc() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(order=\"desc\")",
|
||||
sql(config.order(.desc)))
|
||||
}
|
||||
|
||||
func test_config_compress() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(compress=\"compress_foo\")",
|
||||
sql(config.compress("compress_foo")))
|
||||
}
|
||||
|
||||
func test_config_uncompress() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(uncompress=\"uncompress_foo\")",
|
||||
sql(config.uncompress("uncompress_foo")))
|
||||
}
|
||||
|
||||
func test_config_languageId() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(languageid=\"lid\")",
|
||||
sql(config.languageId("lid")))
|
||||
}
|
||||
|
||||
func test_config_all() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts4(\"int\", \"string\", \"date\", tokenize=porter, prefix=\"2,4\", content=\"table\", notindexed=\"string\", notindexed=\"date\", languageid=\"lid\", matchinfo=\"fts3\", order=\"desc\")",
|
||||
sql(config
|
||||
.tokenizer(.Porter)
|
||||
.column(int)
|
||||
.column(string, [.unindexed])
|
||||
.column(date, [.unindexed])
|
||||
.externalContent(table)
|
||||
.matchInfo(.fts3)
|
||||
.languageId("lid")
|
||||
.order(.desc)
|
||||
.prefix([2, 4]))
|
||||
)
|
||||
}
|
||||
|
||||
func sql(_ config: FTS4Config) -> String {
|
||||
return virtualTable.create(.FTS4(config))
|
||||
}
|
||||
}
|
||||
|
||||
class FTS4IntegrationTests : SQLiteTestCase {
|
||||
#if !SQLITE_SWIFT_STANDALONE && !SQLITE_SWIFT_SQLCIPHER
|
||||
func test_registerTokenizer_registersTokenizer() {
|
||||
let emails = VirtualTable("emails")
|
||||
let subject = Expression<String?>("subject")
|
||||
let body = Expression<String?>("body")
|
||||
|
||||
let locale = CFLocaleCopyCurrent()
|
||||
let tokenizerName = "tokenizer"
|
||||
let tokenizer = CFStringTokenizerCreate(nil, "" as CFString!, CFRangeMake(0, 0), UInt(kCFStringTokenizerUnitWord), locale)
|
||||
try! db.registerTokenizer(tokenizerName) { string in
|
||||
CFStringTokenizerSetString(tokenizer, string as CFString, CFRangeMake(0, CFStringGetLength(string as CFString)))
|
||||
if CFStringTokenizerAdvanceToNextToken(tokenizer).isEmpty {
|
||||
return nil
|
||||
}
|
||||
let range = CFStringTokenizerGetCurrentTokenRange(tokenizer)
|
||||
let input = CFStringCreateWithSubstring(kCFAllocatorDefault, string as CFString, range)!
|
||||
let token = CFStringCreateMutableCopy(nil, range.length, input)!
|
||||
CFStringLowercase(token, locale)
|
||||
CFStringTransform(token, nil, kCFStringTransformStripDiacritics, false)
|
||||
return (token as String, string.range(of: input as String)!)
|
||||
}
|
||||
|
||||
try! db.run(emails.create(.FTS4([subject, body], tokenize: .Custom(tokenizerName))))
|
||||
AssertSQL("CREATE VIRTUAL TABLE \"emails\" USING fts4(\"subject\", \"body\", tokenize=\"SQLite.swift\" \"tokenizer\")")
|
||||
|
||||
try! _ = db.run(emails.insert(subject <- "Aún más cáfe!"))
|
||||
XCTAssertEqual(1, try! db.scalar(emails.filter(emails.match("aun")).count))
|
||||
}
|
||||
#endif
|
||||
}
|
||||
124
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS5Tests.swift
vendored
Normal file
124
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FTS5Tests.swift
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class FTS5Tests: XCTestCase {
|
||||
var config: FTS5Config!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
config = FTS5Config()
|
||||
}
|
||||
|
||||
func test_empty_config() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5()",
|
||||
sql(config))
|
||||
}
|
||||
|
||||
func test_config_column() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\")",
|
||||
sql(config.column(string)))
|
||||
}
|
||||
|
||||
func test_config_columns() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\", \"int\")",
|
||||
sql(config.columns([string, int])))
|
||||
}
|
||||
|
||||
func test_config_unindexed_column() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"string\" UNINDEXED)",
|
||||
sql(config.column(string, [.unindexed])))
|
||||
}
|
||||
|
||||
func test_external_content_table() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"table\")",
|
||||
sql(config.externalContent(table)))
|
||||
}
|
||||
|
||||
func test_external_content_view() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"view\")",
|
||||
sql(config.externalContent(_view)))
|
||||
}
|
||||
|
||||
func test_external_content_virtual_table() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"virtual_table\")",
|
||||
sql(config.externalContent(virtualTable)))
|
||||
}
|
||||
|
||||
func test_content_less() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content=\"\")",
|
||||
sql(config.contentless()))
|
||||
}
|
||||
|
||||
func test_content_rowid() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(content_rowid=\"string\")",
|
||||
sql(config.contentRowId(string)))
|
||||
}
|
||||
|
||||
func test_tokenizer_porter() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=porter)",
|
||||
sql(config.tokenizer(.Porter)))
|
||||
}
|
||||
|
||||
func test_tokenizer_unicode61() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61)",
|
||||
sql(config.tokenizer(.Unicode61())))
|
||||
}
|
||||
|
||||
func test_tokenizer_unicode61_with_options() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(tokenize=unicode61 \"removeDiacritics=1\" \"tokenchars=.\" \"separators=X\")",
|
||||
sql(config.tokenizer(.Unicode61(removeDiacritics: true, tokenchars: ["."], separators: ["X"]))))
|
||||
}
|
||||
|
||||
func test_column_size() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(columnsize=1)",
|
||||
sql(config.columnSize(1)))
|
||||
}
|
||||
|
||||
func test_detail_full() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"full\")",
|
||||
sql(config.detail(.full)))
|
||||
}
|
||||
|
||||
func test_detail_column() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"column\")",
|
||||
sql(config.detail(.column)))
|
||||
}
|
||||
|
||||
func test_detail_none() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(detail=\"none\")",
|
||||
sql(config.detail(.none)))
|
||||
}
|
||||
|
||||
func test_fts5_config_all() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING fts5(\"int\", \"string\" UNINDEXED, \"date\" UNINDEXED, tokenize=porter, prefix=\"2,4\", content=\"table\")",
|
||||
sql(config
|
||||
.tokenizer(.Porter)
|
||||
.column(int)
|
||||
.column(string, [.unindexed])
|
||||
.column(date, [.unindexed])
|
||||
.externalContent(table)
|
||||
.prefix([2, 4]))
|
||||
)
|
||||
}
|
||||
|
||||
func sql(_ config: FTS5Config) -> String {
|
||||
return virtualTable.create(.FTS5(config))
|
||||
}
|
||||
}
|
||||
8
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Fixtures.swift
vendored
Normal file
8
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Fixtures.swift
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import Foundation
|
||||
|
||||
func fixture(_ name: String, withExtension: String?) -> String {
|
||||
let testBundle = Bundle(for: SQLiteTestCase.self)
|
||||
return testBundle.url(
|
||||
forResource: URL(string: "fixtures")?.appendingPathComponent(name).path,
|
||||
withExtension: withExtension)!.path
|
||||
}
|
||||
16
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FoundationTests.swift
vendored
Normal file
16
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/FoundationTests.swift
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class FoundationTests : XCTestCase {
|
||||
func testDataFromBlob() {
|
||||
let data = Data(bytes: [1, 2, 3])
|
||||
let blob = data.datatypeValue
|
||||
XCTAssertEqual([1, 2, 3], blob.bytes)
|
||||
}
|
||||
|
||||
func testBlobToData() {
|
||||
let blob = Blob(bytes: [1, 2, 3])
|
||||
let data = Data.fromDatatypeValue(blob)
|
||||
XCTAssertEqual(Data(bytes: [1, 2, 3]), data)
|
||||
}
|
||||
}
|
||||
24
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Info.plist
vendored
Normal file
24
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/Info.plist
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
296
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/OperatorsTests.swift
vendored
Normal file
296
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/OperatorsTests.swift
vendored
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class OperatorsTests : XCTestCase {
|
||||
|
||||
func test_stringExpressionPlusStringExpression_buildsConcatenatingStringExpression() {
|
||||
AssertSQL("(\"string\" || \"string\")", string + string)
|
||||
AssertSQL("(\"string\" || \"stringOptional\")", string + stringOptional)
|
||||
AssertSQL("(\"stringOptional\" || \"string\")", stringOptional + string)
|
||||
AssertSQL("(\"stringOptional\" || \"stringOptional\")", stringOptional + stringOptional)
|
||||
AssertSQL("(\"string\" || 'literal')", string + "literal")
|
||||
AssertSQL("(\"stringOptional\" || 'literal')", stringOptional + "literal")
|
||||
AssertSQL("('literal' || \"string\")", "literal" + string)
|
||||
AssertSQL("('literal' || \"stringOptional\")", "literal" + stringOptional)
|
||||
}
|
||||
|
||||
func test_numberExpression_plusNumberExpression_buildsAdditiveNumberExpression() {
|
||||
AssertSQL("(\"int\" + \"int\")", int + int)
|
||||
AssertSQL("(\"int\" + \"intOptional\")", int + intOptional)
|
||||
AssertSQL("(\"intOptional\" + \"int\")", intOptional + int)
|
||||
AssertSQL("(\"intOptional\" + \"intOptional\")", intOptional + intOptional)
|
||||
AssertSQL("(\"int\" + 1)", int + 1)
|
||||
AssertSQL("(\"intOptional\" + 1)", intOptional + 1)
|
||||
AssertSQL("(1 + \"int\")", 1 + int)
|
||||
AssertSQL("(1 + \"intOptional\")", 1 + intOptional)
|
||||
|
||||
AssertSQL("(\"double\" + \"double\")", double + double)
|
||||
AssertSQL("(\"double\" + \"doubleOptional\")", double + doubleOptional)
|
||||
AssertSQL("(\"doubleOptional\" + \"double\")", doubleOptional + double)
|
||||
AssertSQL("(\"doubleOptional\" + \"doubleOptional\")", doubleOptional + doubleOptional)
|
||||
AssertSQL("(\"double\" + 1.0)", double + 1)
|
||||
AssertSQL("(\"doubleOptional\" + 1.0)", doubleOptional + 1)
|
||||
AssertSQL("(1.0 + \"double\")", 1 + double)
|
||||
AssertSQL("(1.0 + \"doubleOptional\")", 1 + doubleOptional)
|
||||
}
|
||||
|
||||
func test_numberExpression_minusNumberExpression_buildsSubtractiveNumberExpression() {
|
||||
AssertSQL("(\"int\" - \"int\")", int - int)
|
||||
AssertSQL("(\"int\" - \"intOptional\")", int - intOptional)
|
||||
AssertSQL("(\"intOptional\" - \"int\")", intOptional - int)
|
||||
AssertSQL("(\"intOptional\" - \"intOptional\")", intOptional - intOptional)
|
||||
AssertSQL("(\"int\" - 1)", int - 1)
|
||||
AssertSQL("(\"intOptional\" - 1)", intOptional - 1)
|
||||
AssertSQL("(1 - \"int\")", 1 - int)
|
||||
AssertSQL("(1 - \"intOptional\")", 1 - intOptional)
|
||||
|
||||
AssertSQL("(\"double\" - \"double\")", double - double)
|
||||
AssertSQL("(\"double\" - \"doubleOptional\")", double - doubleOptional)
|
||||
AssertSQL("(\"doubleOptional\" - \"double\")", doubleOptional - double)
|
||||
AssertSQL("(\"doubleOptional\" - \"doubleOptional\")", doubleOptional - doubleOptional)
|
||||
AssertSQL("(\"double\" - 1.0)", double - 1)
|
||||
AssertSQL("(\"doubleOptional\" - 1.0)", doubleOptional - 1)
|
||||
AssertSQL("(1.0 - \"double\")", 1 - double)
|
||||
AssertSQL("(1.0 - \"doubleOptional\")", 1 - doubleOptional)
|
||||
}
|
||||
|
||||
func test_numberExpression_timesNumberExpression_buildsMultiplicativeNumberExpression() {
|
||||
AssertSQL("(\"int\" * \"int\")", int * int)
|
||||
AssertSQL("(\"int\" * \"intOptional\")", int * intOptional)
|
||||
AssertSQL("(\"intOptional\" * \"int\")", intOptional * int)
|
||||
AssertSQL("(\"intOptional\" * \"intOptional\")", intOptional * intOptional)
|
||||
AssertSQL("(\"int\" * 1)", int * 1)
|
||||
AssertSQL("(\"intOptional\" * 1)", intOptional * 1)
|
||||
AssertSQL("(1 * \"int\")", 1 * int)
|
||||
AssertSQL("(1 * \"intOptional\")", 1 * intOptional)
|
||||
|
||||
AssertSQL("(\"double\" * \"double\")", double * double)
|
||||
AssertSQL("(\"double\" * \"doubleOptional\")", double * doubleOptional)
|
||||
AssertSQL("(\"doubleOptional\" * \"double\")", doubleOptional * double)
|
||||
AssertSQL("(\"doubleOptional\" * \"doubleOptional\")", doubleOptional * doubleOptional)
|
||||
AssertSQL("(\"double\" * 1.0)", double * 1)
|
||||
AssertSQL("(\"doubleOptional\" * 1.0)", doubleOptional * 1)
|
||||
AssertSQL("(1.0 * \"double\")", 1 * double)
|
||||
AssertSQL("(1.0 * \"doubleOptional\")", 1 * doubleOptional)
|
||||
}
|
||||
|
||||
func test_numberExpression_dividedByNumberExpression_buildsDivisiveNumberExpression() {
|
||||
AssertSQL("(\"int\" / \"int\")", int / int)
|
||||
AssertSQL("(\"int\" / \"intOptional\")", int / intOptional)
|
||||
AssertSQL("(\"intOptional\" / \"int\")", intOptional / int)
|
||||
AssertSQL("(\"intOptional\" / \"intOptional\")", intOptional / intOptional)
|
||||
AssertSQL("(\"int\" / 1)", int / 1)
|
||||
AssertSQL("(\"intOptional\" / 1)", intOptional / 1)
|
||||
AssertSQL("(1 / \"int\")", 1 / int)
|
||||
AssertSQL("(1 / \"intOptional\")", 1 / intOptional)
|
||||
|
||||
AssertSQL("(\"double\" / \"double\")", double / double)
|
||||
AssertSQL("(\"double\" / \"doubleOptional\")", double / doubleOptional)
|
||||
AssertSQL("(\"doubleOptional\" / \"double\")", doubleOptional / double)
|
||||
AssertSQL("(\"doubleOptional\" / \"doubleOptional\")", doubleOptional / doubleOptional)
|
||||
AssertSQL("(\"double\" / 1.0)", double / 1)
|
||||
AssertSQL("(\"doubleOptional\" / 1.0)", doubleOptional / 1)
|
||||
AssertSQL("(1.0 / \"double\")", 1 / double)
|
||||
AssertSQL("(1.0 / \"doubleOptional\")", 1 / doubleOptional)
|
||||
}
|
||||
|
||||
func test_numberExpression_prefixedWithMinus_buildsInvertedNumberExpression() {
|
||||
AssertSQL("-(\"int\")", -int)
|
||||
AssertSQL("-(\"intOptional\")", -intOptional)
|
||||
|
||||
AssertSQL("-(\"double\")", -double)
|
||||
AssertSQL("-(\"doubleOptional\")", -doubleOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_moduloIntegerExpression_buildsModuloIntegerExpression() {
|
||||
AssertSQL("(\"int\" % \"int\")", int % int)
|
||||
AssertSQL("(\"int\" % \"intOptional\")", int % intOptional)
|
||||
AssertSQL("(\"intOptional\" % \"int\")", intOptional % int)
|
||||
AssertSQL("(\"intOptional\" % \"intOptional\")", intOptional % intOptional)
|
||||
AssertSQL("(\"int\" % 1)", int % 1)
|
||||
AssertSQL("(\"intOptional\" % 1)", intOptional % 1)
|
||||
AssertSQL("(1 % \"int\")", 1 % int)
|
||||
AssertSQL("(1 % \"intOptional\")", 1 % intOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_bitShiftLeftIntegerExpression_buildsLeftShiftedIntegerExpression() {
|
||||
AssertSQL("(\"int\" << \"int\")", int << int)
|
||||
AssertSQL("(\"int\" << \"intOptional\")", int << intOptional)
|
||||
AssertSQL("(\"intOptional\" << \"int\")", intOptional << int)
|
||||
AssertSQL("(\"intOptional\" << \"intOptional\")", intOptional << intOptional)
|
||||
AssertSQL("(\"int\" << 1)", int << 1)
|
||||
AssertSQL("(\"intOptional\" << 1)", intOptional << 1)
|
||||
AssertSQL("(1 << \"int\")", 1 << int)
|
||||
AssertSQL("(1 << \"intOptional\")", 1 << intOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_bitShiftRightIntegerExpression_buildsRightShiftedIntegerExpression() {
|
||||
AssertSQL("(\"int\" >> \"int\")", int >> int)
|
||||
AssertSQL("(\"int\" >> \"intOptional\")", int >> intOptional)
|
||||
AssertSQL("(\"intOptional\" >> \"int\")", intOptional >> int)
|
||||
AssertSQL("(\"intOptional\" >> \"intOptional\")", intOptional >> intOptional)
|
||||
AssertSQL("(\"int\" >> 1)", int >> 1)
|
||||
AssertSQL("(\"intOptional\" >> 1)", intOptional >> 1)
|
||||
AssertSQL("(1 >> \"int\")", 1 >> int)
|
||||
AssertSQL("(1 >> \"intOptional\")", 1 >> intOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_bitwiseAndIntegerExpression_buildsAndedIntegerExpression() {
|
||||
AssertSQL("(\"int\" & \"int\")", int & int)
|
||||
AssertSQL("(\"int\" & \"intOptional\")", int & intOptional)
|
||||
AssertSQL("(\"intOptional\" & \"int\")", intOptional & int)
|
||||
AssertSQL("(\"intOptional\" & \"intOptional\")", intOptional & intOptional)
|
||||
AssertSQL("(\"int\" & 1)", int & 1)
|
||||
AssertSQL("(\"intOptional\" & 1)", intOptional & 1)
|
||||
AssertSQL("(1 & \"int\")", 1 & int)
|
||||
AssertSQL("(1 & \"intOptional\")", 1 & intOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_bitwiseOrIntegerExpression_buildsOredIntegerExpression() {
|
||||
AssertSQL("(\"int\" | \"int\")", int | int)
|
||||
AssertSQL("(\"int\" | \"intOptional\")", int | intOptional)
|
||||
AssertSQL("(\"intOptional\" | \"int\")", intOptional | int)
|
||||
AssertSQL("(\"intOptional\" | \"intOptional\")", intOptional | intOptional)
|
||||
AssertSQL("(\"int\" | 1)", int | 1)
|
||||
AssertSQL("(\"intOptional\" | 1)", intOptional | 1)
|
||||
AssertSQL("(1 | \"int\")", 1 | int)
|
||||
AssertSQL("(1 | \"intOptional\")", 1 | intOptional)
|
||||
}
|
||||
|
||||
func test_integerExpression_bitwiseExclusiveOrIntegerExpression_buildsOredIntegerExpression() {
|
||||
AssertSQL("(~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^ int)
|
||||
AssertSQL("(~((\"int\" & \"intOptional\")) & (\"int\" | \"intOptional\"))", int ^ intOptional)
|
||||
AssertSQL("(~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^ int)
|
||||
AssertSQL("(~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^ intOptional)
|
||||
AssertSQL("(~((\"int\" & 1)) & (\"int\" | 1))", int ^ 1)
|
||||
AssertSQL("(~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^ 1)
|
||||
AssertSQL("(~((1 & \"int\")) & (1 | \"int\"))", 1 ^ int)
|
||||
AssertSQL("(~((1 & \"intOptional\")) & (1 | \"intOptional\"))", 1 ^ intOptional)
|
||||
}
|
||||
|
||||
func test_bitwiseNot_integerExpression_buildsComplementIntegerExpression() {
|
||||
AssertSQL("~(\"int\")", ~int)
|
||||
AssertSQL("~(\"intOptional\")", ~intOptional)
|
||||
}
|
||||
|
||||
func test_equalityOperator_withEquatableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" = \"bool\")", bool == bool)
|
||||
AssertSQL("(\"bool\" = \"boolOptional\")", bool == boolOptional)
|
||||
AssertSQL("(\"boolOptional\" = \"bool\")", boolOptional == bool)
|
||||
AssertSQL("(\"boolOptional\" = \"boolOptional\")", boolOptional == boolOptional)
|
||||
AssertSQL("(\"bool\" = 1)", bool == true)
|
||||
AssertSQL("(\"boolOptional\" = 1)", boolOptional == true)
|
||||
AssertSQL("(1 = \"bool\")", true == bool)
|
||||
AssertSQL("(1 = \"boolOptional\")", true == boolOptional)
|
||||
|
||||
AssertSQL("(\"boolOptional\" IS NULL)", boolOptional == nil)
|
||||
AssertSQL("(NULL IS \"boolOptional\")", nil == boolOptional)
|
||||
}
|
||||
|
||||
func test_inequalityOperator_withEquatableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" != \"bool\")", bool != bool)
|
||||
AssertSQL("(\"bool\" != \"boolOptional\")", bool != boolOptional)
|
||||
AssertSQL("(\"boolOptional\" != \"bool\")", boolOptional != bool)
|
||||
AssertSQL("(\"boolOptional\" != \"boolOptional\")", boolOptional != boolOptional)
|
||||
AssertSQL("(\"bool\" != 1)", bool != true)
|
||||
AssertSQL("(\"boolOptional\" != 1)", boolOptional != true)
|
||||
AssertSQL("(1 != \"bool\")", true != bool)
|
||||
AssertSQL("(1 != \"boolOptional\")", true != boolOptional)
|
||||
|
||||
AssertSQL("(\"boolOptional\" IS NOT NULL)", boolOptional != nil)
|
||||
AssertSQL("(NULL IS NOT \"boolOptional\")", nil != boolOptional)
|
||||
}
|
||||
|
||||
func test_greaterThanOperator_withComparableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" > \"bool\")", bool > bool)
|
||||
AssertSQL("(\"bool\" > \"boolOptional\")", bool > boolOptional)
|
||||
AssertSQL("(\"boolOptional\" > \"bool\")", boolOptional > bool)
|
||||
AssertSQL("(\"boolOptional\" > \"boolOptional\")", boolOptional > boolOptional)
|
||||
AssertSQL("(\"bool\" > 1)", bool > true)
|
||||
AssertSQL("(\"boolOptional\" > 1)", boolOptional > true)
|
||||
AssertSQL("(1 > \"bool\")", true > bool)
|
||||
AssertSQL("(1 > \"boolOptional\")", true > boolOptional)
|
||||
}
|
||||
|
||||
func test_greaterThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" >= \"bool\")", bool >= bool)
|
||||
AssertSQL("(\"bool\" >= \"boolOptional\")", bool >= boolOptional)
|
||||
AssertSQL("(\"boolOptional\" >= \"bool\")", boolOptional >= bool)
|
||||
AssertSQL("(\"boolOptional\" >= \"boolOptional\")", boolOptional >= boolOptional)
|
||||
AssertSQL("(\"bool\" >= 1)", bool >= true)
|
||||
AssertSQL("(\"boolOptional\" >= 1)", boolOptional >= true)
|
||||
AssertSQL("(1 >= \"bool\")", true >= bool)
|
||||
AssertSQL("(1 >= \"boolOptional\")", true >= boolOptional)
|
||||
}
|
||||
|
||||
func test_lessThanOperator_withComparableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" < \"bool\")", bool < bool)
|
||||
AssertSQL("(\"bool\" < \"boolOptional\")", bool < boolOptional)
|
||||
AssertSQL("(\"boolOptional\" < \"bool\")", boolOptional < bool)
|
||||
AssertSQL("(\"boolOptional\" < \"boolOptional\")", boolOptional < boolOptional)
|
||||
AssertSQL("(\"bool\" < 1)", bool < true)
|
||||
AssertSQL("(\"boolOptional\" < 1)", boolOptional < true)
|
||||
AssertSQL("(1 < \"bool\")", true < bool)
|
||||
AssertSQL("(1 < \"boolOptional\")", true < boolOptional)
|
||||
}
|
||||
|
||||
func test_lessThanOrEqualToOperator_withComparableExpressions_buildsBooleanExpression() {
|
||||
AssertSQL("(\"bool\" <= \"bool\")", bool <= bool)
|
||||
AssertSQL("(\"bool\" <= \"boolOptional\")", bool <= boolOptional)
|
||||
AssertSQL("(\"boolOptional\" <= \"bool\")", boolOptional <= bool)
|
||||
AssertSQL("(\"boolOptional\" <= \"boolOptional\")", boolOptional <= boolOptional)
|
||||
AssertSQL("(\"bool\" <= 1)", bool <= true)
|
||||
AssertSQL("(\"boolOptional\" <= 1)", boolOptional <= true)
|
||||
AssertSQL("(1 <= \"bool\")", true <= bool)
|
||||
AssertSQL("(1 <= \"boolOptional\")", true <= boolOptional)
|
||||
}
|
||||
|
||||
func test_patternMatchingOperator_withComparableCountableClosedRange_buildsBetweenBooleanExpression() {
|
||||
AssertSQL("\"int\" BETWEEN 0 AND 5", 0...5 ~= int)
|
||||
AssertSQL("\"intOptional\" BETWEEN 0 AND 5", 0...5 ~= intOptional)
|
||||
}
|
||||
|
||||
func test_patternMatchingOperator_withComparableClosedRange_buildsBetweenBooleanExpression() {
|
||||
AssertSQL("\"double\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= double)
|
||||
AssertSQL("\"doubleOptional\" BETWEEN 1.2 AND 4.5", 1.2...4.5 ~= doubleOptional)
|
||||
}
|
||||
|
||||
func test_patternMatchingOperator_withomparableClosedRangeString_buildsBetweenBooleanExpression() {
|
||||
AssertSQL("\"string\" BETWEEN 'a' AND 'b'", "a"..."b" ~= string)
|
||||
AssertSQL("\"stringOptional\" BETWEEN 'a' AND 'b'", "a"..."b" ~= stringOptional)
|
||||
}
|
||||
|
||||
func test_doubleAndOperator_withBooleanExpressions_buildsCompoundExpression() {
|
||||
AssertSQL("(\"bool\" AND \"bool\")", bool && bool)
|
||||
AssertSQL("(\"bool\" AND \"boolOptional\")", bool && boolOptional)
|
||||
AssertSQL("(\"boolOptional\" AND \"bool\")", boolOptional && bool)
|
||||
AssertSQL("(\"boolOptional\" AND \"boolOptional\")", boolOptional && boolOptional)
|
||||
AssertSQL("(\"bool\" AND 1)", bool && true)
|
||||
AssertSQL("(\"boolOptional\" AND 1)", boolOptional && true)
|
||||
AssertSQL("(1 AND \"bool\")", true && bool)
|
||||
AssertSQL("(1 AND \"boolOptional\")", true && boolOptional)
|
||||
}
|
||||
|
||||
func test_doubleOrOperator_withBooleanExpressions_buildsCompoundExpression() {
|
||||
AssertSQL("(\"bool\" OR \"bool\")", bool || bool)
|
||||
AssertSQL("(\"bool\" OR \"boolOptional\")", bool || boolOptional)
|
||||
AssertSQL("(\"boolOptional\" OR \"bool\")", boolOptional || bool)
|
||||
AssertSQL("(\"boolOptional\" OR \"boolOptional\")", boolOptional || boolOptional)
|
||||
AssertSQL("(\"bool\" OR 1)", bool || true)
|
||||
AssertSQL("(\"boolOptional\" OR 1)", boolOptional || true)
|
||||
AssertSQL("(1 OR \"bool\")", true || bool)
|
||||
AssertSQL("(1 OR \"boolOptional\")", true || boolOptional)
|
||||
}
|
||||
|
||||
func test_unaryNotOperator_withBooleanExpressions_buildsNotExpression() {
|
||||
AssertSQL("NOT (\"bool\")", !bool)
|
||||
AssertSQL("NOT (\"boolOptional\")", !boolOptional)
|
||||
}
|
||||
|
||||
func test_precedencePreserved() {
|
||||
let n = Expression<Int>(value: 1)
|
||||
AssertSQL("(((1 = 1) AND (1 = 1)) OR (1 = 1))", (n == n && n == n) || n == n)
|
||||
AssertSQL("((1 = 1) AND ((1 = 1) OR (1 = 1)))", n == n && (n == n || n == n))
|
||||
}
|
||||
|
||||
}
|
||||
365
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/QueryTests.swift
vendored
Normal file
365
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/QueryTests.swift
vendored
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class QueryTests : XCTestCase {
|
||||
|
||||
let users = Table("users")
|
||||
let id = Expression<Int64>("id")
|
||||
let email = Expression<String>("email")
|
||||
let age = Expression<Int?>("age")
|
||||
let admin = Expression<Bool>("admin")
|
||||
let optionalAdmin = Expression<Bool?>("admin")
|
||||
|
||||
let posts = Table("posts")
|
||||
let userId = Expression<Int64>("user_id")
|
||||
let categoryId = Expression<Int64>("category_id")
|
||||
let published = Expression<Bool>("published")
|
||||
|
||||
let categories = Table("categories")
|
||||
let tag = Expression<String>("tag")
|
||||
|
||||
func test_select_withExpression_compilesSelectClause() {
|
||||
AssertSQL("SELECT \"email\" FROM \"users\"", users.select(email))
|
||||
}
|
||||
|
||||
func test_select_withStarExpression_compilesSelectClause() {
|
||||
AssertSQL("SELECT * FROM \"users\"", users.select(*))
|
||||
}
|
||||
|
||||
func test_select_withNamespacedStarExpression_compilesSelectClause() {
|
||||
AssertSQL("SELECT \"users\".* FROM \"users\"", users.select(users[*]))
|
||||
}
|
||||
|
||||
func test_select_withVariadicExpressions_compilesSelectClause() {
|
||||
AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select(email, count(*)))
|
||||
}
|
||||
|
||||
func test_select_withExpressions_compilesSelectClause() {
|
||||
AssertSQL("SELECT \"email\", count(*) FROM \"users\"", users.select([email, count(*)]))
|
||||
}
|
||||
|
||||
func test_selectDistinct_withExpression_compilesSelectClause() {
|
||||
AssertSQL("SELECT DISTINCT \"age\" FROM \"users\"", users.select(distinct: age))
|
||||
}
|
||||
|
||||
func test_selectDistinct_withExpressions_compilesSelectClause() {
|
||||
AssertSQL("SELECT DISTINCT \"age\", \"admin\" FROM \"users\"", users.select(distinct: [age, admin]))
|
||||
}
|
||||
|
||||
func test_selectDistinct_withStar_compilesSelectClause() {
|
||||
AssertSQL("SELECT DISTINCT * FROM \"users\"", users.select(distinct: *))
|
||||
}
|
||||
|
||||
func test_join_compilesJoinClause() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")",
|
||||
users.join(posts, on: posts[userId] == users[id])
|
||||
)
|
||||
}
|
||||
|
||||
func test_join_withExplicitType_compilesJoinClauseWithType() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" LEFT OUTER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")",
|
||||
users.join(.leftOuter, posts, on: posts[userId] == users[id])
|
||||
)
|
||||
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" CROSS JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\")",
|
||||
users.join(.cross, posts, on: posts[userId] == users[id])
|
||||
)
|
||||
}
|
||||
|
||||
func test_join_withTableCondition_compilesJoinClauseWithTableCondition() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" INNER JOIN \"posts\" ON ((\"posts\".\"user_id\" = \"users\".\"id\") AND \"published\")",
|
||||
users.join(posts.filter(published), on: posts[userId] == users[id])
|
||||
)
|
||||
}
|
||||
|
||||
func test_join_whenChained_compilesAggregateJoinClause() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" " +
|
||||
"INNER JOIN \"posts\" ON (\"posts\".\"user_id\" = \"users\".\"id\") " +
|
||||
"INNER JOIN \"categories\" ON (\"categories\".\"id\" = \"posts\".\"category_id\")",
|
||||
users.join(posts, on: posts[userId] == users[id]).join(categories, on: categories[id] == posts[categoryId])
|
||||
)
|
||||
}
|
||||
|
||||
func test_filter_compilesWhereClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(admin == true))
|
||||
}
|
||||
|
||||
func test_filter_compilesWhereClause_false() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(admin == false))
|
||||
}
|
||||
|
||||
func test_filter_compilesWhereClause_optional() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.filter(optionalAdmin == true))
|
||||
}
|
||||
|
||||
func test_filter_compilesWhereClause_optional_false() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.filter(optionalAdmin == false))
|
||||
}
|
||||
|
||||
func test_where_compilesWhereClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(admin == true))
|
||||
}
|
||||
|
||||
func test_where_compilesWhereClause_false() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(admin == false))
|
||||
}
|
||||
|
||||
func test_where_compilesWhereClause_optional() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 1)", users.where(optionalAdmin == true))
|
||||
}
|
||||
|
||||
func test_where_compilesWhereClause_optional_false() {
|
||||
AssertSQL("SELECT * FROM \"users\" WHERE (\"admin\" = 0)", users.where(optionalAdmin == false))
|
||||
}
|
||||
|
||||
func test_filter_whenChained_compilesAggregateWhereClause() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" WHERE ((\"age\" >= 35) AND \"admin\")",
|
||||
users.filter(age >= 35).filter(admin)
|
||||
)
|
||||
}
|
||||
|
||||
func test_group_withSingleExpressionName_compilesGroupClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\"",
|
||||
users.group(age))
|
||||
}
|
||||
|
||||
func test_group_withVariadicExpressionNames_compilesGroupClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\", \"admin\"", users.group(age, admin))
|
||||
}
|
||||
|
||||
func test_group_withExpressionNameAndHavingBindings_compilesGroupClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING \"admin\"", users.group(age, having: admin))
|
||||
AssertSQL("SELECT * FROM \"users\" GROUP BY \"age\" HAVING (\"age\" >= 30)", users.group(age, having: age >= 30))
|
||||
}
|
||||
|
||||
func test_group_withExpressionNamesAndHavingBindings_compilesGroupClause() {
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING \"admin\"",
|
||||
users.group([age, admin], having: admin)
|
||||
)
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" GROUP BY \"age\", \"admin\" HAVING (\"age\" >= 30)",
|
||||
users.group([age, admin], having: age >= 30)
|
||||
)
|
||||
}
|
||||
|
||||
func test_order_withSingleExpressionName_compilesOrderClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(age))
|
||||
}
|
||||
|
||||
func test_order_withVariadicExpressionNames_compilesOrderClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order(age, email))
|
||||
}
|
||||
|
||||
func test_order_withArrayExpressionNames_compilesOrderClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\", \"email\"", users.order([age, email]))
|
||||
}
|
||||
|
||||
func test_order_withExpressionAndSortDirection_compilesOrderClause() {
|
||||
// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age.desc, email.asc))
|
||||
}
|
||||
|
||||
func test_order_whenChained_resetsOrderClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\"", users.order(email).order(age))
|
||||
}
|
||||
|
||||
func test_reverse_withoutOrder_ordersByRowIdDescending() {
|
||||
// AssertSQL("SELECT * FROM \"users\" ORDER BY \"ROWID\" DESC", users.reverse())
|
||||
}
|
||||
|
||||
func test_reverse_withOrder_reversesOrder() {
|
||||
// AssertSQL("SELECT * FROM \"users\" ORDER BY \"age\" DESC, \"email\" ASC", users.order(age, email.desc).reverse())
|
||||
}
|
||||
|
||||
func test_limit_compilesLimitClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" LIMIT 5", users.limit(5))
|
||||
}
|
||||
|
||||
func test_limit_withOffset_compilesOffsetClause() {
|
||||
AssertSQL("SELECT * FROM \"users\" LIMIT 5 OFFSET 5", users.limit(5, offset: 5))
|
||||
}
|
||||
|
||||
func test_limit_whenChained_overridesLimit() {
|
||||
let query = users.limit(5)
|
||||
|
||||
AssertSQL("SELECT * FROM \"users\" LIMIT 10", query.limit(10))
|
||||
AssertSQL("SELECT * FROM \"users\"", query.limit(nil))
|
||||
}
|
||||
|
||||
func test_limit_whenChained_withOffset_overridesOffset() {
|
||||
let query = users.limit(5, offset: 5)
|
||||
|
||||
AssertSQL("SELECT * FROM \"users\" LIMIT 10 OFFSET 20", query.limit(10, offset: 20))
|
||||
AssertSQL("SELECT * FROM \"users\"", query.limit(nil))
|
||||
}
|
||||
|
||||
func test_alias_aliasesTable() {
|
||||
let managerId = Expression<Int64>("manager_id")
|
||||
|
||||
let managers = users.alias("managers")
|
||||
|
||||
AssertSQL(
|
||||
"SELECT * FROM \"users\" " +
|
||||
"INNER JOIN \"users\" AS \"managers\" ON (\"managers\".\"id\" = \"users\".\"manager_id\")",
|
||||
users.join(managers, on: managers[id] == users[managerId])
|
||||
)
|
||||
}
|
||||
|
||||
func test_insert_compilesInsertExpression() {
|
||||
AssertSQL(
|
||||
"INSERT INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)",
|
||||
users.insert(email <- "alice@example.com", age <- 30)
|
||||
)
|
||||
}
|
||||
|
||||
func test_insert_withOnConflict_compilesInsertOrOnConflictExpression() {
|
||||
AssertSQL(
|
||||
"INSERT OR REPLACE INTO \"users\" (\"email\", \"age\") VALUES ('alice@example.com', 30)",
|
||||
users.insert(or: .replace, email <- "alice@example.com", age <- 30)
|
||||
)
|
||||
}
|
||||
|
||||
func test_insert_compilesInsertExpressionWithDefaultValues() {
|
||||
AssertSQL("INSERT INTO \"users\" DEFAULT VALUES", users.insert())
|
||||
}
|
||||
|
||||
func test_insert_withQuery_compilesInsertExpressionWithSelectStatement() {
|
||||
let emails = Table("emails")
|
||||
|
||||
AssertSQL(
|
||||
"INSERT INTO \"emails\" SELECT \"email\" FROM \"users\" WHERE \"admin\"",
|
||||
emails.insert(users.select(email).filter(admin))
|
||||
)
|
||||
}
|
||||
|
||||
func test_update_compilesUpdateExpression() {
|
||||
AssertSQL(
|
||||
"UPDATE \"users\" SET \"age\" = 30, \"admin\" = 1 WHERE (\"id\" = 1)",
|
||||
users.filter(id == 1).update(age <- 30, admin <- true)
|
||||
)
|
||||
}
|
||||
|
||||
func test_delete_compilesDeleteExpression() {
|
||||
AssertSQL(
|
||||
"DELETE FROM \"users\" WHERE (\"id\" = 1)",
|
||||
users.filter(id == 1).delete()
|
||||
)
|
||||
}
|
||||
|
||||
func test_delete_compilesExistsExpression() {
|
||||
AssertSQL(
|
||||
"SELECT EXISTS (SELECT * FROM \"users\")",
|
||||
users.exists
|
||||
)
|
||||
}
|
||||
|
||||
func test_count_returnsCountExpression() {
|
||||
AssertSQL("SELECT count(*) FROM \"users\"", users.count)
|
||||
}
|
||||
|
||||
func test_scalar_returnsScalarExpression() {
|
||||
AssertSQL("SELECT \"int\" FROM \"table\"", table.select(int) as ScalarQuery<Int>)
|
||||
AssertSQL("SELECT \"intOptional\" FROM \"table\"", table.select(intOptional) as ScalarQuery<Int?>)
|
||||
AssertSQL("SELECT DISTINCT \"int\" FROM \"table\"", table.select(distinct: int) as ScalarQuery<Int>)
|
||||
AssertSQL("SELECT DISTINCT \"intOptional\" FROM \"table\"", table.select(distinct: intOptional) as ScalarQuery<Int?>)
|
||||
}
|
||||
|
||||
func test_subscript_withExpression_returnsNamespacedExpression() {
|
||||
let query = Table("query")
|
||||
|
||||
AssertSQL("\"query\".\"blob\"", query[data])
|
||||
AssertSQL("\"query\".\"blobOptional\"", query[dataOptional])
|
||||
|
||||
AssertSQL("\"query\".\"bool\"", query[bool])
|
||||
AssertSQL("\"query\".\"boolOptional\"", query[boolOptional])
|
||||
|
||||
AssertSQL("\"query\".\"date\"", query[date])
|
||||
AssertSQL("\"query\".\"dateOptional\"", query[dateOptional])
|
||||
|
||||
AssertSQL("\"query\".\"double\"", query[double])
|
||||
AssertSQL("\"query\".\"doubleOptional\"", query[doubleOptional])
|
||||
|
||||
AssertSQL("\"query\".\"int\"", query[int])
|
||||
AssertSQL("\"query\".\"intOptional\"", query[intOptional])
|
||||
|
||||
AssertSQL("\"query\".\"int64\"", query[int64])
|
||||
AssertSQL("\"query\".\"int64Optional\"", query[int64Optional])
|
||||
|
||||
AssertSQL("\"query\".\"string\"", query[string])
|
||||
AssertSQL("\"query\".\"stringOptional\"", query[stringOptional])
|
||||
|
||||
AssertSQL("\"query\".*", query[*])
|
||||
}
|
||||
|
||||
func test_tableNamespacedByDatabase() {
|
||||
let table = Table("table", database: "attached")
|
||||
|
||||
AssertSQL("SELECT * FROM \"attached\".\"table\"", table)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class QueryIntegrationTests : SQLiteTestCase {
|
||||
|
||||
let id = Expression<Int64>("id")
|
||||
let email = Expression<String>("email")
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
CreateUsersTable()
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
func test_select() {
|
||||
for _ in try! db.prepare(users) {
|
||||
// FIXME
|
||||
}
|
||||
|
||||
let managerId = Expression<Int64>("manager_id")
|
||||
let managers = users.alias("managers")
|
||||
|
||||
let alice = try! db.run(users.insert(email <- "alice@example.com"))
|
||||
_ = try! db.run(users.insert(email <- "betsy@example.com", managerId <- alice))
|
||||
|
||||
for user in try! db.prepare(users.join(managers, on: managers[id] == users[managerId])) {
|
||||
_ = user[users[managerId]]
|
||||
}
|
||||
}
|
||||
|
||||
func test_scalar() {
|
||||
XCTAssertEqual(0, try! db.scalar(users.count))
|
||||
XCTAssertEqual(false, try! db.scalar(users.exists))
|
||||
|
||||
try! InsertUsers("alice")
|
||||
XCTAssertEqual(1, try! db.scalar(users.select(id.average)))
|
||||
}
|
||||
|
||||
func test_pluck() {
|
||||
let rowid = try! db.run(users.insert(email <- "alice@example.com"))
|
||||
XCTAssertEqual(rowid, try! db.pluck(users)![id])
|
||||
}
|
||||
|
||||
func test_insert() {
|
||||
let id = try! db.run(users.insert(email <- "alice@example.com"))
|
||||
XCTAssertEqual(1, id)
|
||||
}
|
||||
|
||||
func test_update() {
|
||||
let changes = try! db.run(users.update(email <- "alice@example.com"))
|
||||
XCTAssertEqual(0, changes)
|
||||
}
|
||||
|
||||
func test_delete() {
|
||||
let changes = try! db.run(users.delete())
|
||||
XCTAssertEqual(0, changes)
|
||||
}
|
||||
|
||||
}
|
||||
17
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/RTreeTests.swift
vendored
Normal file
17
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/RTreeTests.swift
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class RTreeTests : XCTestCase {
|
||||
|
||||
func test_create_onVirtualTable_withRTree_createVirtualTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\")",
|
||||
virtualTable.create(.RTree(int64, (double, double)))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING rtree(\"int64\", \"double\", \"double\", \"double\", \"double\")",
|
||||
virtualTable.create(.RTree(int64, (double, double), (double, double)))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
775
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SchemaTests.swift
vendored
Normal file
775
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SchemaTests.swift
vendored
Normal file
|
|
@ -0,0 +1,775 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class SchemaTests : XCTestCase {
|
||||
|
||||
func test_drop_compilesDropTableExpression() {
|
||||
XCTAssertEqual("DROP TABLE \"table\"", table.drop())
|
||||
XCTAssertEqual("DROP TABLE IF EXISTS \"table\"", table.drop(ifExists: true))
|
||||
}
|
||||
|
||||
func test_drop_compilesDropVirtualTableExpression() {
|
||||
XCTAssertEqual("DROP TABLE \"virtual_table\"", virtualTable.drop())
|
||||
XCTAssertEqual("DROP TABLE IF EXISTS \"virtual_table\"", virtualTable.drop(ifExists: true))
|
||||
}
|
||||
|
||||
func test_drop_compilesDropViewExpression() {
|
||||
XCTAssertEqual("DROP VIEW \"view\"", _view.drop())
|
||||
XCTAssertEqual("DROP VIEW IF EXISTS \"view\"", _view.drop(ifExists: true))
|
||||
}
|
||||
|
||||
func test_create_withBuilder_compilesCreateTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (" +
|
||||
"\"blob\" BLOB NOT NULL, " +
|
||||
"\"blobOptional\" BLOB, " +
|
||||
"\"double\" REAL NOT NULL, " +
|
||||
"\"doubleOptional\" REAL, " +
|
||||
"\"int64\" INTEGER NOT NULL, " +
|
||||
"\"int64Optional\" INTEGER, " +
|
||||
"\"string\" TEXT NOT NULL, " +
|
||||
"\"stringOptional\" TEXT" +
|
||||
")",
|
||||
table.create { t in
|
||||
t.column(data)
|
||||
t.column(dataOptional)
|
||||
t.column(double)
|
||||
t.column(doubleOptional)
|
||||
t.column(int64)
|
||||
t.column(int64Optional)
|
||||
t.column(string)
|
||||
t.column(stringOptional)
|
||||
}
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TEMPORARY TABLE \"table\" (\"int64\" INTEGER NOT NULL)",
|
||||
table.create(temporary: true) { $0.column(int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)",
|
||||
table.create(ifNotExists: true) { $0.column(int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TEMPORARY TABLE IF NOT EXISTS \"table\" (\"int64\" INTEGER NOT NULL)",
|
||||
table.create(temporary: true, ifNotExists: true) { $0.column(int64) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_create_withQuery_compilesCreateTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" AS SELECT \"int64\" FROM \"view\"",
|
||||
table.create(_view.select(int64))
|
||||
)
|
||||
}
|
||||
|
||||
// thoroughness test for ambiguity
|
||||
func test_column_compilesColumnDefinitionExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL)",
|
||||
table.create { t in t.column(int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE)",
|
||||
table.create { t in t.column(int64, unique: true) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL DEFAULT (0))",
|
||||
table.create { t in t.column(int64, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE DEFAULT (0))",
|
||||
table.create { t in t.column(int64, unique: true, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64 > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64Optional > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, check: int64 > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64, check: int64 > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64, check: int64Optional > 0, defaultValue: 0) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, primaryKey: true, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64 > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64, primaryKey: true, check: int64Optional > 0, defaultValue: int64) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER)",
|
||||
table.create { t in t.column(int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE)",
|
||||
table.create { t in t.column(int64Optional, unique: true) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64Optional, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64Optional, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (\"int64Optional\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: int64Optional) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, check: int64 > 0, defaultValue: 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (0))",
|
||||
table.create { t in t.column(int64Optional, check: int64Optional > 0, defaultValue: 0) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_column_withIntegerExpression_compilesPrimaryKeyAutoincrementColumnDefinitionExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
|
||||
table.create { t in t.column(int64, primaryKey: .autoincrement) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (\"int64Optional\" > 0))",
|
||||
table.create { t in t.column(int64, primaryKey: .autoincrement, check: int64Optional > 0) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_column_withIntegerExpression_compilesReferentialColumnDefinitionExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, references: qualifiedTable, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, check: int64 > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, check: int64Optional > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64 > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64, unique: true, check: int64Optional > 0, references: table, int64) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64 > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, check: int64Optional > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64 > 0, references: table, int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\"))",
|
||||
table.create { t in t.column(int64Optional, unique: true, check: int64Optional > 0, references: table, int64) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_column_withStringExpression_compilesCollatedColumnDefinitionExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: string != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: stringOptional != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: string != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: stringOptional != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: string != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: string != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: stringOptional != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: string != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: string != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: stringOptional != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: string != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: string != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL UNIQUE CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, unique: true, check: stringOptional != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: string != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"string\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: string, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: string != "", defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT (\"stringOptional\") COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: stringOptional, collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (\"stringOptional\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM)",
|
||||
table.create { t in t.column(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_primaryKey_compilesPrimaryKeyExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (PRIMARY KEY (\"int64\"))",
|
||||
table.create { t in t.primaryKey(int64) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\"))",
|
||||
table.create { t in t.primaryKey(int64, string) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (PRIMARY KEY (\"int64\", \"string\", \"double\"))",
|
||||
table.create { t in t.primaryKey(int64, string, double) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_unique_compilesUniqueExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (UNIQUE (\"int64\"))",
|
||||
table.create { t in t.unique(int64) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_check_compilesCheckExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (CHECK ((\"int64\" > 0)))",
|
||||
table.create { t in t.check(int64 > 0) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (CHECK ((\"int64Optional\" > 0)))",
|
||||
table.create { t in t.check(int64Optional > 0) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_foreignKey_compilesForeignKeyExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\"))",
|
||||
table.create { t in t.foreignKey(string, references: table, string) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (FOREIGN KEY (\"stringOptional\") REFERENCES \"table\" (\"string\"))",
|
||||
table.create { t in t.foreignKey(stringOptional, references: table, string) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (FOREIGN KEY (\"string\") REFERENCES \"table\" (\"string\") ON UPDATE CASCADE ON DELETE SET NULL)",
|
||||
table.create { t in t.foreignKey(string, references: table, string, update: .cascade, delete: .setNull) }
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\"))",
|
||||
table.create { t in t.foreignKey((string, string), references: table, (string, string)) }
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TABLE \"table\" (FOREIGN KEY (\"string\", \"string\", \"string\") REFERENCES \"table\" (\"string\", \"string\", \"string\"))",
|
||||
table.create { t in t.foreignKey((string, string, string), references: table, (string, string, string)) }
|
||||
)
|
||||
}
|
||||
|
||||
func test_addColumn_compilesAlterTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL DEFAULT (1)",
|
||||
table.addColumn(int64, defaultValue: 1)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) DEFAULT (1)",
|
||||
table.addColumn(int64, check: int64 > 0, defaultValue: 1)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) DEFAULT (1)",
|
||||
table.addColumn(int64, check: int64Optional > 0, defaultValue: 1)
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER",
|
||||
table.addColumn(int64Optional)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0)",
|
||||
table.addColumn(int64Optional, check: int64 > 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0)",
|
||||
table.addColumn(int64Optional, check: int64Optional > 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER DEFAULT (1)",
|
||||
table.addColumn(int64Optional, defaultValue: 1)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) DEFAULT (1)",
|
||||
table.addColumn(int64Optional, check: int64 > 0, defaultValue: 1)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) DEFAULT (1)",
|
||||
table.addColumn(int64Optional, check: int64Optional > 0, defaultValue: 1)
|
||||
)
|
||||
}
|
||||
|
||||
func test_addColumn_withIntegerExpression_compilesReferentialAlterTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, unique: true, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, check: int64 > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, check: int64Optional > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, unique: true, check: int64 > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64\" INTEGER NOT NULL UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64, unique: true, check: int64Optional > 0, references: table, int64)
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, unique: true, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, check: int64 > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, check: int64Optional > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, unique: true, check: int64 > 0, references: table, int64)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"int64Optional\" INTEGER UNIQUE CHECK (\"int64Optional\" > 0) REFERENCES \"table\" (\"int64\")",
|
||||
table.addColumn(int64Optional, unique: true, check: int64Optional > 0, references: table, int64)
|
||||
)
|
||||
}
|
||||
|
||||
func test_addColumn_withStringExpression_compilesCollatedAlterTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL DEFAULT ('string') COLLATE RTRIM",
|
||||
table.addColumn(string, defaultValue: "string", collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM",
|
||||
table.addColumn(string, check: string != "", defaultValue: "string", collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"string\" TEXT NOT NULL CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM",
|
||||
table.addColumn(string, check: stringOptional != "", defaultValue: "string", collate: .rtrim)
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT COLLATE RTRIM",
|
||||
table.addColumn(stringOptional, collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') COLLATE RTRIM",
|
||||
table.addColumn(stringOptional, check: string != "", collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') COLLATE RTRIM",
|
||||
table.addColumn(stringOptional, check: stringOptional != "", collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"string\" != '') DEFAULT ('string') COLLATE RTRIM",
|
||||
table.addColumn(stringOptional, check: string != "", defaultValue: "string", collate: .rtrim)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"table\" ADD COLUMN \"stringOptional\" TEXT CHECK (\"stringOptional\" != '') DEFAULT ('string') COLLATE RTRIM",
|
||||
table.addColumn(stringOptional, check: stringOptional != "", defaultValue: "string", collate: .rtrim)
|
||||
)
|
||||
}
|
||||
|
||||
func test_rename_compilesAlterTableRenameToExpression() {
|
||||
XCTAssertEqual("ALTER TABLE \"old\" RENAME TO \"table\"", Table("old").rename(table))
|
||||
}
|
||||
|
||||
func test_createIndex_compilesCreateIndexExpression() {
|
||||
XCTAssertEqual("CREATE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")", table.createIndex(int64))
|
||||
|
||||
XCTAssertEqual(
|
||||
"CREATE UNIQUE INDEX \"index_table_on_int64\" ON \"table\" (\"int64\")",
|
||||
table.createIndex([int64], unique: true)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")",
|
||||
table.createIndex([int64], ifNotExists: true)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS \"index_table_on_int64\" ON \"table\" (\"int64\")",
|
||||
table.createIndex([int64], unique: true, ifNotExists: true)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS \"main\".\"index_table_on_int64\" ON \"table\" (\"int64\")",
|
||||
qualifiedTable.createIndex([int64], unique: true, ifNotExists: true)
|
||||
)
|
||||
}
|
||||
|
||||
func test_dropIndex_compilesCreateIndexExpression() {
|
||||
XCTAssertEqual("DROP INDEX \"index_table_on_int64\"", table.dropIndex(int64))
|
||||
XCTAssertEqual("DROP INDEX IF EXISTS \"index_table_on_int64\"", table.dropIndex([int64], ifExists: true))
|
||||
}
|
||||
|
||||
func test_create_onView_compilesCreateViewExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIEW \"view\" AS SELECT \"int64\" FROM \"table\"",
|
||||
_view.create(table.select(int64))
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TEMPORARY VIEW \"view\" AS SELECT \"int64\" FROM \"table\"",
|
||||
_view.create(table.select(int64), temporary: true)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"",
|
||||
_view.create(table.select(int64), ifNotExists: true)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
"CREATE TEMPORARY VIEW IF NOT EXISTS \"view\" AS SELECT \"int64\" FROM \"table\"",
|
||||
_view.create(table.select(int64), temporary: true, ifNotExists: true)
|
||||
)
|
||||
}
|
||||
|
||||
func test_create_onVirtualTable_compilesCreateVirtualTableExpression() {
|
||||
XCTAssertEqual(
|
||||
"CREATE VIRTUAL TABLE \"virtual_table\" USING \"custom\"('foo', 'bar')",
|
||||
virtualTable.create(Module("custom", ["foo", "bar"]))
|
||||
)
|
||||
}
|
||||
|
||||
func test_rename_onVirtualTable_compilesAlterTableRenameToExpression() {
|
||||
XCTAssertEqual(
|
||||
"ALTER TABLE \"old\" RENAME TO \"virtual_table\"",
|
||||
VirtualTable("old").rename(virtualTable)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
137
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SetterTests.swift
vendored
Normal file
137
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/SetterTests.swift
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class SetterTests : XCTestCase {
|
||||
|
||||
func test_setterAssignmentOperator_buildsSetter() {
|
||||
AssertSQL("\"int\" = \"int\"", int <- int)
|
||||
AssertSQL("\"int\" = 1", int <- 1)
|
||||
AssertSQL("\"intOptional\" = \"int\"", intOptional <- int)
|
||||
AssertSQL("\"intOptional\" = \"intOptional\"", intOptional <- intOptional)
|
||||
AssertSQL("\"intOptional\" = 1", intOptional <- 1)
|
||||
AssertSQL("\"intOptional\" = NULL", intOptional <- nil)
|
||||
}
|
||||
|
||||
func test_plusEquals_withStringExpression_buildsSetter() {
|
||||
AssertSQL("\"string\" = (\"string\" || \"string\")", string += string)
|
||||
AssertSQL("\"string\" = (\"string\" || 'literal')", string += "literal")
|
||||
AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"string\")", stringOptional += string)
|
||||
AssertSQL("\"stringOptional\" = (\"stringOptional\" || \"stringOptional\")", stringOptional += stringOptional)
|
||||
AssertSQL("\"stringOptional\" = (\"stringOptional\" || 'literal')", stringOptional += "literal")
|
||||
}
|
||||
|
||||
func test_plusEquals_withNumberExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" + \"int\")", int += int)
|
||||
AssertSQL("\"int\" = (\"int\" + 1)", int += 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" + \"int\")", intOptional += int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" + \"intOptional\")", intOptional += intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional += 1)
|
||||
|
||||
AssertSQL("\"double\" = (\"double\" + \"double\")", double += double)
|
||||
AssertSQL("\"double\" = (\"double\" + 1.0)", double += 1)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"double\")", doubleOptional += double)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + \"doubleOptional\")", doubleOptional += doubleOptional)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" + 1.0)", doubleOptional += 1)
|
||||
}
|
||||
|
||||
func test_minusEquals_withNumberExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" - \"int\")", int -= int)
|
||||
AssertSQL("\"int\" = (\"int\" - 1)", int -= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" - \"int\")", intOptional -= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" - \"intOptional\")", intOptional -= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional -= 1)
|
||||
|
||||
AssertSQL("\"double\" = (\"double\" - \"double\")", double -= double)
|
||||
AssertSQL("\"double\" = (\"double\" - 1.0)", double -= 1)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"double\")", doubleOptional -= double)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - \"doubleOptional\")", doubleOptional -= doubleOptional)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" - 1.0)", doubleOptional -= 1)
|
||||
}
|
||||
|
||||
func test_timesEquals_withNumberExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" * \"int\")", int *= int)
|
||||
AssertSQL("\"int\" = (\"int\" * 1)", int *= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" * \"int\")", intOptional *= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" * \"intOptional\")", intOptional *= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" * 1)", intOptional *= 1)
|
||||
|
||||
AssertSQL("\"double\" = (\"double\" * \"double\")", double *= double)
|
||||
AssertSQL("\"double\" = (\"double\" * 1.0)", double *= 1)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"double\")", doubleOptional *= double)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * \"doubleOptional\")", doubleOptional *= doubleOptional)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" * 1.0)", doubleOptional *= 1)
|
||||
}
|
||||
|
||||
func test_dividedByEquals_withNumberExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" / \"int\")", int /= int)
|
||||
AssertSQL("\"int\" = (\"int\" / 1)", int /= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" / \"int\")", intOptional /= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" / \"intOptional\")", intOptional /= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" / 1)", intOptional /= 1)
|
||||
|
||||
AssertSQL("\"double\" = (\"double\" / \"double\")", double /= double)
|
||||
AssertSQL("\"double\" = (\"double\" / 1.0)", double /= 1)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"double\")", doubleOptional /= double)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / \"doubleOptional\")", doubleOptional /= doubleOptional)
|
||||
AssertSQL("\"doubleOptional\" = (\"doubleOptional\" / 1.0)", doubleOptional /= 1)
|
||||
}
|
||||
|
||||
func test_moduloEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" % \"int\")", int %= int)
|
||||
AssertSQL("\"int\" = (\"int\" % 1)", int %= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" % \"int\")", intOptional %= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" % \"intOptional\")", intOptional %= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" % 1)", intOptional %= 1)
|
||||
}
|
||||
|
||||
func test_leftShiftEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" << \"int\")", int <<= int)
|
||||
AssertSQL("\"int\" = (\"int\" << 1)", int <<= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" << \"int\")", intOptional <<= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" << \"intOptional\")", intOptional <<= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" << 1)", intOptional <<= 1)
|
||||
}
|
||||
|
||||
func test_rightShiftEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" >> \"int\")", int >>= int)
|
||||
AssertSQL("\"int\" = (\"int\" >> 1)", int >>= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" >> \"int\")", intOptional >>= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" >> \"intOptional\")", intOptional >>= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" >> 1)", intOptional >>= 1)
|
||||
}
|
||||
|
||||
func test_bitwiseAndEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" & \"int\")", int &= int)
|
||||
AssertSQL("\"int\" = (\"int\" & 1)", int &= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" & \"int\")", intOptional &= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" & \"intOptional\")", intOptional &= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" & 1)", intOptional &= 1)
|
||||
}
|
||||
|
||||
func test_bitwiseOrEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" | \"int\")", int |= int)
|
||||
AssertSQL("\"int\" = (\"int\" | 1)", int |= 1)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" | \"int\")", intOptional |= int)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" | \"intOptional\")", intOptional |= intOptional)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" | 1)", intOptional |= 1)
|
||||
}
|
||||
|
||||
func test_bitwiseExclusiveOrEquals_withIntegerExpression_buildsSetter() {
|
||||
AssertSQL("\"int\" = (~((\"int\" & \"int\")) & (\"int\" | \"int\"))", int ^= int)
|
||||
AssertSQL("\"int\" = (~((\"int\" & 1)) & (\"int\" | 1))", int ^= 1)
|
||||
AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"int\")) & (\"intOptional\" | \"int\"))", intOptional ^= int)
|
||||
AssertSQL("\"intOptional\" = (~((\"intOptional\" & \"intOptional\")) & (\"intOptional\" | \"intOptional\"))", intOptional ^= intOptional)
|
||||
AssertSQL("\"intOptional\" = (~((\"intOptional\" & 1)) & (\"intOptional\" | 1))", intOptional ^= 1)
|
||||
}
|
||||
|
||||
func test_postfixPlus_withIntegerValue_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" + 1)", int++)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" + 1)", intOptional++)
|
||||
}
|
||||
|
||||
func test_postfixMinus_withIntegerValue_buildsSetter() {
|
||||
AssertSQL("\"int\" = (\"int\" - 1)", int--)
|
||||
AssertSQL("\"intOptional\" = (\"intOptional\" - 1)", intOptional--)
|
||||
}
|
||||
|
||||
}
|
||||
26
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/StatementTests.swift
vendored
Normal file
26
mobile/ios/ThirdParty/SQLite.swift/Tests/SQLiteTests/StatementTests.swift
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import XCTest
|
||||
import SQLite
|
||||
|
||||
class StatementTests : SQLiteTestCase {
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
CreateUsersTable()
|
||||
}
|
||||
|
||||
func test_cursor_to_blob() {
|
||||
try! InsertUsers("alice")
|
||||
let statement = try! db.prepare("SELECT email FROM users")
|
||||
XCTAssert(try! statement.step())
|
||||
let blob = statement.row[0] as Blob
|
||||
XCTAssertEqual("alice@example.com", String(bytes: blob.bytes, encoding: .utf8)!)
|
||||
}
|
||||
|
||||
func test_zero_sized_blob_returns_null() {
|
||||
let blobs = Table("blobs")
|
||||
let blobColumn = Expression<Blob>("blob_column")
|
||||
try! db.run(blobs.create { $0.column(blobColumn) })
|
||||
try! db.run(blobs.insert(blobColumn <- Blob(bytes: [])))
|
||||
let blobValue = try! db.scalar(blobs.select(blobColumn).limit(1, offset: 0))
|
||||
XCTAssertEqual([], blobValue.bytes)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue