YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

Related tags

YapDatabase
Overview

YapDatabaseLogo Build Status Pod Version Carthage compatible

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS & watchOS.

 

Hello World:

// Create and/or Open the database file
let db = YapDatabase()

// Configure database:
// We're going to store String's in the collection "test".
// To store custom classes/structs, just implement Swift's Codable protocol.
db.registerCodableSerialization(String.self, forCollection: "test")

// Get a connection to the database
// (You can have multiple connections for concurrency.)
let connection = db.newConnection()

// Write an item to the database
connection.readWrite {(transaction) in
  transaction.setObject("hello", forKey: "world", inCollection: "test")
}

// Read it back
connection.read {(transaction) in
  let str = transaction.object(forKey: "world", inCollection: "test") as? String
  // str == "hello"
}

 

YapDB has the following features:

  • Concurrency. You can read from the database while another thread is simultaneously making modifications to the database. So you never have to worry about blocking the main thread, and you can easily write to the database on a background thread. And, of course, you can read from the database on multiple threads simultaneously.
  • Built-In Caching. A configurable object cache is built-in. Of course sqlite has caching too. But it's caching raw serialized bytes, and we're dealing with objects. So having a built-in cache means you can skip the deserialization process, and get your objects much faster.
  • Metadata. Ever wanted to store extra data along with your object? Like maybe a timestamp of when it was downloaded. Or a fully separate but related object? You're in luck. Metadata support comes standard. Along with its own separate configurable cache too!
  • Views. Need to filter, group & sort your data? No problem. YapDatabase comes with Views. And you don't even need to write esoteric SQL queries. Views work using closures, so you just provide a bit of native code. Plus they automatically update themselves, and they make animating tables super easy.
  • Secondary Indexing. Speed up your queries by indexing important properties. And then use SQL style queries to quickly find your items.
  • Full Text Search. Built atop sqlite's FTS module (contributed by google), you can add extremely speedy searching to your app with minimal effort.
  • Relationships. You can setup relationships between objects and even configure cascading delete rules.
  • Hooks. Perform custom app-specific logic when certain events take place, such as an object being modified or deleted.
  • Sync. Support for syncing with Apple's CloudKit is available out of the box. There's even a fully functioning example project that demonstrates writing a syncing Todo app.
  • Extensions. More than just a key/value store, YapDatabase comes with an extensions architecture built-in. You can even create your own extensions.
  • Performance. Fetch thousands of objects on the main thread without dropping a frame.

See what the API looks like in "hello world" for YapDatabase
Learn more by visiting the wiki

