From d09c2d041910f9201be0e20cd3fdf8eace66cbaa Mon Sep 17 00:00:00 2001 From: Uwe <13865709+greenrobot-team@users.noreply.github.com> Date: Wed, 16 Oct 2024 07:39:11 +0200 Subject: [PATCH] ObjectBox Swift database 4.0.1 --- CHANGELOG.md | 13 + Package.swift | 4 +- README.md | 1 + Source/external/objectbox-swift-generator | 2 +- Source/fetch_dependencies.command | 4 +- Source/ios-framework/CodeGenTests/README.md | 4 + .../CodeGenTests/RunToolTests.sh | 2 + .../entity-info/EntityInfo.generated36.swift | 298 +++++++++++++ .../entity-info/EntityInfo.generated37.swift | 325 +++++++++++++++ .../entity-info/EntityInfo.generated38.swift | 316 ++++++++++++++ .../entity-info/EntityInfo.generated39.swift | 390 +++++++++++++++++ .../entity-info/EntityInfo.generated40.swift | 391 ++++++++++++++++++ .../expected/messages/messages41.log | 1 - .../expected/schema-dump/schemaDump16.txt | 1 - .../expected/schema-dump/schemaDump17.txt | 1 - .../expected/schema-dump/schemaDump26.txt | 1 - .../expected/schema-dump/schemaDump30.txt | 4 - .../expected/schema-dump/schemaDump59.txt | 2 - .../GeneratedStoreInitializer.swift | 19 +- .../CommonSource/Internal/objectbox-c-sync.h | 26 +- .../CommonSource/Internal/objectbox-c.h | 11 +- Source/ios-framework/CommonSource/Store.swift | 2 +- .../CommonTests/StoreTests.swift | 6 +- Source/ios-framework/README.md | 6 +- Source/ios-framework/docs/jazzy.yaml | 2 +- cartspec/ObjectBox.json | 1 + 26 files changed, 1801 insertions(+), 32 deletions(-) create mode 100644 Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated36.swift create mode 100644 Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated37.swift create mode 100644 Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated38.swift create mode 100644 Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated39.swift create mode 100644 Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated40.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 26d037a..16132d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ Notable changes to the ObjectBox Swift library. For more insights into what changed in the ObjectBox C++ core, [check the ObjectBox C changelog](https://github.com/objectbox/objectbox-c/blob/main/CHANGELOG.md). +## 4.0.1 - 2024-10-16 + +- Built with Xcode 15.0.1 and Swift 5.9. +- Make closing the Store more robust. In addition to transactions, it also waits for ongoing queries. This is just an + additional safety net. Your apps should still make sure to finish all Store operations, like queries, before closing it. +- Generator: no longer print a `Mapping not found` warning when an entity class uses `ToMany`. +- Some minor vector search performance improvements. +- Update to [ObjectBox C 4.0.2](https://github.com/objectbox/objectbox-c/releases/tag/v4.0.2). + +### Sync + +- **Fix a serious regression, please update as soon as possible.** + ## 4.0.0 - 2024-07-22 **ObjectBox now supports [Vector Search](https://docs.objectbox.io/ann-vector-search)** to enable efficient similarity searches. diff --git a/Package.swift b/Package.swift index abe21ab..b269349 100644 --- a/Package.swift +++ b/Package.swift @@ -16,8 +16,8 @@ let package = Package( targets: [ .binaryTarget( name: "ObjectBox", - url: "https://github.com/objectbox/objectbox-swift/releases/download/v4.0.0/ObjectBox-xcframework-4.0.0.zip", - checksum: "2bed7b8b87dd46dda64fa1f5e7a0b1df87908a783690fda09c6dc943a01a32e5" + url: "https://github.com/objectbox/objectbox-swift/releases/download/v4.0.1/ObjectBox-xcframework-4.0.1.zip", + checksum: "02a0f686ced7488a9afe312e3b1a7cac634848709bd04cd904a3a5fa26ec8d31" ) ] ) diff --git a/README.md b/README.md index 355630a..b01f1f1 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ Here's a list of ObjectBox releases, and the Swift versions they were compiled w | ObjectBox version(s) | Swift version | |:--------------------:|:-------------:| +| 4.0.1 | 5.9 | | 4.0.0 | 5.9 | | 2.0.0 | 5.9 | | 1.9.2 | 5.9 | diff --git a/Source/external/objectbox-swift-generator b/Source/external/objectbox-swift-generator index ce1db1f..a12f629 160000 --- a/Source/external/objectbox-swift-generator +++ b/Source/external/objectbox-swift-generator @@ -1 +1 @@ -Subproject commit ce1db1fe14a07b5f441e1c6e3e1ce6bd352ebead +Subproject commit a12f6291a434ac1ae99efff7e0615ef2c07705ef diff --git a/Source/fetch_dependencies.command b/Source/fetch_dependencies.command index a8119bb..a23d081 100755 --- a/Source/fetch_dependencies.command +++ b/Source/fetch_dependencies.command @@ -10,11 +10,11 @@ set -e # objectbox-swift release version on GitHub: # https://github.com/objectbox/objectbox-swift/releases/download/v${version} -version=4.0.0 +version=4.0.1 # C library version attached to the GitHub release: # ObjectBoxCore-static-${c_version}.zip -c_version=4.0.1 +c_version=4.0.2 # Params supported by apple-build-static-libs.sh build_params="" diff --git a/Source/ios-framework/CodeGenTests/README.md b/Source/ios-framework/CodeGenTests/README.md index 0f0afbd..96dbd42 100644 --- a/Source/ios-framework/CodeGenTests/README.md +++ b/Source/ios-framework/CodeGenTests/README.md @@ -6,6 +6,10 @@ This project is used to test code generation in ObjectBox's Sourcery-descended c It will run the codegen over a given target in the project, then build and run the product. You can do whatever testing you need to do in the actual Swift code. +**Important note**: by passing the `--debug-parsetree` option to the generator in `RunToolTests.sh` +it generates **non-random, stable UIDs**. See `runCLI()` of `objectbox-swift-generator/Sourcery/main.swift`. +These are unlike (notably shorter) UIDs than are generated for a user project. + ## Running these tests These tests require a copy of ObjectBox Swift Code Generator in a known location. To get that all set up, do the following: diff --git a/Source/ios-framework/CodeGenTests/RunToolTests.sh b/Source/ios-framework/CodeGenTests/RunToolTests.sh index c9afa22..5cbd3b2 100755 --- a/Source/ios-framework/CodeGenTests/RunToolTests.sh +++ b/Source/ios-framework/CodeGenTests/RunToolTests.sh @@ -193,6 +193,8 @@ fail_codegen_target_num () { echo "// Ensure there's no leftover code from previous tests." > "$ENTITY_INFO_FILE_ACTUAL" + # Setting --debug-parsetree for the generator also makes it generate non-random UIDs, + # see objectbox-swift-generator/Sourcery/main.swift runCLI(). echo "$SOURCERY --xcode-project \"$TESTPROJECT\" --xcode-target \"ToolTestProject${2}\" --model-json \"$MODEL_FILE_ACTUAL\" --debug-parsetree \"$DUMP_FILE_ACTUAL\" --output \"${ENTITY_INFO_FILE_ACTUAL}\" --disableCache" $SOURCERY --xcode-project "$TESTPROJECT" --xcode-target "ToolTestProject${2}" --model-json "$MODEL_FILE_ACTUAL" --debug-parsetree "$DUMP_FILE_ACTUAL" --output "${ENTITY_INFO_FILE_ACTUAL}" --disableCache > "$TESTMESSAGESFILE" 2>&1 diff --git a/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated36.swift b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated36.swift new file mode 100644 index 0000000..11e012b --- /dev/null +++ b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated36.swift @@ -0,0 +1,298 @@ +// Generated using the ObjectBox Swift Generator — https://objectbox.io +// DO NOT EDIT + +// swiftlint:disable all +import ObjectBox +import Foundation + +// MARK: - Entity metadata + + +extension Author: ObjectBox.__EntityRelatable { + internal typealias EntityType = Author + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Author: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = AuthorBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Author", id: 1) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Author.self, id: 1, uid: 16640) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 14592) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 15616) + + try entityBuilder.lastProperty(id: 2, uid: 15616) + } +} + +extension Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Author.EntityBindingType`. +internal class AuthorBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Author + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Author() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + return entity + } +} + + + +extension Book: ObjectBox.__EntityRelatable { + internal typealias EntityType = Book + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Book: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = BookBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Book", id: 2) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Book.self, id: 2, uid: 20736) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 17664) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 18688) + try entityBuilder.addToManyRelation(id: 1, uid: 19712, + targetId: 1, targetUid: 16640) + + try entityBuilder.lastProperty(id: 2, uid: 18688) + } +} + +extension Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Book.authors` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.relationId(1)) } + + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.authors` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.relationId(1)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Book.EntityBindingType`. +internal class BookBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Book + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func postPut(fromEntity entity: EntityType, id: ObjectBox.Id, store: ObjectBox.Store) throws { + if entityId(of: entity) == 0 { // New object was put? Attach relations now that we have an ID. + let authors = ToMany.relation( + sourceId: EntityId(id.value), + targetBox: store.box(for: ToMany.ReferencedType.self), + relationId: 1) + if !entity.authors.isEmpty { + authors.replace(entity.authors) + } + entity.authors = authors + try entity.authors.applyToDb() + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Book() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + entity.authors = ToMany.relation( + sourceId: EntityId(entity.id.value), + targetBox: store.box(for: ToMany.ReferencedType.self), + relationId: 1) + return entity + } +} + + +/// Helper function that allows calling Enum(rawValue: value) with a nil value, which will return nil. +fileprivate func optConstruct(_ type: T.Type, rawValue: T.RawValue?) -> T? { + guard let rawValue = rawValue else { return nil } + return T(rawValue: rawValue) +} + +// MARK: - Store setup + +fileprivate func cModel() throws -> OpaquePointer { + let modelBuilder = try ObjectBox.ModelBuilder() + try Author.buildEntity(modelBuilder: modelBuilder) + try Book.buildEntity(modelBuilder: modelBuilder) + modelBuilder.lastEntity(id: 2, uid: 20736) + modelBuilder.lastRelation(id: 1, uid: 19712) + return modelBuilder.finish() +} + +extension ObjectBox.Store { + /// A store with a fully configured model. Created by the code generator with your model's metadata in place. + /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// + /// - Parameters: + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. + /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). + /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. + /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). + /// - maxReaders: The maximum number of readers. + /// "Readers" are a finite resource for which we need to define a maximum number upfront. + /// The default value is enough for most apps and usually you can ignore it completely. + /// However, if you get the maxReadersExceeded error, you should verify your + /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends + /// on number of types, relations, and usage patterns. Thus, if you are working with many threads + /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// + /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` + /// initializer, trigger code generation by building your project. + internal convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + try self.init( + model: try cModel(), + directory: directoryPath, + maxDbSizeInKByte: maxDbSizeInKByte, + fileMode: fileMode, + maxReaders: maxReaders, + readOnly: readOnly) + } +} + +// swiftlint:enable all diff --git a/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated37.swift b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated37.swift new file mode 100644 index 0000000..e969c2e --- /dev/null +++ b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated37.swift @@ -0,0 +1,325 @@ +// Generated using the ObjectBox Swift Generator — https://objectbox.io +// DO NOT EDIT + +// swiftlint:disable all +import ObjectBox +import Foundation + +// MARK: - Entity metadata + + +extension Author: ObjectBox.__EntityRelatable { + internal typealias EntityType = Author + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Author: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = AuthorBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Author", id: 1) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Author.self, id: 1, uid: 17664) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 14592) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 15616) + try entityBuilder.addToManyRelation(id: 1, uid: 16640, + targetId: 2, targetUid: 20736) + + try entityBuilder.lastProperty(id: 2, uid: 15616) + } +} + +extension Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Author.books` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.relationId(1)) } + + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.books` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.relationId(1)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Author.EntityBindingType`. +internal class AuthorBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Author + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func postPut(fromEntity entity: EntityType, id: ObjectBox.Id, store: ObjectBox.Store) throws { + if entityId(of: entity) == 0 { // New object was put? Attach relations now that we have an ID. + let books = ToMany.relation( + sourceId: EntityId(id.value), + targetBox: store.box(for: ToMany.ReferencedType.self), + relationId: 1) + if !entity.books.isEmpty { + books.replace(entity.books) + } + entity.books = books + try entity.books.applyToDb() + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Author() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + entity.books = ToMany.relation( + sourceId: EntityId(entity.id.value), + targetBox: store.box(for: ToMany.ReferencedType.self), + relationId: 1) + return entity + } +} + + + +extension Book: ObjectBox.__EntityRelatable { + internal typealias EntityType = Book + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Book: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = BookBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Book", id: 2) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Book.self, id: 2, uid: 20736) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 18688) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 19712) + + try entityBuilder.lastProperty(id: 2, uid: 19712) + } +} + +extension Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Book.authors` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.backlinkRelationId(1)) } + + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.authors` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.backlinkRelationId(1)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Book.EntityBindingType`. +internal class BookBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Book + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func postPut(fromEntity entity: EntityType, id: ObjectBox.Id, store: ObjectBox.Store) throws { + if entityId(of: entity) == 0 { // New object was put? Attach relations now that we have an ID. + let authors = ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + targetId: EntityId(id.value), + relationId: 1) + if !entity.authors.isEmpty { + authors.replace(entity.authors) + } + entity.authors = authors + try entity.authors.applyToDb() + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Book() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + entity.authors = ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + targetId: EntityId(entity.id.value), + relationId: 1) + return entity + } +} + + +/// Helper function that allows calling Enum(rawValue: value) with a nil value, which will return nil. +fileprivate func optConstruct(_ type: T.Type, rawValue: T.RawValue?) -> T? { + guard let rawValue = rawValue else { return nil } + return T(rawValue: rawValue) +} + +// MARK: - Store setup + +fileprivate func cModel() throws -> OpaquePointer { + let modelBuilder = try ObjectBox.ModelBuilder() + try Author.buildEntity(modelBuilder: modelBuilder) + try Book.buildEntity(modelBuilder: modelBuilder) + modelBuilder.lastEntity(id: 2, uid: 20736) + modelBuilder.lastRelation(id: 1, uid: 16640) + return modelBuilder.finish() +} + +extension ObjectBox.Store { + /// A store with a fully configured model. Created by the code generator with your model's metadata in place. + /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// + /// - Parameters: + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. + /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). + /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. + /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). + /// - maxReaders: The maximum number of readers. + /// "Readers" are a finite resource for which we need to define a maximum number upfront. + /// The default value is enough for most apps and usually you can ignore it completely. + /// However, if you get the maxReadersExceeded error, you should verify your + /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends + /// on number of types, relations, and usage patterns. Thus, if you are working with many threads + /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// + /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` + /// initializer, trigger code generation by building your project. + internal convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + try self.init( + model: try cModel(), + directory: directoryPath, + maxDbSizeInKByte: maxDbSizeInKByte, + fileMode: fileMode, + maxReaders: maxReaders, + readOnly: readOnly) + } +} + +// swiftlint:enable all diff --git a/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated38.swift b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated38.swift new file mode 100644 index 0000000..a4e8725 --- /dev/null +++ b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated38.swift @@ -0,0 +1,316 @@ +// Generated using the ObjectBox Swift Generator — https://objectbox.io +// DO NOT EDIT + +// swiftlint:disable all +import ObjectBox +import Foundation + +// MARK: - Entity metadata + + +extension Author: ObjectBox.__EntityRelatable { + internal typealias EntityType = Author + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Author: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = AuthorBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Author", id: 1) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Author.self, id: 1, uid: 16640) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 14592) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 15616) + + try entityBuilder.lastProperty(id: 2, uid: 15616) + } +} + +extension Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Author.books` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.valuePropertyId(3)) } + + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.books` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.valuePropertyId(3)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Author.EntityBindingType`. +internal class AuthorBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Author + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func postPut(fromEntity entity: EntityType, id: ObjectBox.Id, store: ObjectBox.Store) throws { + if entityId(of: entity) == 0 { // New object was put? Attach relations now that we have an ID. + let books = ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + sourceProperty: ToMany.ReferencedType.author, + targetId: EntityId(id.value)) + if !entity.books.isEmpty { + books.replace(entity.books) + } + entity.books = books + try entity.books.applyToDb() + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Author() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + entity.books = ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + sourceProperty: ToMany.ReferencedType.author, + targetId: EntityId(entity.id.value)) + return entity + } +} + + + +extension Book: ObjectBox.__EntityRelatable { + internal typealias EntityType = Book + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Book: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = BookBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Book", id: 2) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Book.self, id: 2, uid: 21504) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 17664) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 18688) + try entityBuilder.addToOneRelation(name: "author", targetEntityInfo: ToOne.Target.entityInfo, flags: [.indexed, .indexPartialSkipZero], id: 3, uid: 20736, indexId: 1, indexUid: 19712) + + try entityBuilder.lastProperty(id: 3, uid: 20736) + } +} + +extension Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + internal static var author: Property.Target>, ToOne.Target> { return Property(propertyId: 3) } + + + fileprivate func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + internal static var author: Property.Target.EntityBindingType.IdType, ToOne.Target> { return Property.Target.EntityBindingType.IdType, ToOne.Target>(propertyId: 3) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Book.EntityBindingType`. +internal class BookBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Book + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setEntityIdUnlessStruct(of entity: EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + try propertyCollector.collect(entity.author, at: 2 + 2 * 3, store: store) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func postPut(fromEntity entity: EntityType, id: ObjectBox.Id, store: ObjectBox.Store) throws { + if entityId(of: entity) == 0 { // New object was put? Attach relations now that we have an ID. + entity.author.attach(to: store.box(for: Author.self)) + } + } + internal func setToOneRelation(_ propertyId: obx_schema_id, of entity: EntityType, to entityId: ObjectBox.Id?) { + switch propertyId { + case 3: + entity.author.targetId = (entityId != nil) ? EntityId(entityId!) : nil + default: + fatalError("Attempt to change nonexistent ToOne relation with ID \(propertyId)") + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entity = Book() + + entity.id = entityReader.read(at: 2 + 2 * 1) + entity.name = entityReader.read(at: 2 + 2 * 2) + + entity.author = entityReader.read(at: 2 + 2 * 3, store: store) + return entity + } +} + + +/// Helper function that allows calling Enum(rawValue: value) with a nil value, which will return nil. +fileprivate func optConstruct(_ type: T.Type, rawValue: T.RawValue?) -> T? { + guard let rawValue = rawValue else { return nil } + return T(rawValue: rawValue) +} + +// MARK: - Store setup + +fileprivate func cModel() throws -> OpaquePointer { + let modelBuilder = try ObjectBox.ModelBuilder() + try Author.buildEntity(modelBuilder: modelBuilder) + try Book.buildEntity(modelBuilder: modelBuilder) + modelBuilder.lastEntity(id: 2, uid: 21504) + modelBuilder.lastIndex(id: 1, uid: 19712) + return modelBuilder.finish() +} + +extension ObjectBox.Store { + /// A store with a fully configured model. Created by the code generator with your model's metadata in place. + /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// + /// - Parameters: + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. + /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). + /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. + /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). + /// - maxReaders: The maximum number of readers. + /// "Readers" are a finite resource for which we need to define a maximum number upfront. + /// The default value is enough for most apps and usually you can ignore it completely. + /// However, if you get the maxReadersExceeded error, you should verify your + /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends + /// on number of types, relations, and usage patterns. Thus, if you are working with many threads + /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// + /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` + /// initializer, trigger code generation by building your project. + internal convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + try self.init( + model: try cModel(), + directory: directoryPath, + maxDbSizeInKByte: maxDbSizeInKByte, + fileMode: fileMode, + maxReaders: maxReaders, + readOnly: readOnly) + } +} + +// swiftlint:enable all diff --git a/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated39.swift b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated39.swift new file mode 100644 index 0000000..449d7de --- /dev/null +++ b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated39.swift @@ -0,0 +1,390 @@ +// Generated using the ObjectBox Swift Generator — https://objectbox.io +// DO NOT EDIT + +// swiftlint:disable all +import ObjectBox +import Foundation + +// MARK: - Entity metadata + + +extension Author: ObjectBox.__EntityRelatable { + internal typealias EntityType = Author + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Author: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = AuthorBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Author", id: 1) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Author.self, id: 1, uid: 16640) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 14592) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 15616) + + try entityBuilder.lastProperty(id: 2, uid: 15616) + } +} + +extension Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Author.books` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.valuePropertyId(3)) } + + + fileprivate mutating func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.books` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.valuePropertyId(3)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Author.EntityBindingType`. +internal class AuthorBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Author + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setStructEntityId(of entity: inout EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entityId: EntityId = entityReader.read(at: 2 + 2 * 1) + let entity = Author( + id: entityId, + name: entityReader.read(at: 2 + 2 * 2), + books: ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + sourceProperty: ToMany.ReferencedType.author, + targetId: EntityId(entityId.value)) + ) + return entity + } +} + +extension ObjectBox.Box where E == Author { + + /// Puts the Author in the box (aka persisting it) returning a copy with the ID updated to the ID it + /// has been assigned. + /// If you know the entity has already been persisted, you can use put() to avoid the cost of the copy. + /// + /// - Parameter entity: Object to persist. + /// - Returns: The stored object. If `entity`'s id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(struct entity: Author) throws -> Author { + let entityId: Author.EntityBindingType.IdType = try self.put(entity) + + return Author( + id: entityId, + name: entity.name, + books: entity.books + ) + } + + /// Puts the Authors in the box (aka persisting it) returning copies with their IDs updated to the + /// IDs they've been assigned. + /// If you know all entities have already been persisted, you can use put() to avoid the cost of the + /// copies. + /// + /// - Parameter entities: Objects to persist. + /// - Returns: The stored objects. If any entity's id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(structs entities: [Author]) throws -> [Author] { + let entityIds: [Author.EntityBindingType.IdType] = try self.putAndReturnIDs(entities) + var newEntities = [Author]() + newEntities.reserveCapacity(entities.count) + + for i in 0 ..< min(entities.count, entityIds.count) { + let entity = entities[i] + let entityId = entityIds[i] + + newEntities.append(Author( + id: entityId, + name: entity.name, + books: entity.books + )) + } + + return newEntities + } +} + + +extension Book: ObjectBox.__EntityRelatable { + internal typealias EntityType = Book + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Book: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = BookBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Book", id: 2) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Book.self, id: 2, uid: 21504) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 17664) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 18688) + try entityBuilder.addToOneRelation(name: "author", targetEntityInfo: ToOne.Target.entityInfo, flags: [.indexed, .indexPartialSkipZero], id: 3, uid: 20736, indexId: 1, indexUid: 19712) + + try entityBuilder.lastProperty(id: 3, uid: 20736) + } +} + +extension Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + internal static var author: Property.Target>, ToOne.Target> { return Property(propertyId: 3) } + + + fileprivate mutating func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + internal static var author: Property.Target.EntityBindingType.IdType, ToOne.Target> { return Property.Target.EntityBindingType.IdType, ToOne.Target>(propertyId: 3) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Book.EntityBindingType`. +internal class BookBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Book + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setStructEntityId(of entity: inout EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + try propertyCollector.collect(entity.author, at: 2 + 2 * 3, store: store) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func setToOneRelation(_ propertyId: obx_schema_id, of entity: EntityType, to entityId: ObjectBox.Id?) { + switch propertyId { + case 3: + entity.author.targetId = (entityId != nil) ? EntityId(entityId!) : nil + default: + fatalError("Attempt to change nonexistent ToOne relation with ID \(propertyId)") + } + } + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entityId: EntityId = entityReader.read(at: 2 + 2 * 1) + let entity = Book( + id: entityId, + name: entityReader.read(at: 2 + 2 * 2), + author: entityReader.read(at: 2 + 2 * 3, store: store) + ) + return entity + } +} + +extension ObjectBox.Box where E == Book { + + /// Puts the Book in the box (aka persisting it) returning a copy with the ID updated to the ID it + /// has been assigned. + /// If you know the entity has already been persisted, you can use put() to avoid the cost of the copy. + /// + /// - Parameter entity: Object to persist. + /// - Returns: The stored object. If `entity`'s id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(struct entity: Book) throws -> Book { + let entityId: Book.EntityBindingType.IdType = try self.put(entity) + + return Book( + id: entityId, + name: entity.name, + author: entity.author + ) + } + + /// Puts the Books in the box (aka persisting it) returning copies with their IDs updated to the + /// IDs they've been assigned. + /// If you know all entities have already been persisted, you can use put() to avoid the cost of the + /// copies. + /// + /// - Parameter entities: Objects to persist. + /// - Returns: The stored objects. If any entity's id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(structs entities: [Book]) throws -> [Book] { + let entityIds: [Book.EntityBindingType.IdType] = try self.putAndReturnIDs(entities) + var newEntities = [Book]() + newEntities.reserveCapacity(entities.count) + + for i in 0 ..< min(entities.count, entityIds.count) { + let entity = entities[i] + let entityId = entityIds[i] + + newEntities.append(Book( + id: entityId, + name: entity.name, + author: entity.author + )) + } + + return newEntities + } +} + +/// Helper function that allows calling Enum(rawValue: value) with a nil value, which will return nil. +fileprivate func optConstruct(_ type: T.Type, rawValue: T.RawValue?) -> T? { + guard let rawValue = rawValue else { return nil } + return T(rawValue: rawValue) +} + +// MARK: - Store setup + +fileprivate func cModel() throws -> OpaquePointer { + let modelBuilder = try ObjectBox.ModelBuilder() + try Author.buildEntity(modelBuilder: modelBuilder) + try Book.buildEntity(modelBuilder: modelBuilder) + modelBuilder.lastEntity(id: 2, uid: 21504) + modelBuilder.lastIndex(id: 1, uid: 19712) + return modelBuilder.finish() +} + +extension ObjectBox.Store { + /// A store with a fully configured model. Created by the code generator with your model's metadata in place. + /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// + /// - Parameters: + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. + /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). + /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. + /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). + /// - maxReaders: The maximum number of readers. + /// "Readers" are a finite resource for which we need to define a maximum number upfront. + /// The default value is enough for most apps and usually you can ignore it completely. + /// However, if you get the maxReadersExceeded error, you should verify your + /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends + /// on number of types, relations, and usage patterns. Thus, if you are working with many threads + /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// + /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` + /// initializer, trigger code generation by building your project. + internal convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + try self.init( + model: try cModel(), + directory: directoryPath, + maxDbSizeInKByte: maxDbSizeInKByte, + fileMode: fileMode, + maxReaders: maxReaders, + readOnly: readOnly) + } +} + +// swiftlint:enable all diff --git a/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated40.swift b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated40.swift new file mode 100644 index 0000000..087f3cf --- /dev/null +++ b/Source/ios-framework/CodeGenTests/expected/entity-info/EntityInfo.generated40.swift @@ -0,0 +1,391 @@ +// Generated using the ObjectBox Swift Generator — https://objectbox.io +// DO NOT EDIT + +// swiftlint:disable all +import ObjectBox +import Foundation + +// MARK: - Entity metadata + + +extension Author: ObjectBox.__EntityRelatable { + internal typealias EntityType = Author + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Author: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = AuthorBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Author", id: 1) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Author.self, id: 1, uid: 17664) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 14592) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 15616) + try entityBuilder.addToManyRelation(id: 1, uid: 16640, + targetId: 2, targetUid: 20736) + + try entityBuilder.lastProperty(id: 2, uid: 15616) + } +} + +extension Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Author.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Author.books` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.relationId(1)) } + + + fileprivate mutating func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Author { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.books` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var books: ToManyProperty { return ToManyProperty(.relationId(1)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Author.EntityBindingType`. +internal class AuthorBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Author + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setStructEntityId(of entity: inout EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entityId: EntityId = entityReader.read(at: 2 + 2 * 1) + let entity = Author( + id: entityId, + name: entityReader.read(at: 2 + 2 * 2), + books: ToMany.relation( + sourceId: EntityId(entityId.value), + targetBox: store.box(for: ToMany.ReferencedType.self), + relationId: 1) + ) + return entity + } +} + +extension ObjectBox.Box where E == Author { + + /// Puts the Author in the box (aka persisting it) returning a copy with the ID updated to the ID it + /// has been assigned. + /// If you know the entity has already been persisted, you can use put() to avoid the cost of the copy. + /// + /// - Parameter entity: Object to persist. + /// - Returns: The stored object. If `entity`'s id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(struct entity: Author) throws -> Author { + let entityId: Author.EntityBindingType.IdType = try self.put(entity) + + return Author( + id: entityId, + name: entity.name, + books: entity.books + ) + } + + /// Puts the Authors in the box (aka persisting it) returning copies with their IDs updated to the + /// IDs they've been assigned. + /// If you know all entities have already been persisted, you can use put() to avoid the cost of the + /// copies. + /// + /// - Parameter entities: Objects to persist. + /// - Returns: The stored objects. If any entity's id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(structs entities: [Author]) throws -> [Author] { + let entityIds: [Author.EntityBindingType.IdType] = try self.putAndReturnIDs(entities) + var newEntities = [Author]() + newEntities.reserveCapacity(entities.count) + + for i in 0 ..< min(entities.count, entityIds.count) { + let entity = entities[i] + let entityId = entityIds[i] + + newEntities.append(Author( + id: entityId, + name: entity.name, + books: entity.books + )) + } + + return newEntities + } +} + + +extension Book: ObjectBox.__EntityRelatable { + internal typealias EntityType = Book + + internal var _id: EntityId { + return EntityId(self.id.value) + } +} + +extension Book: ObjectBox.EntityInspectable { + internal typealias EntityBindingType = BookBinding + + /// Generated metadata used by ObjectBox to persist the entity. + internal static var entityInfo = ObjectBox.EntityInfo(name: "Book", id: 2) + + internal static var entityBinding = EntityBindingType() + + fileprivate static func buildEntity(modelBuilder: ObjectBox.ModelBuilder) throws { + let entityBuilder = try modelBuilder.entityBuilder(for: Book.self, id: 2, uid: 20736) + try entityBuilder.addProperty(name: "id", type: PropertyType.long, flags: [.id], id: 1, uid: 18688) + try entityBuilder.addProperty(name: "name", type: PropertyType.string, id: 2, uid: 19712) + + try entityBuilder.lastProperty(id: 2, uid: 19712) + } +} + +extension Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.id == myId } + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { Book.name.startsWith("X") } + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + /// Use `Book.authors` to refer to this ToMany relation property in queries, + /// like when using `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.backlinkRelationId(1)) } + + + fileprivate mutating func __setId(identifier: ObjectBox.Id) { + self.id = EntityId(identifier) + } +} + +extension ObjectBox.Property where E == Book { + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .id == myId } + + internal static var id: Property, EntityId> { return Property, EntityId>(propertyId: 1, isPrimaryKey: true) } + + /// Generated entity property information. + /// + /// You may want to use this in queries to specify fetch conditions, for example: + /// + /// box.query { .name.startsWith("X") } + + internal static var name: Property { return Property(propertyId: 2, isPrimaryKey: false) } + + /// Use `.authors` to refer to this ToMany relation property in queries, like when using + /// `QueryBuilder.and(property:, conditions:)`. + + internal static var authors: ToManyProperty { return ToManyProperty(.backlinkRelationId(1)) } + +} + + +/// Generated service type to handle persisting and reading entity data. Exposed through `Book.EntityBindingType`. +internal class BookBinding: ObjectBox.EntityBinding { + internal typealias EntityType = Book + internal typealias IdType = EntityId + + internal required init() {} + + internal func generatorBindingVersion() -> Int { 1 } + + internal func setStructEntityId(of entity: inout EntityType, to entityId: ObjectBox.Id) { + entity.__setId(identifier: entityId) + } + + internal func entityId(of entity: EntityType) -> ObjectBox.Id { + return entity.id.value + } + + internal func collect(fromEntity entity: EntityType, id: ObjectBox.Id, + propertyCollector: ObjectBox.FlatBufferBuilder, store: ObjectBox.Store) throws { + let propertyOffset_name = propertyCollector.prepare(string: entity.name) + + propertyCollector.collect(id, at: 2 + 2 * 1) + propertyCollector.collect(dataOffset: propertyOffset_name, at: 2 + 2 * 2) + } + + internal func createEntity(entityReader: ObjectBox.FlatBufferReader, store: ObjectBox.Store) -> EntityType { + let entityId: EntityId = entityReader.read(at: 2 + 2 * 1) + let entity = Book( + id: entityId, + name: entityReader.read(at: 2 + 2 * 2), + authors: ToMany.backlink( + sourceBox: store.box(for: ToMany.ReferencedType.self), + targetId: EntityId(entityId.value), + relationId: 1) + ) + return entity + } +} + +extension ObjectBox.Box where E == Book { + + /// Puts the Book in the box (aka persisting it) returning a copy with the ID updated to the ID it + /// has been assigned. + /// If you know the entity has already been persisted, you can use put() to avoid the cost of the copy. + /// + /// - Parameter entity: Object to persist. + /// - Returns: The stored object. If `entity`'s id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(struct entity: Book) throws -> Book { + let entityId: Book.EntityBindingType.IdType = try self.put(entity) + + return Book( + id: entityId, + name: entity.name, + authors: entity.authors + ) + } + + /// Puts the Books in the box (aka persisting it) returning copies with their IDs updated to the + /// IDs they've been assigned. + /// If you know all entities have already been persisted, you can use put() to avoid the cost of the + /// copies. + /// + /// - Parameter entities: Objects to persist. + /// - Returns: The stored objects. If any entity's id is 0, an ID is generated. + /// - Throws: ObjectBoxError errors for database write errors. + func put(structs entities: [Book]) throws -> [Book] { + let entityIds: [Book.EntityBindingType.IdType] = try self.putAndReturnIDs(entities) + var newEntities = [Book]() + newEntities.reserveCapacity(entities.count) + + for i in 0 ..< min(entities.count, entityIds.count) { + let entity = entities[i] + let entityId = entityIds[i] + + newEntities.append(Book( + id: entityId, + name: entity.name, + authors: entity.authors + )) + } + + return newEntities + } +} + +/// Helper function that allows calling Enum(rawValue: value) with a nil value, which will return nil. +fileprivate func optConstruct(_ type: T.Type, rawValue: T.RawValue?) -> T? { + guard let rawValue = rawValue else { return nil } + return T(rawValue: rawValue) +} + +// MARK: - Store setup + +fileprivate func cModel() throws -> OpaquePointer { + let modelBuilder = try ObjectBox.ModelBuilder() + try Author.buildEntity(modelBuilder: modelBuilder) + try Book.buildEntity(modelBuilder: modelBuilder) + modelBuilder.lastEntity(id: 2, uid: 20736) + modelBuilder.lastRelation(id: 1, uid: 16640) + return modelBuilder.finish() +} + +extension ObjectBox.Store { + /// A store with a fully configured model. Created by the code generator with your model's metadata in place. + /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// + /// - Parameters: + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. + /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). + /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. + /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). + /// - maxReaders: The maximum number of readers. + /// "Readers" are a finite resource for which we need to define a maximum number upfront. + /// The default value is enough for most apps and usually you can ignore it completely. + /// However, if you get the maxReadersExceeded error, you should verify your + /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends + /// on number of types, relations, and usage patterns. Thus, if you are working with many threads + /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// + /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` + /// initializer, trigger code generation by building your project. + internal convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + try self.init( + model: try cModel(), + directory: directoryPath, + maxDbSizeInKByte: maxDbSizeInKByte, + fileMode: fileMode, + maxReaders: maxReaders, + readOnly: readOnly) + } +} + +// swiftlint:enable all diff --git a/Source/ios-framework/CodeGenTests/expected/messages/messages41.log b/Source/ios-framework/CodeGenTests/expected/messages/messages41.log index 61c48bc..e23454d 100644 --- a/Source/ios-framework/CodeGenTests/expected/messages/messages41.log +++ b/Source/ios-framework/CodeGenTests/expected/messages/messages41.log @@ -1,6 +1,5 @@ Scanning sources... Found 3 types. -Mapping not found: Optional(ToMany) ToMany ToMany nil warning: Found an // objectbox: backlink annotation on ToOne relation "author". Did you mean to put // objectbox: backlink = "author" on the ToMany relation "books" in "Author"? note: ObjectBox ID Model file created: model41.json. Loading templates... diff --git a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump16.txt b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump16.txt index 0723803..b492516 100644 --- a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump16.txt +++ b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump16.txt @@ -54,7 +54,6 @@ Schema { isBuiltInType = false isStringType = true isRelation = false - indexType = hashIndex } ] indexes = [SchemaIndex { diff --git a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump17.txt b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump17.txt index aca8fa5..eb58811 100644 --- a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump17.txt +++ b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump17.txt @@ -54,7 +54,6 @@ Schema { isBuiltInType = false isStringType = true isRelation = false - indexType = hashIndex } ] indexes = [SchemaIndex { diff --git a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump26.txt b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump26.txt index aca8fa5..eb58811 100644 --- a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump26.txt +++ b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump26.txt @@ -54,7 +54,6 @@ Schema { isBuiltInType = false isStringType = true isRelation = false - indexType = hashIndex } ] indexes = [SchemaIndex { diff --git a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump30.txt b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump30.txt index e461c6c..378581a 100644 --- a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump30.txt +++ b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump30.txt @@ -37,8 +37,6 @@ Schema { isBuiltInType = false isStringType = true isRelation = false - isUniqueIndex = true - indexType = hashIndex } , SchemaProperty { modelId = Optional(IdUid(3:17664)) @@ -73,8 +71,6 @@ Schema { isBuiltInType = false isStringType = true isRelation = false - isUniqueIndex = true - indexType = hashIndex } ] indexes = [SchemaIndex { diff --git a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump59.txt b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump59.txt index 92b7ecd..4c5d53d 100644 --- a/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump59.txt +++ b/Source/ios-framework/CodeGenTests/expected/schema-dump/schemaDump59.txt @@ -37,7 +37,6 @@ Schema { isBuiltInType = false isStringType = false isRelation = false - indexType = valueIndex isScalarVectorType = true hnswParams = SchemaHnswParams { dimensions = 2 @@ -136,7 +135,6 @@ Schema { isBuiltInType = false isStringType = false isRelation = false - indexType = valueIndex isScalarVectorType = true hnswParams = SchemaHnswParams { dimensions = 2 diff --git a/Source/ios-framework/CommonSource/GeneratedStoreInitializer.swift b/Source/ios-framework/CommonSource/GeneratedStoreInitializer.swift index b430682..be41a3f 100644 --- a/Source/ios-framework/CommonSource/GeneratedStoreInitializer.swift +++ b/Source/ios-framework/CommonSource/GeneratedStoreInitializer.swift @@ -6,8 +6,16 @@ public extension Store { /// A store with a fully configured model. Created by the code generator with your model's metadata in place. /// + /// # In-memory database + /// To use a file-less in-memory database, instead of a directory path pass `memory:` + /// together with an identifier string: + /// ```swift + /// let inMemoryStore = try Store(directoryPath: "memory:test-db") + /// ``` + /// /// - Parameters: - /// - directoryPath: The directory path in which ObjectBox places its database files for this store. + /// - directoryPath: The directory path in which ObjectBox places its database files for this store, + /// or to use an in-memory database `memory:`. /// - maxDbSizeInKByte: Limit of on-disk space for the database files. Default is `1024 * 1024` (1 GiB). /// - fileMode: UNIX-style bit mask used for the database files; default is `0o644`. /// Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750). @@ -18,12 +26,13 @@ public extension Store { /// threading. For each thread, ObjectBox uses multiple readers. Their number (per thread) depends /// on number of types, relations, and usage patterns. Thus, if you are working with many threads /// (e.g. in a server-like scenario), it can make sense to increase the maximum number of readers. - /// Note: The internal default is currently around 120. - /// So when hitting this limit, try values around 200-500. + /// Note: The internal default is currently around 120. So when hitting this limit, try values around 200-500. + /// - readOnly: Opens the database in read-only mode, i.e. not allowing write transactions. + /// /// - important: This initializer is created by the code generator. If you only see the internal `init(model:...)` /// initializer, trigger code generation by building your project. - public convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, fileMode: UInt32 = 0o755, - maxReaders: UInt32 = 0, readOnly: Bool = false) throws { + public convenience init(directoryPath: String, maxDbSizeInKByte: UInt64 = 1024 * 1024, + fileMode: UInt32 = 0o644, maxReaders: UInt32 = 0, readOnly: Bool = false) throws { try self.init( model: OpaquePointer(bitPattern: 0)!, directory: directoryPath, diff --git a/Source/ios-framework/CommonSource/Internal/objectbox-c-sync.h b/Source/ios-framework/CommonSource/Internal/objectbox-c-sync.h index 73cdcca..afa8913 100644 --- a/Source/ios-framework/CommonSource/Internal/objectbox-c-sync.h +++ b/Source/ios-framework/CommonSource/Internal/objectbox-c-sync.h @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 ObjectBox Ltd. All rights reserved. + * Copyright 2018-2024 ObjectBox Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ #include "objectbox-c.h" #if defined(static_assert) || defined(__cplusplus) -static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 1, // NOLINT +static_assert(OBX_VERSION_MAJOR == 4 && OBX_VERSION_MINOR == 0 && OBX_VERSION_PATCH == 2, // NOLINT "Versions of objectbox.h and objectbox-sync.h files do not match, please update"); #endif @@ -52,7 +52,7 @@ struct OBX_sync; typedef struct OBX_sync OBX_sync; /// Specifies user-side credential types as well as server-side authenticator types. -/// Some credentail types do not make sense as authenticators such as OBXSyncCredentialsType_USER_PASSWORD which +/// Some credential types do not make sense as authenticators such as OBXSyncCredentialsType_USER_PASSWORD which /// specifies a generic client-side credential type. typedef enum { OBXSyncCredentialsType_NONE = 1, @@ -444,6 +444,12 @@ typedef struct OBX_sync_server OBX_sync_server; /// @returns NULL if server could not be created (e.g. the store could not be opened, bad URL, etc.) OBX_C_API OBX_sync_server* obx_sync_server(OBX_store_options* store_options, const char* url); +/// Like obx_sync_server(), but retrieves its options for the Sync Server from the given FlatBuffers options. +/// @param flat_options FlatBuffers serialized options for the server (start of the bytes buffer, not the "table"). +/// @param flat_options_size Size of the FlatBuffers serialized options. +OBX_C_API OBX_sync_server* obx_sync_server_from_flat_options(OBX_store_options* store_options, const void* flat_options, + size_t flat_options_size); + /// Stops and closes (deletes) the sync server, freeing its resources. /// This includes the store associated with the server; it gets closed and must not be used anymore after this call. OBX_C_API obx_err obx_sync_server_close(OBX_sync_server* server); @@ -479,6 +485,20 @@ OBX_C_API obx_err obx_sync_server_worker_threads(OBX_sync_server* server, int th OBX_C_API obx_err obx_sync_server_history_max_size_in_kb(OBX_sync_server* server, uint64_t max_in_kb, uint64_t target_in_kb); +/// Configures the cluster ID for the given embedded server (the cluster feature must be enabled). +/// @param id A user defined string to identify the cluster (all cluster peer must share the same ID). +OBX_C_API obx_err obx_sync_server_cluster_id(OBX_sync_server* server, const char* id); + +/// Adds a remote cluster peer that can be connected to using the given URL and credentials. +/// Call this method multiple times to add multiple peers (at least 2 times for a cluster of 3). +/// @param url URL to the remote cluster peer used to connect it. +/// @param flags For now, always pass 0. +/// @param credentials the credentials provided to the remote peer to login (it must match the remote's configuration). +/// May be NULL in combination with OBXSyncCredentialsType_NONE. +OBX_C_API obx_err obx_sync_server_add_cluster_peer(OBX_sync_server* server, const char* url, + OBXSyncCredentialsType credentials_type, const void* credentials, + size_t credentials_size, uint32_t flags); + /// Set or overwrite a previously set 'change' listener - provides information about incoming changes. /// @param listener set NULL to reset /// @param listener_arg is a pass-through argument passed to the listener diff --git a/Source/ios-framework/CommonSource/Internal/objectbox-c.h b/Source/ios-framework/CommonSource/Internal/objectbox-c.h index 813c2d3..5a2cacb 100644 --- a/Source/ios-framework/CommonSource/Internal/objectbox-c.h +++ b/Source/ios-framework/CommonSource/Internal/objectbox-c.h @@ -53,7 +53,7 @@ extern "C" { /// obx_version() or obx_version_is_at_least(). #define OBX_VERSION_MAJOR 4 #define OBX_VERSION_MINOR 0 -#define OBX_VERSION_PATCH 1 // values >= 100 are reserved for dev releases leading to the next minor/major increase +#define OBX_VERSION_PATCH 2 // values >= 100 are reserved for dev releases leading to the next minor/major increase //---------------------------------------------- // Common types @@ -86,6 +86,8 @@ typedef int obx_err; /// @return The visitor returns true to keep going or false to cancel. typedef bool obx_data_visitor(const void* data, size_t size, void* user_data); +struct OBX_bytes_score; // Forward declaration for the obx_data_score_visitor typedef + /// The callback for reading data (i.e. object bytes) with a search score one-by-one. /// @param data contains the current data with score element /// @param user_data is a pass-through argument passed to the called API @@ -165,6 +167,13 @@ typedef enum { /// Vector search functionality; enables indexing for nearest neighbor search. OBXFeature_VectorSearch = 14, + /// WAL (write-ahead logging). + OBXFeature_Wal = 15, + + /// Sync connector to integrate MongoDB with SyncServer. + OBXFeature_SyncMongoDb = 16, + + } OBXFeature; /// Checks whether the given feature is available in the currently loaded library. diff --git a/Source/ios-framework/CommonSource/Store.swift b/Source/ios-framework/CommonSource/Store.swift index b17abf0..05d5604 100644 --- a/Source/ios-framework/CommonSource/Store.swift +++ b/Source/ios-framework/CommonSource/Store.swift @@ -43,7 +43,7 @@ public class Store: CustomDebugStringConvertible { internal(set) public var directoryPath: String /// Returns the version of ObjectBox Swift. - public static var version = "4.0.0" + public static var version = "4.0.1" /// Pass this together with a String identifier as the directory path to use /// a file-less in-memory database. diff --git a/Source/ios-framework/CommonTests/StoreTests.swift b/Source/ios-framework/CommonTests/StoreTests.swift index 6b917c9..3db396e 100644 --- a/Source/ios-framework/CommonTests/StoreTests.swift +++ b/Source/ios-framework/CommonTests/StoreTests.swift @@ -47,9 +47,9 @@ class StoreTests: XCTestCase { // Update the expected versions every now and then. // TODO XCTAssertGreaterThanOrEqual doesn't respect semantic versioning: // e.g. 0.10.0 will be evaluated as lower than 0.9.1 - XCTAssertGreaterThanOrEqual(Store.version, "4.0.0") - XCTAssertGreaterThanOrEqual(Store.versionLib, "4.0.1") - XCTAssertGreaterThanOrEqual(Store.versionCore, "4.0.1-2024-07-17") + XCTAssertGreaterThanOrEqual(Store.version, "4.0.1") + XCTAssertGreaterThanOrEqual(Store.versionLib, "4.0.2") + XCTAssertGreaterThanOrEqual(Store.versionCore, "4.0.2-2024-10-15") } func testCloseTwice() { diff --git a/Source/ios-framework/README.md b/Source/ios-framework/README.md index d12acbf..5c2a00e 100644 --- a/Source/ios-framework/README.md +++ b/Source/ios-framework/README.md @@ -4,12 +4,12 @@ -[ObjectBox](https://objectbox.io/) Swift is a superfast, light-weight object persistence framework for iOS and macOS. +[ObjectBox Swift](https://github.com/objectbox/objectbox-swift) is a superfast, light-weight object persistence framework for iOS and macOS. This is the ObjectBox Swift **API reference**. -Also check the **[guides](https://swift.objectbox.io/)** for general documentation including [setup](https://swift.objectbox.io/install) and [getting started](https://swift.objectbox.io/getting-started). +Check **[the documentation](https://swift.objectbox.io/)** on how to install and use ObjectBox Swift. -Current version: 4.0.0 +This documents API version: 4.0.1 ## Most Important Types diff --git a/Source/ios-framework/docs/jazzy.yaml b/Source/ios-framework/docs/jazzy.yaml index 90e37d4..b007dd6 100644 --- a/Source/ios-framework/docs/jazzy.yaml +++ b/Source/ios-framework/docs/jazzy.yaml @@ -4,7 +4,7 @@ author: "ObjectBox" author_url: "https://objectbox.io" module: "ObjectBox" -module_version: 4.0.0 +module_version: 4.0.1 github_url: "https://github.com/objectbox/objectbox-swift" root_url: "https://objectbox.io/docfiles/swift/current/" diff --git a/cartspec/ObjectBox.json b/cartspec/ObjectBox.json index 219e55e..8cd4e9b 100644 --- a/cartspec/ObjectBox.json +++ b/cartspec/ObjectBox.json @@ -1,4 +1,5 @@ { + "4.0.1": "https://github.com/objectbox/objectbox-swift/releases/download/v4.0.1/ObjectBox-4.0.1-Carthage.framework.zip", "4.0.0": "https://github.com/objectbox/objectbox-swift/releases/download/v4.0.0/ObjectBox-4.0.0-Carthage.framework.zip", "2.0.0": "https://github.com/objectbox/objectbox-swift/releases/download/v2.0.0/ObjectBox-2.0.0-Carthage.framework.zip", "1.9.2": "https://github.com/objectbox/objectbox-swift/releases/download/v1.9.2/ObjectBox-1.9.2-Carthage.framework.zip",