6
\$\begingroup\$

I've designed a library for connecting Objective-C (and now Swift) apps to Microsoft SQL Server 2005+. (I believe there are other databases it works with, but I've only tested with MSSQL.)

The project is available on Github here, and while users are fully capable of downloading the uncompiled project, my recommended option is downloading the compiled project along with the necessary headers.

I am interested in a review of the library's API.

Here it is:

SQLConnect.h

@import Foundation;

NSString * const SQLCONNECTION_VERSION_NUM;

#import "SQLConnection.h"

#import "SQLViewController.h"
#import "SQLTableViewController.h"
#import "SQLCollectionViewController.h"
#import "SQLSettings.h"

BOOL isNull(id obj);
id nullReplace(id obj, id replacement);

SQLConnection.h

#import "SQLConnectionDelegate.h"
#import "SQLSettings.h"

@interface SQLConnection : NSObject

#pragma mark Properties
/**
 *  Indicates whether or not the database is currently connected
 */
@property (nonatomic,assign,readonly) BOOL connected;

/**
 *  The database server to use.  Supports server, server:port, or server\instance (be sure to escape the backslash)
 */
@property (nonatomic,strong) NSString *server;

/**
 *  The database username
 */
@property (nonatomic,strong) NSString *username;

/**
 *  The database password
 */
@property (nonatomic,strong) NSString *password;

/**
 *  The database name to use
 */
@property (nonatomic,strong) NSString *database;

/**
 *  Delegate to handle callbacks
 */
@property (nonatomic,weak) id<SQLConnectionDelegate> delegate;

/**
 *  The queue to execute database operations on.  A default queue name is used, but can be overridden.
 */
@property (nonatomic,strong) NSOperationQueue *workerQueue;

/**
 *  The queue for delegate callbacks.  Uses current queue by default, but can be overridden.
 */
@property (nonatomic,strong) NSOperationQueue *callbackQueue;

/**
 *  The character set to use for converting the UCS-2 server results. Default is UTF-8. Can be overridden to any charset supported by the iconv library. 
 *  To list all supported iconv character sets, open a Terminal window and enter:
 *  $ iconv --list
 */
@property (nonatomic,strong) NSString *charset;

/**
 *  Login timeout, in seconds. Default is 5.  Override before calling connect
 */
@property (nonatomic,assign) int loginTimeout;

/**
 *  Query timeout, in seconds. Default is 5. Override before calling executeQuery:
 */
@property (nonatomic,assign) int executeTimeout;

/*
 *  Tag for the object.  Not used internally at all.  Only used for the user to distinguish which connection is calling the delegate method if wanted.
 */
@property (nonatomic,assign) NSInteger tag;

#pragma mark Initializer methods

- (id)init __attribute__((unavailable("Must initialize with a delegate")));

/**
 *  Returns a SQLConnection instance using the defaults defined in the SQLSettings defaultSettings object
 *
 *  @param delegate Required. An object conforming to the SQLConnectionDelegate protocol for receiving callback messages.
 *
 *  @return SQLConnection object using the SQLSettings defaultSettings
 */
+ (instancetype)sqlConnectionWithDelegate:(NSObject<SQLConnectionDelegate>*)delegate;

/**
 *  Returns a SQLConnection instance
 *
 *  @param server   Required. The database server to use.  Supports server, server:port, or server\instance (be sure to escape the backslash)
 *  @param username Required. The database username.
 *  @param password Required. The database password.
 *  @param database Required. The database name.
 *  @param delegate Required. An object conforming to the SQLConnectionDelegate protocol for receiving callback messages.
 *
 *  @return SQLConnection object
 */
- (id)initWithServer:(NSString*)server
            username:(NSString*)username
            password:(NSString*)password
            database:(NSString*)database
            delegate:(id<SQLConnectionDelegate>)delegate;

/**
 *  Returns a SQLConnection instance
 *
 *  @param server   Required. The database server to use.  Supports server, server:port, or server\instance (be sure to escape the backslash)
 *  @param username Required. The database username.
 *  @param password Required. The database password.
 *  @param database Required. The database name.
 *  @param delegate Required. An object conforming to the SQLConnectionDelegate protocol for receiving callback messages.
 *
 *  @return SQLConnection object
 */
