Coder Social home page Coder Social logo

sworm's Introduction

Swift ORM

SWORM

Features

  1. Pure swift objects - no more subclasses of NSManagedObject
  2. Extensible attribute system - store any type in CoreData storage by implementing a simple protocol in type extension
  3. Strongly typed data queries
  4. Progressive migrations

Motivation

CoreData is hard. It was originally designed as a data layer for applications with a focus on I/O performance, but hardware has become more powerful over time and the complexity of CoreData still persists (lol). In modern applications, building CoreData-based data layer is expensive and often unreasonable decision.

Even the NSPersistentContainer doesn't relieve us of the need to keep track of the lifecycle of the managed objects associated with the context and remember to read / write on the context queue. In addition, an application often has a second set of data models, similar to managed objects and code for converting between the two sets of models.

Apple is aware of all of this and in modern guides prefers data persistence based on Codable models.

At the same time, CoreData has many advantages - a powerful visual editor for data models, automatic migrations, a simplified (compared to SQL) query system, secure multi-threaded access to data out of the box, and so on.

Sworm is a tool that hides the complexity of CoreData from the developer, but keeps the advantages.

How to use

Basic usage

Attributes

Queries

Read and write your data graph

Proper setup of PersistentContainer

Progressive migrations

Examples

See tests

Installation

Use SPM:

dependencies: [
    .package(url: "https://github.com/prisma-ai/Sworm.git", .upToNextMajor(from: "1.0.0"))
]

sworm's People

Contributors

geor-kasapidi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sworm's Issues

Q: How to update an existing item?

Just for better understanding: There is no "update" method in Sworm, just insert and delete. How is an existing object updated?

My use case is an editor sheet, that provides "cancel" and "save" operations. This includes (a) the need for a rollback, and (b) the need for an update.

The missing "update" operation may be interpreted in a way that Sworm updates "on-the-fly" whenever an attribute changes.

So, how does Sworm work in this context? How should an update intentionally be handled?

delete operation throws build error

I created a generic repository that gets a PersistentContainer injected (I followed you instructions up to there):

public class BaseRepository<T>: Repository where T: ManagedObjectConvertible {
	
	public var persistentContainer: PersistentContainer
	
	init(persistentContainer: PersistentContainer) {
		
		self.persistentContainer = persistentContainer
	}
	
	public func allItems() throws -> [T] {

		try self.persistentContainer.perform { context in
			
			try context.fetch(T.all).map { try $0.decode() }
		}
	}
	
	public func create(_ item: T) throws {
		try self.persistentContainer.perform { context in
			
			try context.insert(item)
		}
	}
	
	public func remove(_ item: T) throws {
		try self.persistentContainer.perform { context in
			
			try context.delete(item)
		}
	}
} 

However, the "remove" function where the delete operation on the context is used, throws a build error:

Cannot convert value of type 'T' to expected argument type 'ManagedObject<PlainObject>'

I tried around, but I cannot figure out how to fix this. Do you have any ideas?

The calling part looks like this (a repository factory):

	public func makeRepository<R>(for storyType: StoreType) -> R where R: Repository {

		switch storyType {
			case .country:
				return BaseRepository<Country>(persistentContainer: persistentContainer) as! R
				
			case .location:
				return BaseRepository<Location>(persistentContainer: persistentContainer) as! R
		}
	}

where

public protocol Repository {
	associatedtype T: ManagedObjectConvertible
	
	var persistentContainer: PersistentContainer { get }
	
	func allItems() throws -> [T]
}

Thanks for your support!

Relations cannot be set

Hello again,

I'm struggling with relations and their handling. The use case is:

  • There are companies, that have a many-to-many-relationship with persons
  • I create a company, and I create some persons.
  • I want to assign the persons to the company.

Actually, pretty simple.

The test case is:

		let domainStore: DomainStore = .init(kind: .temporary)

		let companyStore = GenericAPI<Company>(domainStore: domainStore)
		let personStore = GenericAPI<Person>(domainStore: domainStore)
		
		companyStore.refresh()
		personStore.refresh()
		
		XCTAssertEqual(companyStore.list, [])
		XCTAssertEqual(personStore.list, [])

		// Add some persons.
		var new1: Person = personStore.add()
		new1.name = "Paul"
		personStore.save(new1)
		
		var new2: Person = personStore.add()
		new2.name = "Peter"
		personStore.save(new2)
		
		XCTAssertEqual(personStore.list.count, 2)
		
		// Add a company.
		var new3: Company = companyStore.add()
		new3.name = "The AG"
		companyStore.save(new3)
				
		XCTAssertEqual(companyStore.list.count, 1)
		XCTAssertEqual(companyStore.list[0].name, "The AG")
		
		new3.persons = [new1, new2]

The error occurts in the last line, where the compiler says: "Value of type Company has no member persons."

Now, Company is defined such:

public struct Company: DomainType {
	
	public init(uuid: UUID, name: String) {
		self.uuid = uuid
		self.name = name
	}
	
	public var uuid: UUID
	public var name: String
}

extension Company {
	
	public static var idKeyPath: KeyPath<Company, UUID> {
		\.uuid
	}
	
	public init() {
		self.uuid = .init()
		self.name = .init()
	}
	
	public static let entityName = "CompanyMO"
	
	public static let attributes: Set<Attribute<Company>> = [
		
		.init(\.uuid, "uuid"),
		.init(\.name, "name"),
	]
	
	public struct Relations {
		public init() {}
		public let persons = ToManyRelation<Person>("persons")
	}
	
	public static let relations = Relations()
}

So, actually everything as stated in your directions and test cases, where a Book has authors.

The public init() was kind of desperation task, cause I thought it may be a visiblity problem (the domain types are defined in a package), but it did not change anything.

So it seems I'm doing something wrong - but what?

Thanks in advance for your help!

Key path value type cannot be converted to contextual type

I'm following the guidance in basic usage docs and I have hit a snag with the package.

The following throws a compile time error of Key path value type 'WritableKeyPath<Forecast, Date>' cannot be converted to contextual type 'KeyPath<Forecast, Date>'.

Any tips?

XCode 14.1 targeting iOS 16

import Foundation
import Sworm

struct Forecast {
    let date: Date    
    let area: Area
    
    init(date: Date, area: Area) {
        self.date = date
        self.area = area
    }
}

extension Forecast : ManagedObjectConvertible {
    init() {
    }
    
    static let entityName = "Forecast"

    static let attributes: Set<Attribute<Forecast>> = [
        .init(\.date, "date") // Key path value type 'WritableKeyPath<Forecast, Date>' cannot be converted to contextual type 'KeyPath<Forecast, Date>'
    ]

    struct Relations {
        let area = ToOneRelation<Area>("area")
    }

    static let relations = Relations()
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.