Issues
  • Integration with SQLCipher for Encryption

    Integration with SQLCipher for Encryption

    Hi,

    Would it be possible to use SQLCipher (http://www.sqlcipher.net) instead of the built-in SQLite engine? I don't see why not, but I'm just asking for clarification.

    documentation 
    opened by brendand 24
  • Creating a 'work' queue

    Creating a 'work' queue

    I wanted to use Yap to create a sort of persistent work queue.

    The example I'm thinking of is a messaging app. Each message moves through multiple 'states' like being encrypted, sending to the server, and handling error cases.

    So in this case the 'encryption listener' would be on the end of queue for messages needing encryption. Then once encrypted they would be stored back into yap and marked for needing sending. And then the 'sending listener' would pick up the message and send it over the wire. This helps us in the case where the device is offline so we don't loose any messages or are unsure of the messages state.

    My question is what's the best yap tool for the job? It seems Views would be the closest even if they have a few other features that wouldn't be necessary. Or would it be worthwhile to create a new extension for this?

    opened by davidchiles 21
  • adding initWithFilter:sort:view initializer for dynamic groups

    adding initWithFilter:sort:view initializer for dynamic groups

    Here's a stab at the dynamic groups discussed in #34. I don't think this pull request is ready, I haven't tested it manually or written unit tests. Will work on those more tonight.

    opened by jonnolen 21
  • Task/multiprocess

    Task/multiprocess

    This is a first version to allow YapDatabase to work across multiple processes, you have to set the enableMultiprocessSupport option when creating the database. You can add a CrossProcessNotifier extension to be notified when another process has modified the database.

    Allowing the database to work across process requires us to disable a few optimizations when the user has enabled multiprocess support. The optimizations are still available when in single process mode

    @robbiehanson here is a summary of changes, would be glad if you could comment on those

    Summary of changes

    • added a busy_handler when creating the database to make sure we can open several databases in multiprocess mode (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-c9a9379c637725775619d9e0b7933ca7R75)
    • added a enableMultiprocessSupport option to database (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-2e3be8a8d3931c503fa36d74f2a407e9R273)
    • we read the last snapshot from the database instead, instead of restarting from 0 (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-c9a9379c637725775619d9e0b7933ca7R1350)
    • replaced busy_timeout with a busy_handler which loops and sleep 50ms, outputs a log each 4 cycles if the lock was not acquired (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-4fc49c6d91fb2d5322f8ee0387c2f447R72)
    • updated preReadTransaction (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-4fc49c6d91fb2d5322f8ee0387c2f447R2157)
      • added a flag || isMultiprocess to force reading the latest snapshot number from the database file (instead of the last version from the singleton YapDatabase object)
      • when we get the changeset, if we miss one snapshot number in the list of changesets, we return nil instead of the array of changeset, and we clear the cache of the connection and all its extensions
      • we do this by counting the number of relevantChangesets which should match the increase in the snapshot number maxSnapshot - connectionSnapshot
      • after flushing memory, we still update the snapshot of the current transaction to the one that we read from the database
      • then do we also need to update the global [database snapshot] version? when should we update this one? there might be a case where the current connection was just updated from the database file, so it is > to the one in [database snapshot]
    • updated preReadWriteTransaction (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-4fc49c6d91fb2d5322f8ee0387c2f447R2442)
      • replaced beginTransaction with beginImmediateTransaction to acquire the lock if we are in multiprocess mode, so there is no concurrent readTransaction while doing a writeTransaction, which would cause issues (allowing read while there is a write transaction would require to extend the race-condition check to the multiprocess case, which would be complex)
      • in multiprocess mode, we force reading the current snapshot from the database file, and we update with changesets or clean cache if one is missing
    • updated postReadWriteTransaction
      • when a readWrite connection makes changes and publishes a changeset, if it detected that the database was externally modified, it sends a changeset with the YapDatabaseModifiedExternallyKey set to TRUE to notify other connections and extensions that they should clean their cache
    • added a CrossProcessNotification extension that allows to receive a YapDatabaseModifiedExternallyNotification when another process updates the database (it uses an identifier so you can have several databases with different identifiers if needed), but this does not transmit the changeset (https://github.com/yapstudios/YapDatabase/pull/283/files#diff-0fa70ef80dace0725d7786e5ac3cb17aR20)
    • YapDatabaseModifiedNotification: right now we send changesets cross-process, so we don't send this modification when the database has been externally modified
    • when a changeset with the YapDatabaseModifiedExternallyKey is sent, methods like hasChangeForCollection, hasChangeForKey, all respond TRUE
    • when updating from a changeset (YapDatabaseConnection.noteCommitedChangeset), if changeset.snapshot != connection.snapshot + 1, we flush the cache, then update the changeset
    • QUESTION: https://github.com/yapstudios/YapDatabase/pull/283/files#diff-4fc49c6d91fb2d5322f8ee0387c2f447R327
    • QUESTION: what is the use of YPDBLogTrace and should we remove this line https://github.com/yapstudios/YapDatabase/pull/283/files#diff-cdbb67ebc7a257151869cc4413f1dc9aR146

    You can see an example https://github.com/yapstudios/YapDatabase/pull/283/files#diff-4a13c0a0aa202a99f4ebe0ab5d3e6175R20

    NOTE: right now the ModifiedExternally notification works by sending the pid as payload in libnotify, so if the current process has the same pid, it does not send the notification, and only other processes send it. Another way to go about it would be to send the snapshot number as payload, and each process check whether its [database snapshot] has the same value, otherwise it sends a ModifiedExternally notification (so for instance if the database instance had the time to update before receiving the libnotify message, we don't have to send another ModifiedExternally notification since the database was already updated)

    opened by maelp 19
  • Dynamic view groups?

    Dynamic view groups?

    Hi, I'm in the process of migrating an app over from core data to YapDatabase. I'm currently using Views to replace my NSFetchedResultsController and I've run into a snag. I have a list of events that are grouped by day. So I need a section, or group, for each day for which there is an event. The problem is that mappings require you to know beforehand the names of all the groups. Is there a way to do this using views and mappings?

    Thanks.

    opened by lancep 18
  • Pervasive YapDatabaseViewConnection dealloc crash

    Pervasive YapDatabaseViewConnection dealloc crash

    Hi Robbie and others,

    We're seeing a very odd SIGSEGV crash that makes up about 90% of our app's crashes right now. The stack trace looks like this:

    0 CoreFoundation 0x0000000183a813d4 -[__NSArrayM dealloc] + 140 1 CoreFoundation 0x0000000183a82784 -[__NSDictionaryM dealloc] + 148 2 libobjc.A.dylib 0x0000000183202b54 object_cxxDestructFromClass(objc_object_, objc_class_) + 144 3 libobjc.A.dylib 0x000000018320e080 objc_destructInstance + 88 4 libobjc.A.dylib 0x000000018320e0e0 object_dispose + 24 5 YapDatabase 0x00000001027ba65c -YapDatabaseViewConnection .cxx_destruct 6 libobjc.A.dylib 0x0000000183202b54 object_cxxDestructFromClass(objc_object_, objc_class_) + 144 7 libobjc.A.dylib 0x000000018320e080 objc_destructInstance + 88 8 libobjc.A.dylib 0x000000018320e0e0 object_dispose + 24 9 YapDatabase 0x00000001027b6c40 -YapDatabaseViewConnection dealloc 10 CoreFoundation 0x0000000183ac7984 -[__NSDictionaryM removeAllObjects] + 508 11 YapDatabase 0x000000010273d528 -YapDatabaseConnection dealloc 12 CoreFoundation 0x0000000183ae51ac -[NSSharedKeyDictionary dealloc] + 84 13 Foundation 0x000000018446aee4 -[NSConcreteNotification dealloc] + 84

    The only likely candidate we've found for that NSMutableDictionary instance that lines up with the stack trace is group_pagesMetadata_dict, which contains arrays of YapDatabaseViewPageMetadata objects. Our current line of thinking is that a deallocation of the YapDatabaseViewState ivar of YapDatabaseViewConnection deallocates the dictionary instance, and then an object under a pointer in one of the arrays is being freed. Very weird considering all of this is ARC managed, and that removals from the YapDatabaseViewPageMetadata arrays are controlled through the API.

    Any thoughts on where to look next would be most appreciated. We've so far been unable to identify a place where a non-arc-like release might occur. It's also worth noting that our interactions with YapDatabase's API are entirely from Swift - possibly leaving the door open for things like group names (Strings) to have lingering swifty memory management

    opened by pwerry 16
  • CocoaLumberjack

    CocoaLumberjack

    It would be great if YapDatabase did not force me to include CocoaLumberjack. It may be useful for the project itself but I do not wish to include it in my applications.

    opened by calebd 16
  • Fast searching using data, not keys

    Fast searching using data, not keys

    Hi,

    If you needed to do fast searching for specific values, not just a key lookup, how would you accomplish that? For example, doing a substring search for "Term" within a Movies database and having it return a list of movies with the Movie Titles that contain the term "Term".

    For example:

    Movie Title:

    The Terminator Terminator 2: Judgement Day The Terminal

    Right now I'm using SQLCipher with the FTS3 full text search engine in SQLite. But there's an overhead in maintaining the separate FTS search engine that I'd like to remove.

    I'm assuming that your system would require me to fetch all data into memory and then do an in-memory filter using something like an NSPredicate. There would be a big memory and performance impact in doing so I would think.

    opened by brendand 15
  • Can I make a complex SELECT, such as LEFT JOIN , INNER JOIN

    Can I make a complex SELECT, such as LEFT JOIN , INNER JOIN

    Hello,Can I make a complex SELECT, such as LEFT JOIN , INNER JOIN , LIMIT, and so on

    opened by KorolZhu 14
  • build with carthage

    build with carthage

    when i using carthage, there was no macos scheme in YapDatabase.xcodeproj, can you add it to your todo list, please? (sorry. my english, perhaps, is coarse)

    opened by prinsun 14
  • Multiple Search Handles > Single View

    Multiple Search Handles > Single View

    I'm theorising my solution for implementing Full Text Search, and I had a few questions to ensure my understanding of the module is correct.

    Full Disclosure; I have not tried writing or experimenting with any code.

    Models

    I have two distinct model objects which I need to index for using with YapDB's FTS module.

    
    struct Foo {
        let identifier: String
        let title: String
        let keywords: [String]
    }
    
    struct Bar {
        let identifier: String
        let title: String
        let author: String   
        let summary: String?
    }
    

    A distinct merged struct can be created from the above like so:

    enum SearchableType {
        case Foo
        case Bar
    }
    
    struct Searchable {
        let identifier: String
        let title: String
        let keywords: [String]?
        let author: String?
        let summary: String?
        let type: SearchableType
    }
    

    View

    For my search view, I need to show both matching types (Foo and Bar) based on the user's input.

    Question

    As per the documentation for FTS, the YapDatabaseFullTextSearch initialiser takes a columns argument with propertiesToIndex as its value.

    In my case, title and identifier are the only common property across the two models. What the documentation is unclear about are conditional values for the columns.

    A: Assuming that conditional values are unsupported (i.e. the FTS module would not like NULL values in these columns), should I create two separate handlers and YapDatabaseFullTextSearch extensions for each struct (and forego the merged struct)?

    B: If conditional values are supported, do I need to take additional care when writing the queries for fetching results? Repurposing one of the examples from the documentation:

    // struct.author matches: john
    // struct.summary contains phrase: "board meeting"
    
    query = "author:john summary:\"board meeting\""
    ftsTransaction.enumerateKeysAndObjects(matching: query) { (collection, key, obj, stop) in
        // ...
    }
    

    Does the FTS module take care of only looking at non-NULL values in its table? Or do I need to modify the above query to explicitly tell it to skip over NULL values?

    opened by dezinezync 0
  • Fix nullability for yap database view sorting block

    Fix nullability for yap database view sorting block

    TL;DR YapDatabaseViewSortingBlock declared as returning nonnull objects but in fact can return nil in some cases

    Details in this comment https://github.com/yapstudios/YapDatabase/issues/459#issuecomment-812550132

    opened by danillahtin 0
  • Prevent from bad access bcz of object still nil

    Prevent from bad access bcz of object still nil

    Don't know this kind of handling is okay or not, but it actually fixed my app crashing from bad access!

    opened by ethan1022 0
  • SQLCipher commercial licence

    SQLCipher commercial licence

    Is there possibility to integrate SQLCipher with commercial licence? Or only community edition is available?

    opened by PiotrBogus 0
  • hello world does not  wirte to disk ?

    hello world does not wirte to disk ?

    "hello world" code can run, but when I terminal my app and just run the code below, str is nil

    let db = YapDatabase() db.registerCodableSerialization(String.self, forCollection: "test")

    let connection = db.newConnection()

    //connection.readWrite {(transaction) in // transaction.setObject("hello", forKey: "world", inCollection: "test") //}

    connection.read {(transaction) in let str = transaction.object(forKey: "world", inCollection: "test") as? String }

    opened by expll 0
  • Relationship edge inconsistency

    Relationship edge inconsistency

    I'm having an issue where relationships are causing the wrong object to be deleted. Unfortunately this is in a very complex code path, so I can't give any steps to reproduce the behaviour, but I can report my observations. While I can't guarantee that there are no bugs in our code, the behaviour I'm observing from Yap does seem inconsistent.

    This is a pretty serious bug because it can cause seemingly random data deletions in a Yap app that uses relationships.

    Mechanism

    I tracked this down to [YapDatabaseTransaction removeObjectForCollectionKey:withRowId:] being called with the wrong row ID. I added the following code block to the start of the method and put a breakpoint in it.

        YapCollectionKey *storedKey = [self collectionKeyForRowid:rowid];
        if (![storedKey isEqual:cacheKey]) {
            int64_t correctRowID = 0;
            BOOL result = [self getRowid:&correctRowID forCollectionKey:cacheKey];
            
            NSLog(@"====rssr yap is removing rowid %ld. Caller thinks the key is %@ but it's actually %@. The correct rowid to delete is most likely %ld (fetch rowid result was %@)", rowid, cacheKey, storedKey, correctRowID, result ? @"TRUE": @"FALSE");
        }
    

    When the issue happens I get the following log:

    2021-01-14 18:14:12.558989-0500 Daylite[2351:1444308] ====rssr yap is removing rowid 9691. Caller thinks the key is <YapCollectionKey collection(RemoteMutationsReferences) key(72D89780-77D6-436F-BEEE-5024AA600D2F_1)> but it's actually <YapCollectionKey collection(accounts) key(6)>. The correct rowid to delete is most likely 0 (fetch rowid result was FALSE)

    So it looks like the wrong row id is stored in the edge (it doesn't match the destination key)

    The call to remove the object is in YapDatabaseRelationshipTransaction.m, at the end of "Enumerate all edges where source node is the deleted node" around line 3727:

    								[databaseRwTransaction removeObjectForKey:edge->destinationKey
    								                             inCollection:edge->destinationCollection
    								                                withRowid:edge->destinationRowid];
    

    My Steps To Reproduce

    The workflow in our app is so complicated that it isn't possible to glean the real requirements for this issue from them, but I think there is some information about the preconditions.

    1. View the messages list (it's backed by a YapDatabaseAutoView).
    2. Start swiping to delete messages from the list.
    3. Each deletion will trigger a server sync that will push the deletion up to the server and then fetch any new data (There does not need to be any new data to trigger the bug however).
    4. After a certain number of messages are deleted one of them will come back. We do have code that will read back a deleted object if we fail to push the deletion to the server, but I haven't verified that this is the cause of the object coming back (due to some of the issues listed below).
    5. Swipe to delete the same message again. This second deletion succeeds locally, but when pushed to the server it causes the entire account object to be deleted while cleaning up some unrelated relationships.

    Notes & Observations

    1. In my debug code above I try to fetch the correct rowID from the CollectionKey and it comes back as 0, so I'm guessing that the intended target of the edge has already been deleted.
    2. I don't think that the bug is caused when the edge is firing in step 5, I believe that it's actually in step 4 when the object comes back. If I quit the application between steps 4 and 5 the message that 'comes back' is not there, so it looks like it wasn't fetched back by our application and persisted, it's an in memory issue.
    3. If you look at the output of the debug log I put above it tries to resolve the real rowid of the destination, and it comes back as 0. I believe that the 'real' target of the relationship has already been deleted, but the machinery in edge processing doesn't realize this because of the rowid issue. (That's just a guess at this point). I have stepped through the call to fetch the rowid and the zero doesn't come from the cache and it does do a database query to attempt to retrieve the rowid.
    4. I have code that performs a rollback in some cases, but I did not see the log from this code at all in some cases where this issue has occurred.
    5. The edge that is firing was not created in the same transaction as the one that is deleting everything.
    6. While investigaing this we have noticed a few other inconsistencies where some of our objects were in an unexpected state. Broken references between objects that are updated in a single transaction. We weren't able to fully rule out a bug in our code, so I don't know if that issue is related to this one.
    7. If the message that 'came back' was caused by our sync code, the new message would have been assigned a new id, since we assign ids to objects sequentially and don't re-use them.
    8. We upgraded our version of Yap recently, and commits b3d459964f2fbd55a8ce0e9f59f97f37551a11dc and dda1ecea8d3292facb9db7d989418875ebc07c70 are both new to our repo. I don't believe that we had this problem before, but it is a bit hard to tell if this issue is happening or not.
    9. This issue is heavily timing dependant. I added a lot of logs to both our code and to Yap and the issue stopped happening. Clearly this is exposing an issue in some special case for concurrent code that doesn't get hit all the time.
    10. I can reproduce this issue with a debug build of Yap.
    11. The object that is incorrectly targeted by the edge is the root of our object hierarchy. Not only does this trigger the deletion of everything, I suspect that it is the first row in our database, which may be a clue to the mechanism of operation.

    Workaround

    As a workaround I'm going to try removing the edge that is firing and deleting the wrong objects. We don't need this particular relationship anymore, so hopefully it will prevent this issue. But that seems like a band-aid solution, since the underlying problem is likely to remain. I'm a bit worried about trusting the relationship extension.

    opened by MythicLionMan 1
  • EXC_BAD_ACCESS (code=1, address=0x0) on asyncRegisterExtension

    EXC_BAD_ACCESS (code=1, address=0x0) on asyncRegisterExtension

    image

    If I call asyncRegisterExtension for storage with not registered serialisation for some persisted object, YapDatabase will throw unprocessed exception.

    I want to perform lazy serialisation registration for my objects.

    opened by DmitriyBagrov92 1
  • How to load sqlite fts extension?

    How to load sqlite fts extension?

    Hi, I build a fts5 tokenizer follow this https://www.sqlite.org/fts5.html#custom_tokenizers, how can I load it in YapDatabase ?

    This is my extension: https://github.com/wangfenjin/simple

    Thanks

    opened by wangfenjin 0
  • Q: FilteringView rerun after Relationship modification?

    Q: FilteringView rerun after Relationship modification?

    I have a filtering view that queries for relationship edges in its filtering block. Is there any mechanism that would trigger a rerun of the filtering block when an edge affecting a certain element in one of the whitelisted collections is (manually) added or removed — or do I need to bump the version tag of all filter views after a (manual) edge operation?

    opened by mickeyl 0
  • YapDatabase cannot be created twice at same path.

    YapDatabase cannot be created twice at same path.

    It is an API error to create two instances of YapDatbase that reference the same database file. To enforce this YapDatabaseManager registers the normalized path of all database instances, and releases them when the instance is dealloced. When a new instance is created it checks the registry, and if another instance has registered the path then it throws an exception.

    There is a bug in this procedure where a registered path can 'leak' and prevent a new instance from being allocated with the same path despite the fact that the original instance has been released.

    Steps to reproduce

    1. Create a YapDatabase instance with a path that is relative to '/private'.
    2. Profit from said instance…
    3. Release the instance.
    4. Delete the database files that were created in step 1.
    5. Create a new instance with the same same path and in the same running application as step 1.

    Expected behaviour

    The second database instance is created and useable.

    Actual behaviour

    Creation of the second instance fails because the database path was not released in step 4 (the path is still visible in the 'registeredPaths' set).

    Analysis

    The documentation for 'stringByStandardizingPath' states that it has different behaviour for paths that have '/private' as their root based on the existence of the file reference by the path in the file system. If such a path still points to a valid file after removing the '/private' prefix, the prefix is removed (under the assumption that it is the same file). (Oddly enough the documentation for the Swift version of the method is not so detailed, even though it has the same behaviour).

    Thus if Yap registers the normalized path before the database is created, when it is released and the path is normalized again it attempts to deregister a path without the '/private' prefix, while it registered one that does have the prefix, so the registration leaks. The next attempt to connect will succeed if the file remains, since the new normalized path won't have the prefix either. But if the database is deleted the new normalized path will have the prefix, and since it is still registered it will throw an exception.

    Workaround

    An easy workaround is to 'touch' the database file before creating a YapDatabase instance. If there is no existing database file create an empty file to ensure that normalization is consistent before and after the database are created. sqlite will happily create a database on top of an empty file.

    Fix

    There are a few ways to fix this.

    • Use the workaround and create an empty file within YapDatabase init before path normalization.
    • 'Hack' the path by stripping the '/private' prefix off manually, or normalize it with a different API that doesn't consult the filesystem. (but this doesn't fix lookup issues, like a path with and without the prefix, and it isn't very future proof since it has to anticipate the behaviour of stringByStandardizingPath which may change in the future).
    • Do not normalize the path again when deregistering the database to ensure that it is consistent with the path used on launch. (but this doesn't fix lookup issues, like a path with and without the prefix).
    • Use a map table instead of a set with the YapDatabase instance as the key (or some other unique value derived from it), to ensure that the path associated with an instance is always the path that is released when it is dealloced (but this doesn't fix lookup issues, like a path with and without the prefix).
    • Don't check for duplicate paths at all since it is a bit error prone.
    opened by MythicLionMan 1
Releases(2.6.3)
Owner
Yap Studios
Yap Studios is a digital development agency located in Silicon Valley. We craft incredible apps for leading brands worldwide.
Yap Studios
A Cocoa / Objective-C wrapper around SQLite

FMDB v2.7 This is an Objective-C wrapper around SQLite. The FMDB Mailing List: https://groups.google.com/group/fmdb Read the SQLite FAQ: https://www.s

August 13.6k Sep 21, 2021
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS &

Yap Studios 3.3k Sep 14, 2021
Official home of the DB Browser for SQLite (DB4S) project. Previously known as "SQLite Database Browser" and "Database Browser for SQLite". Website at:

DB Browser for SQLite What it is DB Browser for SQLite (DB4S) is a high quality, visual, open source tool to create, design, and edit database files c

null 15.4k Sep 24, 2021
Mac Native Mongodb Client

System Requirements Mac OS X (10.8.x, 10.9.x, 10.10.x), intel 64bit based. Download HERE Or you can compile it yourself using Xcode Build Just build i

Jérôme Lebel 2.5k Sep 12, 2021
WCDB is a cross-platform database framework developed by WeChat.

WCDB 中文版本请参看这里 WCDB is an efficient, complete, easy-to-use mobile database framework used in the WeChat application. It's currently available on iOS,

Tencent 9.2k Sep 16, 2021
Native MongoDB driver for Swift, written in Swift

Installation | Tutorial | Basic usage | About BSON | Codable | Community | How to help A fast, pure swift MongoDB driver based on Swift NIO built for

null 617 Sep 20, 2021
Realm is a mobile database: a replacement for Core Data & SQLite

Realm is a mobile database that runs directly inside phones, tablets or wearables. This repository holds the source code for the iOS, macOS, tvOS & wa

Realm 14.6k Sep 16, 2021
CoreData/Realm sweet wrapper written in Swift

What is SugarRecord? SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way. Than

Modo 2.1k Aug 18, 2021
Free universal database tool and SQL client

DBeaver Free multi-platform database tool for developers, SQL programmers, database administrators and analysts. Supports any database which has JDBC

DBeaver 22.2k Sep 16, 2021
Unrealm is an extension on RealmCocoa, which enables Swift native types to be saved in Realm.

Unrealm enables you to easily store Swift native Classes, Structs and Enums into Realm . Stop inheriting from Object! Go for Protocol-Oriented program

Artur  Mkrtchyan 459 Sep 14, 2021
Sync Realm Database with CloudKit

IceCream helps you sync Realm Database with CloudKit. It works like magic! Features Realm Database Off-line First Thread Safety Reactive Programming O

Soledad 1.6k Sep 18, 2021
A library that provides the ability to import/export Realm files from a variety of data container formats.

Realm Converter Realm Converter is an open source software utility framework to make it easier to get data both in and out of Realm. It has been built

Realm 204 Jul 28, 2021
💻 Medis is a beautiful, easy-to-use Mac database management application for Redis.

Medis Medis is a beautiful, easy-to-use Redis management application built on the modern web with Electron, React, and Redux. It's powered by many awe

Zihua Li 10.4k Sep 14, 2021
:wrench: Cross-platform GUI management tool for Redis

RDM Install & Run | Quick Start | Native Formatters | Development Guide | Known issues | Telegram Chat Open source cross-platform Desktop Manager for

Igor Malinovskiy 19k Sep 24, 2021
MySQL/MariaDB database management for macOS

Sequel Ace Sequel Ace is the "sequel" to longtime macOS tool Sequel Pro. Sequel Ace is a fast, easy-to-use Mac database management application for wor

Sequel-Ace 3.6k Sep 18, 2021
The easiest way to get started with PostgreSQL on the Mac

Postgres.app The easiest way to run PostgreSQL on your Mac Includes everything you need to get started with PostgreSQL Comes with a pretty GUI to star

Postgres.app 6k Sep 23, 2021
MySQL/MariaDB database management for macOS

Sequel Pro Sequel Pro is a fast, easy-to-use Mac database management application for working with MySQL & MariaDB databases. You can find more details

Sequel Pro 8.5k Sep 19, 2021
The easiest way to get started with MongoDB on the Mac

mongoDB.app The easiest way to get started with mongoDB on the Mac. Just download, drag to the applications folder, and double-click. Download Version

Giovanni Collazo 472 Sep 16, 2021