+ (instancetype)sqlConnectionWithServer:(NSString*)server
                               username:(NSString*)username
                               password:(NSString*)password
                               database:(NSString*)database
                               delegate:(NSObject<SQLConnectionDelegate>*)delegate;

/**
 *  Returns a SQLConnection instance
 *
 *  @param settings Required. The settings to use for connecting to the database.
 *  @param delegate Required. An object conforming to the SQLConnectionDelegate protocol for receiving callback messages.
 *
 *  @return SQLConnection object
 */
- (id)initWithSettings:(SQLSettings*)settings delegate:(NSObject<SQLConnectionDelegate>*)delegate;

/**
 *  Returns a SQLConnection instance
 *
 *  @param settings Required. The settings to use for connecting to the database.
 *  @param delegate Required. An object conforming to the SQLConnectionDelegate protocol for receiving callback messages.
 *
 *  @return SQLConnection object
 */
+ (instancetype)sqlConnectionWithSettings:(SQLSettings*)settings delegate:(NSObject<SQLConnectionDelegate>*)delegate;

#pragma mark Working methods

/**
 *  Connects to the SQL database using the current connection settings.
 */
- (void)connect;

/*
 *  An optional alternative to connect.  This method frees the connection info immediately after the connection attempt so it is not kept in memory.
 *
 *  @param server   Required. The database server to use.  Supports server, server:port, or server\instance (be sure to escape the backslash)
 *  @param username Required. The database username.
 *  @param password Required. The database password.
 *  @param database Required. The database name.
 *  @param charset  Optional. The charset to use.  Will default to preset charset if nil is passed.
 */
- (void)connectToServer:(NSString *)server withUsername:(NSString *)username password:(NSString *)password usingDatabase:(NSString *)database charset:(NSString *)charset;

/**
 *  Executes the provided SQL statement.  Results are handled via the delegate methods.
 */
- (void)execute:(NSString*)statement;

/**
 *  Disconnects from database server
 */
- (void)disconnect;

@end

SQLConnectionDelegate.h

@class SQLConnection;

@protocol SQLConnection <NSObject>

/*
 *  Required delegate method to handle successful connection completion
 *  
 *  @param  connection  The SQLConnection instance which completed connection successfully
 */
@required - (void)sqlConnectionDidSucceed:(SQLConnection *)connection;

/*
 *  Required delegate method to handle connection failure
 *
 *  @param  connection  The SQLConnection instance which failed to connect
 *  @param  error       An error describing the connection problem
 */
@required - (void)sqlConnection:(SQLConnection *)connection connectionDidFailWithError:(NSError *)error;

@end

@protocol SQLQuery <NSObject>

/*
 *  Required delegate method to handle successful execution of a SQL command on the server
 *
 *  @param  connection  The SQLConnection instance which handled the execution
 *  @param  results     The results, if any, returned from the database
 */
@required - (void)sqlConnection:(SQLConnection *)connection executeDidCompleteWithResults:(NSArray *)results;

/*
 *  Required delegate method to handle unsuccessful execution of a SQL command on the server
 *
 *  @param  connection  The SQLConnection instance which handled the execution
 *  @param  error       An error describing the execution problem
 */
@required - (void)sqlConnection:(SQLConnection *)connection executeDidFailWithError:(NSError *)error;

@end

@protocol SQLConnectionDelegate <SQLConnection, SQLQuery>

/*
 *  Optional delegate method to handle message notifications from the server
 *
 *  @param  connection  The SQLConnection instance which received the message
 *  @param  message     The message from the server
 */
@optional - (void)sqlConnection:(SQLConnection *)connection didReceiveServerMessage:(NSString *)message;

/*
 *  Optional delegate method to handle error notifications from the server
 *
 *  @param  connection  The SQLConnection instance which received the message
 *  @param  error       The error message from the server
 *  @param  code        The error code from the server
 *  @param  severity    The error severity from the server
 */
@optional - (void)sqlConnection:(SQLConnection *)connection didReceiveServerError:(NSString*)error code:(int)code severity:(int)severity;

@end

SQLSettings.h

@import Foundation.NSObject;
@import Foundation.NSString;

@interface SQLSettings : NSObject

/*
 *  Returns a SQLSettings instance
 *
 *  @return SLQSettings object
 */
+ (instancetype)settings;

/*
 *  Returns a shared SQLSettings instance. This object can be used to specify default settings that SQLConnection objects will use when initialized without settings parameters.
 *
 *  @return Default settings object
 */
+ (instancetype)defaultSettings;

/**
 *  The database server to use.  Supports server, server:port, or server\instance (be sure to escape the backslash)
 */
@property (nonatomic,strong) NSString *server;

/**
 *  The database username
 */
@property (nonatomic,strong) NSString *username;

/**
 *  The database password
 */
@property (nonatomic,strong) NSString *password;

/**
 *  The database name to use
 */
@property (nonatomic,strong) NSString *database;

@end

SQLViewController.h

@interface SQLViewController : UIViewController

@property (nonatomic,assign) BOOL sqlDebugLogging;

- (void)viewDidLoad NS_REQUIRES_SUPER;
- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillLayoutSubviews NS_REQUIRES_SUPER;
- (void)viewDidLayoutSubviews NS_REQUIRES_SUPER;

@end

SQLTableViewController.h

@interface SQLTableViewController : UITableViewController

@property (nonatomic,assign) BOOL sqlDebugLogging;

- (void)viewDidLoad NS_REQUIRES_SUPER;
- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillLayoutSubviews NS_REQUIRES_SUPER;
- (void)viewDidLayoutSubviews NS_REQUIRES_SUPER;

@end

SQLCollectionViewController.h

@interface SQLCollectionViewController : UICollectionViewController

@property (nonatomic,assign) BOOL sqlDebugLogging;

- (void)viewDidLoad NS_REQUIRES_SUPER;
- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
- (void)viewWillLayoutSubviews NS_REQUIRES_SUPER;
- (void)viewDidLayoutSubviews NS_REQUIRES_SUPER;

@end

Presuming you got only these files and the compiled library file, would you feel confident using this library? Are there any naming issues? Anything missing?

And if you're wondering about, NS_REQUIRES_SUPER, here's some reading.

\$\endgroup\$

1 Answer 1

8
\$\begingroup\$

A few notes:

  • I feel like some of your properties should have the readonly attribute applied to them. Do we really want the API users to have the ability to change the username, password, or server variables after initialization?

    @property (nonatomic, strong, readonly) NSString *server;
    

    If you do really want them to have that ability, I would add a method so that those variables could be set to different values at the same time.

  • You have the phrase "Required." in a lot of your @param comments. As a frequent user of many APIs, I always assume that a valid parameter value is required unless told otherwise. So you only need to tell me what parameters are optional in your documentation (which is just one, that I could see).

  • You forgot that little extra * on some of your comment lines. This is important, since this is needed for Doxygen to parse these comment blocks (you are using Doxygen, correct?).

    /*  <---- need two * right there
     *
     *  Required delegate method to handle successful execution of a SQL command on the server
     *
     *  @param  connection  The SQLConnection instance which handled the execution
     *  @param  results     The results, if any, returned from the database
     */
    
\$\endgroup\$
3
  • \$\begingroup\$ I don't see where I'm missing a *. I intended use something to turn this into some nice looking Apple docs sometime, but haven't got around to it yet. \$\endgroup\$
    – nhgrif
    Aug 21, 2014 at 11:26
  • \$\begingroup\$ As for "Required", I may have copied this pattern from Apple's official documentation--I'll double check. If not, I'll implement this change. \$\endgroup\$
    – nhgrif
    Aug 21, 2014 at 11:32
  • \$\begingroup\$ As for readonly, "Do we really want the API users to have the ability to change the username or server variables after initialization?" Yes, actually, which suggests to me I might need better documentation and comments on this matter. \$\endgroup\$
    – nhgrif
    Aug 21, 2014 at 11:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.