diff --git a/.gitignore b/.gitignore index ea0c923..5fc8169 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ /tmp /out-tsc +.env + + # dependencies node_modules package-lock.json @@ -42,3 +45,5 @@ Thumbs.db *.tgz packages/**/angular/dist + +.nx/cache \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 413ca14..f358a6f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,5 @@ /dist /coverage native-src + +/.nx/cache \ No newline at end of file diff --git a/apps/demo-angular/package.json b/apps/demo-angular/package.json index 01576da..2adc216 100644 --- a/apps/demo-angular/package.json +++ b/apps/demo-angular/package.json @@ -4,14 +4,15 @@ "@nativescript/core": "file:../../node_modules/@nativescript/core", "@valor/nativescript-websockets": "file:../../node_modules/@valor/nativescript-websockets", "@herefishyfish/nativescript-rxdb": "file:../../dist/packages/nativescript-rxdb", - "@herefishyfish/nativescript-md5": "file:../../dist/packages/nativescript-md5", "@herefishyfish/nativescript-sqlite-rxstorage-adapter": "file:../../dist/packages/nativescript-sqlite-rxstorage-adapter", - "@herefishyfish/nativescript-pouchdb-sqlite-adapter": "file:../../dist/packages/nativescript-pouchdb-sqlite-adapter", "@herefishyfish/nativescript-lokijs": "file:../../dist/packages/nativescript-lokijs", "@herefishyfish/requery-sqlite": "file:../../dist/packages/requery-sqlite" }, + "__docs": { + "@herefishyfish/requery-sqlite": "3.4.2" + }, "devDependencies": { - "@nativescript/android": "beta", - "@nativescript/ios": "~8.4.0" + "@nativescript/android": "~8.9.0", + "@nativescript/ios": "~8.9.0" } } diff --git a/apps/demo-angular/src/RxDB.d.ts b/apps/demo-angular/src/RxDB.d.ts new file mode 100644 index 0000000..429c4e0 --- /dev/null +++ b/apps/demo-angular/src/RxDB.d.ts @@ -0,0 +1,18 @@ +import type { RxDocument, RxCollection, RxDatabase } from 'rxdb'; +import { RxHeroDocumentType } from './schemas/hero.schema'; +import { Signal } from '@angular/core'; + +// ORM methods +type RxHeroDocMethods = { + addHero: (name: string, color: string) => Promise; +}; + +export type RxHeroDocument = RxDocument; + +export type RxHeroCollection = RxCollection>; + +export type RxHeroesCollections = { + hero: RxHeroCollection; +}; + +export type RxHeroesDatabase = RxDatabase>; diff --git a/apps/demo-angular/src/app-routing.module.ts b/apps/demo-angular/src/app-routing.module.ts index b62d527..cdf9252 100644 --- a/apps/demo-angular/src/app-routing.module.ts +++ b/apps/demo-angular/src/app-routing.module.ts @@ -7,10 +7,9 @@ import { HomeComponent } from './home.component'; const routes: Routes = [ { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: 'home', component: HomeComponent }, + { path: 'rxstorage-memory', loadComponent: () => import('./plugin-demos/rxstorage-memory/rxstorage-memory.component').then((m) => m.NativeScriptRxStorageMemoryComponent) }, { path: 'lokijs-rxstorage', loadComponent: () => import('./plugin-demos/rxstorage-lokijs/lokijs-rxstorage.component').then((m) => m.NativescriptLokijsRxstorageComponent) }, { path: 'sqlite-rxstorage', loadComponent: () => import('./plugin-demos/rxstorage-sqlite/sqlite-rxstorage.component').then((m) => m.NativescriptSQLiteRxstorageComponent) }, - { path: 'rxstorage-memory', loadComponent: () => import('./plugin-demos/rxstorage-memory/rxstorage-memory.component').then((m) => m.NativeScriptRxStorageMemoryComponent) }, - { path: 'pouchdb-sqlite', loadComponent: () => import('./plugin-demos/pouchdb-sqlite/pouchdb-sqlite.component').then((m) => m.NativescriptSQLitePouchDBComponent) }, ]; @NgModule({ diff --git a/apps/demo-angular/src/app.component.ts b/apps/demo-angular/src/app.component.ts index 13d329c..d440552 100644 --- a/apps/demo-angular/src/app.component.ts +++ b/apps/demo-angular/src/app.component.ts @@ -1,8 +1,9 @@ import { Component } from '@angular/core'; -import 'zone.js/dist/zone-patch-rxjs'; +// import 'zone.js/dist/zone-patch-rxjs'; @Component({ selector: 'demo-app', + standalone: false, template: ` `, diff --git a/apps/demo-angular/src/home.component.ts b/apps/demo-angular/src/home.component.ts index 902d962..c72a232 100644 --- a/apps/demo-angular/src/home.component.ts +++ b/apps/demo-angular/src/home.component.ts @@ -2,21 +2,19 @@ import { Component } from '@angular/core'; @Component({ selector: 'demo-home', + standalone: false, templateUrl: 'home.component.html', }) export class HomeComponent { demos = [ { - name: 'lokijs-rxstorage', + name: 'rxstorage-memory', }, { name: 'sqlite-rxstorage', }, { - name: 'rxstorage-memory', - }, - { - name: 'pouchdb-sqlite', + name: 'lokijs-rxstorage', }, ]; } diff --git a/apps/demo-angular/src/plugin-demos/pouchdb-sqlite/pouchdb-sqlite.component.ts b/apps/demo-angular/src/plugin-demos/pouchdb-sqlite/pouchdb-sqlite.component.ts deleted file mode 100644 index 50c196f..0000000 --- a/apps/demo-angular/src/plugin-demos/pouchdb-sqlite/pouchdb-sqlite.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { getRxStorageLoki } from 'rxdb/plugins/storage-lokijs'; -import { RxDBCoreService, RXDB_STORAGE } from '../../replicator/rxdb-service'; -import { LokiNativescriptAdapter } from '@herefishyfish/nativescript-lokijs'; -import { NativeScriptCommonModule } from '@nativescript/angular'; -import { HeroComponent } from '../shared/hero.component'; - -@Component({ - selector: 'demo-nativescript-lokijs', - templateUrl: '../shared/hero.page.html', - standalone: true, - schemas: [NO_ERRORS_SCHEMA], - imports: [NativeScriptCommonModule, HeroComponent], - providers: [ - RxDBCoreService, - { - provide: RXDB_STORAGE, - useFactory: () => { - return getRxStorageLoki({ - env: 'NATIVESCRIPT', - adapter: new LokiNativescriptAdapter(), - }); - }, - }, - ], -}) -export class NativescriptSQLitePouchDBComponent { - adapter = 'SQLite PouchDB Adapter'; - constructor(public _rxdb: RxDBCoreService) {} -} diff --git a/apps/demo-angular/src/plugin-demos/rxstorage-lokijs/lokijs-rxstorage.component.ts b/apps/demo-angular/src/plugin-demos/rxstorage-lokijs/lokijs-rxstorage.component.ts index 7c018cc..cf336f6 100644 --- a/apps/demo-angular/src/plugin-demos/rxstorage-lokijs/lokijs-rxstorage.component.ts +++ b/apps/demo-angular/src/plugin-demos/rxstorage-lokijs/lokijs-rxstorage.component.ts @@ -1,30 +1,32 @@ import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; -import { getRxStorageLoki } from 'rxdb/plugins/storage-lokijs'; -import { RxDBCoreService, RXDB_STORAGE } from '../../replicator/rxdb-service'; -import { LokiNativescriptAdapter } from '@herefishyfish/nativescript-lokijs'; +// import { getRxStorageLoki } from 'rxdb/plugins/storage-lokijs'; import { NativeScriptCommonModule } from '@nativescript/angular'; -import { HeroComponent } from '../shared/hero.component'; @Component({ selector: 'demo-nativescript-lokijs', - templateUrl: '../shared/hero.page.html', + // templateUrl: '../shared/hero.page.html', + template: ` + + + + `, standalone: true, schemas: [NO_ERRORS_SCHEMA], - imports: [NativeScriptCommonModule, HeroComponent], - providers: [ - RxDBCoreService, - { - provide: RXDB_STORAGE, - useFactory: () => { - return getRxStorageLoki({ - env: 'NATIVESCRIPT', - adapter: new LokiNativescriptAdapter(), - }); - }, - }, - ], + imports: [NativeScriptCommonModule], + // providers: [ + // RxDBCoreService, + // { + // provide: RXDB_STORAGE, + // useFactory: () => { + // return getRxStorageLoki({ + // env: 'NATIVESCRIPT', + // adapter: new LokiNativescriptAdapter(), + // }); + // }, + // }, + // ], }) export class NativescriptLokijsRxstorageComponent { - adapter = 'LokiJS RxStorage Adapter'; - constructor(public _rxdb: RxDBCoreService) {} + adapter = 'LokiJS RxStorage Adapter (deprecated)'; + // constructor(public _rxdb: RxDBCoreService) {} } diff --git a/apps/demo-angular/src/plugin-demos/rxstorage-sqlite/sqlite-rxstorage.component.ts b/apps/demo-angular/src/plugin-demos/rxstorage-sqlite/sqlite-rxstorage.component.ts index 9beed42..069d87c 100644 --- a/apps/demo-angular/src/plugin-demos/rxstorage-sqlite/sqlite-rxstorage.component.ts +++ b/apps/demo-angular/src/plugin-demos/rxstorage-sqlite/sqlite-rxstorage.component.ts @@ -25,5 +25,11 @@ import { HeroComponent } from '../shared/hero.component'; }) export class NativescriptSQLiteRxstorageComponent { adapter = 'SQLite RxStorage Adapter'; - constructor(public _rxdb: RxDBCoreService) {} + constructor(public _rxdb: RxDBCoreService) { + setTimeout(() => { + this._rxdb.heros$.subscribe((heroes) => { + console.log('Heroes:', heroes); + }); + }, 5000); + } } diff --git a/apps/demo-angular/src/plugin-demos/shared/hero.component.ts b/apps/demo-angular/src/plugin-demos/shared/hero.component.ts index 24d64b1..c5113a2 100644 --- a/apps/demo-angular/src/plugin-demos/shared/hero.component.ts +++ b/apps/demo-angular/src/plugin-demos/shared/hero.component.ts @@ -3,11 +3,12 @@ import { NativeScriptCommonModule } from '@nativescript/angular'; import { Dialogs } from '@nativescript/core'; import { RxDBCoreService } from '../../replicator/rxdb-service'; import { RxHeroDocumentType } from '../../schemas/hero.schema'; +import { RxDocument } from 'rxdb'; @Component({ selector: 'app-hero', template: ` - + @@ -30,7 +31,7 @@ import { RxHeroDocumentType } from '../../schemas/hero.schema'; schemas: [NO_ERRORS_SCHEMA], }) export class HeroComponent { - @Input() hero!: RxHeroDocumentType; + @Input() hero!: RxDocument; _rxdb = inject(RxDBCoreService); onTap() { @@ -45,4 +46,17 @@ export class HeroComponent { } }); } + + deleteHero() { + Dialogs.confirm({ + title: 'Delete hero', + message: `Are you sure you want to delete ${this.hero.name}?`, + cancelButtonText: 'Cancel', + okButtonText: 'Delete', + }).then((result) => { + if (result) { + this.hero.remove(); + } + }); + } } diff --git a/apps/demo-angular/src/polyfills.ts b/apps/demo-angular/src/polyfills.ts index bb1882a..ac9e2d7 100644 --- a/apps/demo-angular/src/polyfills.ts +++ b/apps/demo-angular/src/polyfills.ts @@ -18,5 +18,9 @@ import '@nativescript/zone-js/dist/pre-zone-polyfills'; // Zone JS is required by default for Angular itself import 'zone.js'; +import './zone-disable'; + +import 'zone.js/plugins/zone-patch-rxjs'; + // Add NativeScript specific Zone JS patches import '@nativescript/zone-js'; diff --git a/apps/demo-angular/src/replicator/graphql-plugin.ts b/apps/demo-angular/src/replicator/graphql-plugin.ts deleted file mode 100644 index fd3028f..0000000 --- a/apps/demo-angular/src/replicator/graphql-plugin.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { Client, createClient } from 'graphql-ws'; -import * as objectPath from 'object-path'; -import { RxCollection, SyncOptionsGraphQL, RxReplicationPullStreamItem, WithDeleted, RxReplicationWriteToMasterRow, fastUnsecureHash, ensureNotFalsy, RxPlugin, lastOfArray } from 'rxdb'; -import { ReplicationPullOptions, ReplicationPushOptions } from 'rxdb/dist/types/types/plugins/replication'; -import { startReplicationOnLeaderShip } from 'rxdb/plugins/replication'; -import { GRAPHQL_REPLICATION_PLUGIN_IDENTITY_PREFIX, GRAPHQL_WEBSOCKET_BY_URL, removeGraphQLWebSocketRef, RxGraphQLReplicationState } from 'rxdb/plugins/replication-graphql'; -import { Subject } from 'rxjs'; - -/** - * From RxDB 13 the GraphQL replication plugin requires each action to provide a - * documents and checkpoint. Because we're using Hasura for the demo it would mean - * we would need to create custom actions for every replicated table. - * - * This plugin is a work-around from the intended method so that it behaves like previous - * versions of RxDB. - * - * Original plugin: https://github.com/pubkey/rxdb/tree/master/src/plugins/replication-graphql - */ -/** - * UPDATE: 2023-03-16 - * - * Hasura added in streaming support for GraphQL subscriptions. This means we can - * use the standard GraphQL replication plugin with the standard modifiers. This - * plugin is no longer required. - */ - -/** - * Standard getGraphQLWebSocket definition doesn't allow adding connection params only the url. - * Fixes document/checkpoint results. - */ -function getGraphQLWebSocket(url: string, headers = {}): Client { - let has = GRAPHQL_WEBSOCKET_BY_URL.get(url); - if (!has) { - const wsClient = createClient({ - url, - retryAttempts: Number.MAX_SAFE_INTEGER, - shouldRetry: () => true, - connectionParams: { - headers, - }, - }); - has = { - url, - socket: wsClient, - refCount: 1, - }; - GRAPHQL_WEBSOCKET_BY_URL.set(url, has); - } else { - has.refCount = has.refCount + 1; - } - return has.socket; -} - -function getCheckpoint(data: any[], lastCheckpoint) { - const lastDoc = lastOfArray(data); - return { - id: lastDoc?.id ?? lastCheckpoint?.id ?? '', - updatedAt: lastDoc?.updatedAt ?? lastCheckpoint?.updatedAt ?? new Date(0).toISOString(), - }; -} - -/** - * Fixes document/checkpoint results. - */ -function syncHasuraGraphQL( - this: RxCollection, - { - url, - headers = {}, - credentials, - deletedField = '_deleted', - waitForLeadership = true, - pull, - push, - live = true, - retryTime = 1000 * 5, // in ms - autoStart = true, - }: SyncOptionsGraphQL -): RxGraphQLReplicationState { - // eslint-disable-next-line @typescript-eslint/no-this-alias - const collection = this; - - /** - * We use this object to store the GraphQL client - * so we can later swap out the client inside of the replication handlers. - */ - const mutateableClientState = { - headers, - credentials, - }; - - const pullStream$: Subject> = new Subject(); - - let replicationPrimitivesPull: ReplicationPullOptions | undefined; - if (pull) { - const pullBatchSize = pull.batchSize ? pull.batchSize : 20; - replicationPrimitivesPull = { - async handler(lastPulledCheckpoint: CheckpointType) { - const pullGraphQL = await pull.queryBuilder(lastPulledCheckpoint, pullBatchSize); - const result = await graphqlReplicationState.graphQLRequest(pullGraphQL); - - if (result.errors) { - throw result.errors; - } - - const dataPath = pull.dataPath || ['data', Object.keys(result.data)[0]]; - let data: any = objectPath.get(result, dataPath); - - if (pull.responseModifier) { - data = await pull.responseModifier(data, 'handler', lastPulledCheckpoint); - } - - // const docsData: WithDeleted[] = data.documents; - // const newCheckpoint = data.checkpoint; - const docsData: WithDeleted[] = data; - const newCheckpoint = getCheckpoint(docsData, lastPulledCheckpoint); - - return { - documents: docsData, - checkpoint: newCheckpoint, - } as any; - }, - batchSize: pull.batchSize, - modifier: pull.modifier, - stream$: pullStream$.asObservable(), - }; - } - let replicationPrimitivesPush: ReplicationPushOptions | undefined; - if (push) { - replicationPrimitivesPush = { - async handler(rows: RxReplicationWriteToMasterRow[]) { - const pushObj = await push.queryBuilder(rows); - const result = await graphqlReplicationState.graphQLRequest(pushObj); - - if (result.errors) { - throw result.errors; - } - - // const dataPath = Object.keys(result.data)[0]; - // const data: any = objectPath.get(result.data, dataPath); - // return data; - return []; - }, - batchSize: push.batchSize, - modifier: push.modifier, - }; - } - - const graphqlReplicationState = new RxGraphQLReplicationState(url, mutateableClientState, GRAPHQL_REPLICATION_PLUGIN_IDENTITY_PREFIX + fastUnsecureHash(url.http ? url.http : (url.ws as any)), collection, deletedField, replicationPrimitivesPull, replicationPrimitivesPush, live, retryTime, autoStart); - - const mustUseSocket = url.ws && pull && pull.streamQueryBuilder && live; - - const startBefore = graphqlReplicationState.start.bind(graphqlReplicationState); - graphqlReplicationState.start = () => { - if (mustUseSocket) { - const wsClient = getGraphQLWebSocket(ensureNotFalsy(url.ws), mutateableClientState.headers); - - wsClient.on('connected', () => { - pullStream$.next('RESYNC'); - }); - - const query: any = ensureNotFalsy(pull.streamQueryBuilder)(mutateableClientState.headers); - - wsClient.subscribe(query, { - next: async (streamResponse: any) => { - pullStream$.next('RESYNC'); - // const firstField = Object.keys(streamResponse.data)[0]; - // const docsData = streamResponse.data[firstField]; - // const newCheckpoint = getCheckpoint( - // streamResponse.data[firstField], - // {} - // ); - // pullStream$.next({ - // documents: docsData, - // checkpoint: newCheckpoint, - // } as any); - }, - error: (error: any) => { - pullStream$.error(error); - }, - complete: () => { - pullStream$.complete(); - }, - }); - } - return startBefore(); - }; - - const cancelBefore = graphqlReplicationState.cancel.bind(graphqlReplicationState); - graphqlReplicationState.cancel = () => { - pullStream$.complete(); - if (mustUseSocket) { - removeGraphQLWebSocketRef(ensureNotFalsy(url.ws)); - } - return cancelBefore(); - }; - - startReplicationOnLeaderShip(waitForLeadership, graphqlReplicationState); - return graphqlReplicationState; -} - -export const RxDBReplicationHasuraGraphQLPlugin: RxPlugin = { - name: 'replication-hasura-graphql', - init() { - // Leader election isn't required on a single application level. - // addRxPlugin(RxDBLeaderElectionPlugin); - }, - rxdb: true, - prototypes: { - RxCollection: (proto: any) => { - proto.syncGraphQL = syncHasuraGraphQL; - }, - }, -}; diff --git a/apps/demo-angular/src/replicator/query-builder.ts b/apps/demo-angular/src/replicator/query-builder.ts index 93c8cef..3b34e7d 100644 --- a/apps/demo-angular/src/replicator/query-builder.ts +++ b/apps/demo-angular/src/replicator/query-builder.ts @@ -1,11 +1,11 @@ export const pushQueryBuilder = (docs) => { // remove rxdb metadata before push const query = `mutation - hero ($doc: [hero_insert_input!]!) { - insert_hero( + InsertHero ($doc: [heroes_insert_input!]!) { + insert_heroes( objects: $doc, on_conflict: { - constraint: hero_pkey, + constraint: heroes_pkey, update_columns: [ name, color, deleted, updatedAt, createdAt ] @@ -29,8 +29,8 @@ export const pushQueryBuilder = (docs) => { export const pullQueryBuilder = (checkpoint, limit) => { // the first pull does not have a start-document const sortByValue = checkpoint ? checkpoint['updatedAt'] : new Date(0).toISOString(); - const query = `query MyQuery { - hero(where: {updatedAt: {_gt: "${sortByValue}"}}, order_by: {updatedAt: asc}, limit: ${limit}) { + const query = `query GetHeroes { + heroes(where: {updatedAt: {_gt: "${sortByValue}"}}, order_by: {updatedAt: asc}, limit: ${limit}) { color createdAt deleted @@ -51,7 +51,7 @@ export const pullStreamQueryBuilder = (headers) => { const sortByValue = new Date().toISOString(); const query = `subscription HeroSubscription { - hero_stream(cursor: {initial_value: {updatedAt: "${sortByValue}"}}, batch_size: ${limit}) { + heroes_stream(cursor: {initial_value: {updatedAt: "${sortByValue}"}}, batch_size: ${limit}) { color createdAt deleted diff --git a/apps/demo-angular/src/replicator/rxdb-service.ts b/apps/demo-angular/src/replicator/rxdb-service.ts index b8f9c9d..c9fd579 100644 --- a/apps/demo-angular/src/replicator/rxdb-service.ts +++ b/apps/demo-angular/src/replicator/rxdb-service.ts @@ -1,7 +1,8 @@ -import { Inject, Injectable, InjectionToken, OnDestroy } from '@angular/core'; +import { Inject, Injectable, InjectionToken, Injector, OnDestroy, Signal, untracked } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; import { Dialogs, isAndroid, isIOS } from '@nativescript/core'; -import { addRxPlugin, createRxDatabase, lastOfArray, RxDatabase, RxDocument } from 'rxdb'; -import { distinctUntilChanged, Subject, takeUntil } from 'rxjs'; +import { addRxPlugin, createRxDatabase, lastOfArray, RxDatabase, RxDocument, RxReactivityFactory } from 'rxdb'; +import { distinctUntilChanged, Observable, Subject, takeUntil } from 'rxjs'; import { replicateGraphQL } from 'rxdb/plugins/replication-graphql'; import { RxDBQueryBuilderPlugin } from 'rxdb/plugins/query-builder'; import { pullQueryBuilder, pushQueryBuilder, pullStreamQueryBuilder } from './query-builder'; @@ -31,35 +32,49 @@ export class RxDBCoreService implements OnDestroy { database: RxDatabase; private destroy$ = new Subject(); - constructor(@Inject(RXDB_STORAGE) private rxdbStorage: RxDBStorage) { + constructor(@Inject(RXDB_STORAGE) private rxdbStorage: RxDBStorage, private injector: Injector) { addRxPlugin(RxDBQueryBuilderPlugin); addRxPlugin(RxDBDevModePlugin); - this.initDb(); + this.initDb(this.injector); } uuid() { - if (isAndroid) { - return java.util.UUID.randomUUID().toString(); - } else { - return NSUUID.UUID().UUIDString.toLowerCase(); - } + return crypto.randomUUID(); } - async initDb() { + async initDb(injector: Injector) { + const reactivityFactory: RxReactivityFactory> = { + fromObservable(obs, initialValue: any) { + return untracked(() => + toSignal(obs, { + initialValue, + injector, + rejectErrors: true, + }) + ); + }, + }; + + const { wrappedValidateAjvStorage } = await import('rxdb/plugins/validate-ajv'); + const storage = wrappedValidateAjvStorage({ + storage: this.rxdbStorage as any, + }); + console.log('Creating Database'); this.database = await createRxDatabase({ name: 'exampledb', - storage: this.rxdbStorage as any, + storage: storage, multiInstance: false, ignoreDuplicate: true, + reactivity: reactivityFactory, }); console.log('Creating Collections'); await this.database.addCollections({ heroes: { schema: HERO_SCHEMA, - statics: { + methods: { async addHero(name, color) { return this.upsert({ id: this.uuid(), @@ -81,8 +96,8 @@ export class RxDBCoreService implements OnDestroy { >({ collection: this.database.heroes, url: { - http: 'https://working-oriole-73.hasura.app/v1/graphql', - ws: 'wss://working-oriole-73.hasura.app/v1/graphql', + http: 'https://together-seahorse-29.hasura.app/v1/graphql', + ws: 'wss://together-seahorse-29.hasura.app/v1/graphql', }, push: { batchSize, @@ -105,6 +120,7 @@ export class RxDBCoreService implements OnDestroy { live: true, autoStart: true, waitForLeadership: false, + replicationIdentifier: 'rxdbHeroesReplication', deletedField: 'deleted', }); @@ -163,13 +179,12 @@ export class RxDBCoreService implements OnDestroy { for (let i = 0; i < 100; i++) { const date = '2023-01-18T13:00:00.000Z'; const color = '#' + (0x1000000 + Math.random() * 0xffffff).toString(16).substr(1, 6); - await this.database?.heroes.upsert({ + await this.database.heroes.upsert({ id: id, name: `hero ${i}`, color, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), - deleted: false, }); } }; @@ -186,6 +201,6 @@ export class RxDBCoreService implements OnDestroy { ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); - this.database.destroy(); + this.database.remove(); } } diff --git a/apps/demo-angular/src/schemas/hero.schema.ts b/apps/demo-angular/src/schemas/hero.schema.ts index b8df145..1dab2da 100644 --- a/apps/demo-angular/src/schemas/hero.schema.ts +++ b/apps/demo-angular/src/schemas/hero.schema.ts @@ -30,7 +30,7 @@ export const HERO_SCHEMA_LITERAL = { // type: 'boolean', // } }, - required: ['id', 'name'], + required: ['id', 'name', 'color'], } as const; const schemaTyped = toTypedRxJsonSchema(HERO_SCHEMA_LITERAL); diff --git a/apps/demo-angular/src/zone-disable.ts b/apps/demo-angular/src/zone-disable.ts new file mode 100644 index 0000000..fa48145 --- /dev/null +++ b/apps/demo-angular/src/zone-disable.ts @@ -0,0 +1 @@ +global['__Zone_disable_nativescript_FileReader'] = true; diff --git a/package.json b/package.json index 2b4697b..565521c 100644 --- a/package.json +++ b/package.json @@ -16,33 +16,33 @@ }, "private": true, "devDependencies": { - "@angular-devkit/build-angular": "^15.0.0", - "@angular/animations": "^15.0.0", - "@angular/common": "^15.0.0", - "@angular/compiler": "^15.0.0", - "@angular/compiler-cli": "^15.0.0", - "@angular/core": "^15.0.0", - "@angular/forms": "^15.0.0", - "@angular/platform-browser": "^15.0.0", - "@angular/platform-browser-dynamic": "^15.0.0", - "@angular/router": "^15.0.0", + "@angular-devkit/build-angular": "^19.0.0", + "@angular/animations": "^19.0.0", + "@angular/common": "^19.0.0", + "@angular/compiler": "^19.0.0", + "@angular/compiler-cli": "^19.0.0", + "@angular/core": "^19.0.0", + "@angular/forms": "^19.0.0", + "@angular/platform-browser": "^19.0.0", + "@angular/platform-browser-dynamic": "^19.0.0", + "@angular/router": "^19.0.0", "@nano-sql/core": "^2.3.7", "@nativescript-community/typeorm": "^0.2.29", - "@nativescript/angular": "^15.0.0", - "@nativescript/core": "~8.4.0", + "@nativescript/angular": "^19.0.0", + "@nativescript/core": "~8.9.0", "@nativescript/plugin-tools": "4.0.1", - "@nativescript/types": "~8.4.0", - "@nativescript/webpack": "~5.0.12", - "@ngtools/webpack": "^15.0.0", + "@nativescript/types": "~8.9.0", + "@nativescript/webpack": "~5.0.24", + "@ngtools/webpack": "^19.0.0", "husky": "^8.0.0", "nativescript-permissions": "1.3.11", "nativescript-vue": "~2.9.0", "nativescript-vue-template-compiler": "~2.9.0", - "ng-packagr": "^15.0.0", + "ng-packagr": "^19.0.0", "nx": "15.8.6", "rxjs": "~7.8.0", - "typescript": "~4.8.0", - "zone.js": "~0.12.0" + "typescript": "~5.6.0", + "zone.js": "~0.15.0" }, "lint-staged": { "**/*.{js,ts,scss,json,html}": [ @@ -51,14 +51,13 @@ }, "dependencies": { "@nativescript-community/sqlite": "^3.4.1", - "@valor/nativescript-websockets": "^1.0.2", + "@valor/nativescript-websockets": "^2.0.2", "app-root-path": "^3.1.0", - "graphql-ws": "^5.11.1", + "graphql-ws": "^6.0.4", "lokijs": "^1.5.12", - "nativescript-md5": "^1.0.1", "object-path": "^0.11.8", "patch-package": "^6.4.7", - "rxdb": "14.4.0", - "rxdb-premium": "14.3.6" + "rxdb": "16.11.0", + "rxdb-premium": "16.11.0" } } diff --git a/packages/nativescript-md5/.eslintrc.json b/packages/nativescript-md5/.eslintrc.json deleted file mode 100644 index 53c06c8..0000000 --- a/packages/nativescript-md5/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "node_modules/**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/packages/nativescript-md5/README.md b/packages/nativescript-md5/README.md deleted file mode 100644 index c7b8e1d..0000000 --- a/packages/nativescript-md5/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# @rxdb/nativescript-md5 - -```javascript -npm i @rxdb/nativescript-md5 -``` - -## Usage - -// TODO - -## License - -Apache License Version 2.0 diff --git a/packages/nativescript-md5/common.ts b/packages/nativescript-md5/common.ts deleted file mode 100644 index dddd638..0000000 --- a/packages/nativescript-md5/common.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class Utils { - static numberToZedoPadHex(n: number): string { - if (typeof n !== 'number') { - return ''; - } - const hex = n.toString(16); - return hex.length === 1 ? '0' + hex : hex; - } -} diff --git a/packages/nativescript-md5/index.android.ts b/packages/nativescript-md5/index.android.ts deleted file mode 100644 index efcdb61..0000000 --- a/packages/nativescript-md5/index.android.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { INativescriptMd5 } from '.'; -import { Utils } from './common'; - -export class NativescriptMd5 implements INativescriptMd5 { - hashForString(s: string): string { - let hash = ''; - try { - const digest = java.security.MessageDigest.getInstance('MD5'); - const javaString = new java.lang.String(s); - digest.update(javaString.getBytes()); - const messageDigest = digest.digest(); - - for (let i = 0; i < messageDigest.length; i++) { - const hex = Utils.numberToZedoPadHex(0xff & messageDigest[i]); - hash += hex; - } - return hash; - } catch (err) { - console.error('failed to create hash. ', err); - return ''; - } - } -} diff --git a/packages/nativescript-md5/index.d.ts b/packages/nativescript-md5/index.d.ts deleted file mode 100644 index e1b2ef3..0000000 --- a/packages/nativescript-md5/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface INativescriptMd5 { - static hashForString(params: type): string; -} - -export class NativescriptMd5 implements INativescriptMd5 { - static hashForString(params: string): string; -} diff --git a/packages/nativescript-md5/index.ios.ts b/packages/nativescript-md5/index.ios.ts deleted file mode 100644 index 9c9589c..0000000 --- a/packages/nativescript-md5/index.ios.ts +++ /dev/null @@ -1 +0,0 @@ -export class NativescriptMd5 {} diff --git a/packages/nativescript-md5/package.json b/packages/nativescript-md5/package.json deleted file mode 100644 index b052333..0000000 --- a/packages/nativescript-md5/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@herefishyfish/nativescript-md5", - "version": "1.0.0", - "description": "Add a plugin description", - "main": "index", - "typings": "index.d.ts", - "nativescript": { - "platforms": { - "ios": "6.0.0", - "android": "6.0.0" - } - }, - "repository": { - "type": "git", - "url": "https://github.com/herefishyfish/rxdb-nativescript.git" - }, - "keywords": [ - "NativeScript", - "JavaScript", - "TypeScript", - "iOS", - "Android" - ], - "author": { - "name": "Dylan Llewellyn", - "email": "dylan@herefushy.dev" - }, - "bugs": { - "url": "https://github.com/herefishyfish/rxdb-nativescript/issues" - }, - "license": "Apache-2.0", - "homepage": "https://github.com/herefishyfish/rxdb-nativescript", - "readmeFilename": "README.md", - "bootstrapper": "@nativescript/plugin-seed" -} diff --git a/packages/nativescript-md5/pouch-db/index.ts b/packages/nativescript-md5/pouch-db/index.ts deleted file mode 100644 index 887df57..0000000 --- a/packages/nativescript-md5/pouch-db/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -// import crypto from 'crypto'; -// import { MD5 } from 'nativescript-md5'; - -import { NativescriptMd5 } from '..'; - -function binaryMd5(data, callback) { - // var base64 = crypto.createHash('md5').update(data, 'binary').digest('base64'); - callback(NativescriptMd5.hashForString(data)); -} - -function stringMd5(string) { - return NativescriptMd5.hashForString(string); - // return crypto.createHash('md5').update(string, 'binary').digest('hex'); -} - -export { binaryMd5, stringMd5 }; diff --git a/packages/nativescript-md5/project.json b/packages/nativescript-md5/project.json deleted file mode 100644 index 16d1529..0000000 --- a/packages/nativescript-md5/project.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "packages/nativescript-md5", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "options": { - "outputPath": "dist/packages/nativescript-md5", - "tsConfig": "packages/nativescript-md5/tsconfig.json", - "packageJson": "packages/nativescript-md5/package.json", - "main": "packages/nativescript-md5/index.d.ts", - "assets": [ - "packages/nativescript-md5/*.md", - "packages/nativescript-md5/index.d.ts", - "LICENSE", - { - "glob": "**/*", - "input": "packages/nativescript-md5/platforms/", - "output": "./platforms/" - } - ], - "dependsOn": [ - { - "target": "build.all", - "projects": "dependencies" - } - ] - } - }, - "build.all": { - "executor": "@nrwl/workspace:run-commands", - "options": { - "commands": ["node tools/scripts/build-finish.ts nativescript-md5"], - "parallel": false - }, - "outputs": ["dist/packages/nativescript-md5"], - "dependsOn": [ - { - "target": "build.all", - "projects": "dependencies" - }, - { - "target": "build", - "projects": "self" - } - ] - }, - "focus": { - "executor": "@nrwl/workspace:run-commands", - "options": { - "commands": ["nx g @nativescript/plugin-tools:focus-packages nativescript-md5"], - "parallel": false - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "options": { - "lintFilePatterns": ["packages/nativescript-md5/**/*.ts"] - } - } - }, - "tags": [] -} diff --git a/packages/nativescript-md5/references.d.ts b/packages/nativescript-md5/references.d.ts deleted file mode 100644 index 22bac92..0000000 --- a/packages/nativescript-md5/references.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/nativescript-md5/tsconfig.json b/packages/nativescript-md5/tsconfig.json deleted file mode 100644 index aed7323..0000000 --- a/packages/nativescript-md5/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "rootDir": "." - }, - "exclude": ["**/*.spec.ts", "**/*.test.ts", "angular"], - "include": ["**/*.ts", "references.d.ts"] -} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/.eslintrc.json b/packages/nativescript-pouchdb-sqlite-adapter/.eslintrc.json deleted file mode 100644 index 53c06c8..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "node_modules/**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/README.md b/packages/nativescript-pouchdb-sqlite-adapter/README.md deleted file mode 100644 index c0fe269..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# @herefishyfish/nativescript-pouchdb-sqlite-adapter - -```javascript -ns plugin add @herefishyfish/nativescript-pouchdb-sqlite-adapter -``` - -## Usage - -// TODO - -## License - -Apache License Version 2.0 diff --git a/packages/nativescript-pouchdb-sqlite-adapter/common.ts b/packages/nativescript-pouchdb-sqlite-adapter/common.ts deleted file mode 100644 index 737875b..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/common.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Observable } from '@nativescript/core'; - -export class NativescriptPouchdbSqliteAdapterCommon extends Observable {} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/index.android.ts b/packages/nativescript-pouchdb-sqlite-adapter/index.android.ts deleted file mode 100644 index 59642b6..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/index.android.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { NativescriptPouchdbSqliteAdapterCommon } from './common'; - -export class NativescriptPouchdbSqliteAdapter extends NativescriptPouchdbSqliteAdapterCommon {} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/index.d.ts b/packages/nativescript-pouchdb-sqlite-adapter/index.d.ts deleted file mode 100644 index 155654e..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { NativescriptPouchdbSqliteAdapterCommon } from './common'; - -export declare class NativescriptPouchdbSqliteAdapter extends NativescriptPouchdbSqliteAdapterCommon {} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/index.ios.ts b/packages/nativescript-pouchdb-sqlite-adapter/index.ios.ts deleted file mode 100644 index 59642b6..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/index.ios.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { NativescriptPouchdbSqliteAdapterCommon } from './common'; - -export class NativescriptPouchdbSqliteAdapter extends NativescriptPouchdbSqliteAdapterCommon {} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/package.json b/packages/nativescript-pouchdb-sqlite-adapter/package.json deleted file mode 100644 index 7812866..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@herefishyfish/nativescript-pouchdb-sqlite-adapter", - "version": "1.0.0", - "description": "Add a plugin description", - "main": "index", - "typings": "index.d.ts", - "nativescript": { - "platforms": { - "ios": "6.0.0", - "android": "6.0.0" - } - }, - "repository": { - "type": "git", - "url": "https://github.com/herefishyfish/rxdb-nativescript.git" - }, - "keywords": [ - "NativeScript", - "JavaScript", - "TypeScript", - "iOS", - "Android" - ], - "author": { - "name": "Dylan Llewellyn", - "email": "dylan@herefishy.dev" - }, - "bugs": { - "url": "https://github.com/herefishyfish/rxdb-nativescript/issues" - }, - "license": "Apache-2.0", - "homepage": "https://github.com/herefishyfish/rxdb-nativescript", - "readmeFilename": "README.md", - "bootstrapper": "@nativescript/plugin-seed" -} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/project.json b/packages/nativescript-pouchdb-sqlite-adapter/project.json deleted file mode 100644 index b6b80cf..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/project.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "packages/nativescript-pouchdb-sqlite-adapter", - "targets": { - "build": { - "executor": "@nrwl/js:tsc", - "options": { - "outputPath": "dist/packages/nativescript-pouchdb-sqlite-adapter", - "tsConfig": "packages/nativescript-pouchdb-sqlite-adapter/tsconfig.json", - "packageJson": "packages/nativescript-pouchdb-sqlite-adapter/package.json", - "main": "packages/nativescript-pouchdb-sqlite-adapter/index.d.ts", - "assets": [ - "packages/nativescript-pouchdb-sqlite-adapter/*.md", - "packages/nativescript-pouchdb-sqlite-adapter/index.d.ts", - "LICENSE", - { - "glob": "**/*", - "input": "packages/nativescript-pouchdb-sqlite-adapter/platforms/", - "output": "./platforms/" - } - ], - "dependsOn": [ - { - "target": "build.all", - "projects": "dependencies" - } - ] - } - }, - "build.all": { - "executor": "@nrwl/workspace:run-commands", - "options": { - "commands": ["node tools/scripts/build-finish.ts nativescript-pouchdb-sqlite-adapter"], - "parallel": false - }, - "outputs": ["dist/packages/nativescript-pouchdb-sqlite-adapter"], - "dependsOn": [ - { - "target": "build.all", - "projects": "dependencies" - }, - { - "target": "build", - "projects": "self" - } - ] - }, - "focus": { - "executor": "@nrwl/workspace:run-commands", - "options": { - "commands": ["nx g @nativescript/plugin-tools:focus-packages nativescript-pouchdb-sqlite-adapter"], - "parallel": false - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "options": { - "lintFilePatterns": ["packages/nativescript-pouchdb-sqlite-adapter/**/*.ts"] - } - } - }, - "tags": [] -} diff --git a/packages/nativescript-pouchdb-sqlite-adapter/references.d.ts b/packages/nativescript-pouchdb-sqlite-adapter/references.d.ts deleted file mode 100644 index 22bac92..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/references.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/nativescript-pouchdb-sqlite-adapter/tsconfig.json b/packages/nativescript-pouchdb-sqlite-adapter/tsconfig.json deleted file mode 100644 index aed7323..0000000 --- a/packages/nativescript-pouchdb-sqlite-adapter/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "rootDir": "." - }, - "exclude": ["**/*.spec.ts", "**/*.test.ts", "angular"], - "include": ["**/*.ts", "references.d.ts"] -} diff --git a/packages/nativescript-rxdb/index.ts b/packages/nativescript-rxdb/index.ts deleted file mode 100644 index 2f7e3c7..0000000 --- a/packages/nativescript-rxdb/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './uuid'; diff --git a/packages/nativescript-rxdb/isomorphic-ws/index.ts b/packages/nativescript-rxdb/isomorphic-ws/index.ts deleted file mode 100644 index cee3a22..0000000 --- a/packages/nativescript-rxdb/isomorphic-ws/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { WebSocket } from 'ws'; - -export default { WebSocket: WebSocket }; diff --git a/packages/nativescript-rxdb/nativescript.webpack.js b/packages/nativescript-rxdb/nativescript.webpack.js index e7da843..56dae65 100644 --- a/packages/nativescript-rxdb/nativescript.webpack.js +++ b/packages/nativescript-rxdb/nativescript.webpack.js @@ -1,22 +1,11 @@ const { resolve } = require('path'); const appRoot = require('app-root-path'); -const { ProvidePlugin, NormalModuleReplacementPlugin } = require('webpack'); module.exports = (webpack) => { webpack.chainWebpack((config) => { const nodeModulesPath = webpack.Utils.project.getProjectFilePath('node_modules'); - config.plugin('ProvidePlugin|Polyfills').use(ProvidePlugin, [ - { - Buffer: [require.resolve('buffer/'), 'Buffer'], - }, - ]); - // Fix and patch imports - config.resolve.alias.set('ws', resolve(nodeModulesPath, '@valor/nativescript-websockets')); - config.resolve.alias.set('pouchdb-md5', resolve(nodeModulesPath, '@herefishyfish/nativescript-rxdb/pouchdb')); - config.resolve.alias.set('uuid', resolve(nodeModulesPath, '@herefishyfish/nativescript-rxdb/uuid')); - // config.resolve.alias.set('isomorphic-ws', resolve(nodeModulesPath, '@herefishyfish/nativescript-rxdb/isomorphic-ws')); config.resolve.alias.set('isomorphic-ws', resolve(appRoot.path, './node_modules/isomorphic-ws/browser.js')); config.resolve.alias.set('isomorphic-fetch', resolve(nodeModulesPath, '@nativescript/core')); config.resolve.alias.set('broadcast-channel', resolve(appRoot.path, './node_modules/broadcast-channel/dist/esbrowser')); diff --git a/packages/nativescript-rxdb/pouchdb/index.ts b/packages/nativescript-rxdb/pouchdb/index.ts deleted file mode 100644 index 89562ba..0000000 --- a/packages/nativescript-rxdb/pouchdb/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { MD5 } from 'nativescript-md5'; - -export function binaryMd5(data, callback) { - callback(MD5.hashForString(data)); -} - -export function stringMd5(string) { - return MD5.hashForString(string); -} diff --git a/packages/nativescript-sqlite-rxstorage-adapter/index.ts b/packages/nativescript-sqlite-rxstorage-adapter/index.ts index 30303f8..74eac6f 100644 --- a/packages/nativescript-sqlite-rxstorage-adapter/index.ts +++ b/packages/nativescript-sqlite-rxstorage-adapter/index.ts @@ -1,7 +1,6 @@ -type SQLiteQueryWithParams = any; import { knownFolders, path } from '@nativescript/core'; import { openOrCreate, SQLiteDatabase } from '@herefishyfish/requery-sqlite'; -import { SQLiteBasics } from 'rxdb-premium/plugins/storage-sqlite'; +import { SQLiteBasics, SQLResultRow, SQLiteQueryWithParams } from 'rxdb-premium/plugins/storage-sqlite'; export interface ISQLiteDatabaseAdapterOptions { transformBlobs?: boolean; @@ -20,13 +19,13 @@ export const getSQLiteBasicsNativeScript = (options?: ISQLiteDatabaseAdapterOpti ...(options ?? {}), }); }, - all: async (db: SQLiteDatabase, queryWithParams: SQLiteQueryWithParams) => { - return (await db.select(queryWithParams.query, queryWithParams.params ?? [])) as any; + all: async (db: SQLiteDatabase, queryWithParams: SQLiteQueryWithParams): Promise => { + return db.select(queryWithParams.query, queryWithParams.params ?? []); }, run: async (db: SQLiteDatabase, queryWithParams: SQLiteQueryWithParams) => { - await db.select(queryWithParams.query, queryWithParams.params ?? []); + return db.select(queryWithParams.query, queryWithParams.params ?? []); }, - close: (db: SQLiteDatabase) => { + close: async (db: SQLiteDatabase) => { return db.close(); }, journalMode: '', diff --git a/packages/requery-sqlite/platforms/android/include.gradle b/packages/requery-sqlite/platforms/android/include.gradle index 6e40a7f..6ef0d65 100644 --- a/packages/requery-sqlite/platforms/android/include.gradle +++ b/packages/requery-sqlite/platforms/android/include.gradle @@ -5,6 +5,6 @@ } dependencies { - implementation 'com.github.requery:sqlite-android:3.39.2' + implementation 'com.github.requery:sqlite-android:3.45.0' implementation 'androidx.sqlite:sqlite:2.1.0' } diff --git a/packages/requery-sqlite/sqlite.android.ts b/packages/requery-sqlite/sqlite.android.ts index 99d5951..fcdf6f5 100644 --- a/packages/requery-sqlite/sqlite.android.ts +++ b/packages/requery-sqlite/sqlite.android.ts @@ -37,6 +37,19 @@ export class SQLiteDatabase extends SQLiteDatabaseBase { } } +export function wrapDb( + db: io.requery.android.database.sqlite.SQLiteDatabase, + options?: { + readOnly?: boolean; + transformBlobs?: boolean; + threading?: boolean; + } +): SQLiteDatabase { + const obj = new SQLiteDatabase(db, options); + obj.open(); + return obj; +} + export const openOrCreate = ( filePath: string, options?: { diff --git a/packages/requery-sqlite/sqlite.common.ts b/packages/requery-sqlite/sqlite.common.ts index 0cc65c7..63163da 100644 --- a/packages/requery-sqlite/sqlite.common.ts +++ b/packages/requery-sqlite/sqlite.common.ts @@ -11,13 +11,13 @@ export type Db = any; export type SqliteUpgrade = (db: Db) => void; export interface SQLiteDatabase { - getVersion(): Promise; + getVersion(); - setVersion(version: number): Promise; + setVersion(version: number); isOpen: boolean; - close(): Promise; + close(); select(query: string, params?: SqliteParams): Promise; @@ -31,7 +31,7 @@ export interface SQLiteDatabase { transaction(action: (cancel?: () => void) => Promise): Promise; - each(query: string, params: SqliteParams, callback: (error: Error, result: SqliteRow) => void, complete: (error: Error, count: number) => void): Promise; + each(query: string, params: SqliteParams, callback: (error: Error, result: SqliteRow) => void, complete: (error: Error, count: number) => void): Promise; } export function isNothing(x: any) { diff --git a/packages/requery-sqlite/sqlite.ios.ts b/packages/requery-sqlite/sqlite.ios.ts index a536f0d..4680840 100644 --- a/packages/requery-sqlite/sqlite.ios.ts +++ b/packages/requery-sqlite/sqlite.ios.ts @@ -1,6 +1,4 @@ -import { SqliteParam, SqliteParams, SqliteRow, paramsToStringArray, throwError } from './sqlite.common'; - -declare const strlen: any; +import { SQLiteDatabase as ISQLiteDatabase, SqliteParam, SqliteParams, SqliteRow, paramsToStringArray, throwError } from './sqlite.common'; const iosProperty = (_self, property: T): T => { if (typeof property === 'function') { @@ -12,13 +10,13 @@ const iosProperty = (_self, property: T): T => { } }; -const toCharPtr = (str: string) => { - const objcStr = NSString.stringWithString(str); - const size = strlen(objcStr.UTF8String) + 1; - const buffer = interop.alloc(size) as any; - objcStr.getCStringMaxLengthEncoding(buffer, size, NSUTF8StringEncoding); - return buffer; -}; +// const toCharPtr = (str: string) => { +// const objcStr = NSString.stringWithString(str); +// const size = strlen(objcStr.UTF8String) + 1; +// const buffer = interop.alloc(size) as any; +// objcStr.getCStringMaxLengthEncoding(buffer, size, NSUTF8StringEncoding); +// return buffer; +// }; interface CursorStatement { built: boolean; @@ -405,47 +403,56 @@ async function transactionRaw(db: FMDatabase, action: (cancel?: () => v if (isFirstTransaction) { execRaw(db, 'ROLLBACK TRANSACTION'); } - throwError(`transaction: ${e}`); + throwError(e); return null; } } -export class SQLiteDatabase { +export class SQLiteDatabase implements ISQLiteDatabase { db: FMDatabase; transformBlobs: boolean; + filePath: string; constructor( - public filePath: string, + filePathOrDb: string | FMDatabase, options?: { threading?: boolean; transformBlobs?: boolean; readOnly?: boolean; } ) { + if (filePathOrDb instanceof FMDatabase) { + this.db = filePathOrDb; + this.filePath = filePathOrDb.databaseURL.absoluteString; + this.isOpen = this.db.isOpen; + } else { + this.filePath = filePathOrDb; + } this.transformBlobs = !options || options.transformBlobs !== false; } isOpen = false; - async open() { + open() { if (!this.db) { this.db = FMDatabase.databaseWithPath(getRealPath(this.filePath)); } + this.isOpen = this.db.isOpen; if (!this.isOpen) { this.isOpen = this.db.open(); } return this.isOpen; } - async close() { + close() { if (!this.isOpen) return; this.db.close(); // sqlite3_close_v2(db); this.db = null; this.isOpen = false; } - async setVersion(version: number) { + setVersion(version: number) { this.db.userVersion = version + 0; // const query = "PRAGMA user_version=" + (version + 0).toString(); // execRaw(this.db, query); } - async getVersion() { + getVersion() { // const query = "PRAGMA user_version"; // const result = this.getArray(query); // return result && (result[0] as number); @@ -472,12 +479,20 @@ export class SQLiteDatabase { _isInTransaction = false; async transaction(action: (cancel?: () => void) => Promise): Promise { let res; - if (!this._isInTransaction) { - this._isInTransaction = true; - res = transactionRaw(this.db, action, true); - this._isInTransaction = false; - } else { - res = transactionRaw(this.db, action, false); + let shouldFinishTransaction = false; + try { + if (!this._isInTransaction) { + this._isInTransaction = shouldFinishTransaction = true; + res = await transactionRaw(this.db, action, true); + } else { + res = await transactionRaw(this.db, action, false); + } + } catch (error) { + throw error; + } finally { + if (shouldFinishTransaction) { + this._isInTransaction = false; + } } return res; } @@ -497,6 +512,19 @@ export function openOrCreate( return obj; } +export function wrapDb( + db: FMDatabase, + options?: { + readOnly?: boolean; + transformBlobs?: boolean; + threading?: boolean; + } +): SQLiteDatabase { + const obj = new SQLiteDatabase(db, options); + obj.open(); + return obj; +} + export const deleteDatabase = (filePath: string) => { filePath = getRealPath(filePath); const fileManager = iosProperty(NSFileManager, NSFileManager.defaultManager); diff --git a/packages/requery-sqlite/sqlitedatabase.ts b/packages/requery-sqlite/sqlitedatabase.ts index 2462799..aff261a 100644 --- a/packages/requery-sqlite/sqlitedatabase.ts +++ b/packages/requery-sqlite/sqlitedatabase.ts @@ -1,6 +1,6 @@ import { SqliteParam, SqliteParams, SqliteRow, paramsToStringArray, throwError } from './sqlite.common'; -type Db = any; +type Db = io.requery.android.database.sqlite.SQLiteDatabase; type FromCursor = (cursor: android.database.Cursor, transformBlobs?: boolean) => T; @@ -75,6 +75,10 @@ const arrayFromCursor = (cursor: android.database.Cursor, transformBlobs?: boole data.push(transformBlobs ? byteArrayToBuffer(cursor.getBlob(i)) : cursor.getBlob(i)); break; + case android.database.Cursor.FIELD_TYPE_NULL: + data.push(null); + break; + default: throwError(`unknown.type: ${type}`); } @@ -142,13 +146,15 @@ const transactionRaw = async (db: Db, action: (cancel?: () => void) => } }; -const messagePromises: { [key: string]: { resolve; reject; timeoutTimer: NodeJS.Timer }[] } = {}; +const messagePromises: { [key: string]: { resolve: Function; reject: Function; timeoutTimer: ReturnType }[] } = {}; + export class SQLiteDatabaseBase { + filePath: string; db: io.requery.android.database.sqlite.SQLiteDatabase; flags; transformBlobs: boolean; constructor( - public filePath: string, + filePathOrDb: string | io.requery.android.database.sqlite.SQLiteDatabase, options?: { threading?: boolean; readOnly?: boolean; @@ -156,6 +162,12 @@ export class SQLiteDatabaseBase { transformBlobs?: boolean; } ) { + if (filePathOrDb instanceof io.requery.android.database.sqlite.SQLiteDatabase) { + this.db = filePathOrDb; + this.filePath = filePathOrDb.getPath(); + } else { + this.filePath = filePathOrDb; + } this.threading = options && options.threading === true; this.flags = options?.flags; this.transformBlobs = !options || options.transformBlobs !== false; @@ -187,15 +199,7 @@ export class SQLiteDatabaseBase { } } lastId: number; - sendMessageToWorker( - nativeData, - messageData, - timeout = 0 - ): Promise<{ - id: number; - nativeDatas?: { [k: string]: any }; - [k: string]: any; - }> { + sendMessageToWorker(nativeData, messageData, timeout = 0): Promise { return new Promise((resolve, reject) => { let id = Date.now().valueOf(); if (id <= this.lastId) { @@ -238,7 +242,7 @@ export class SQLiteDatabaseBase { return this.db && this.db.isOpen(); } - async close() { + close() { if (!this.isOpen) return; if (this.worker) { this.worker.postMessage({ @@ -253,7 +257,7 @@ export class SQLiteDatabaseBase { async setVersion(version: number) { this.db.setVersion(version); } - async getVersion() { + getVersion() { return this.db.getVersion(); } async execute(query: string, params?: SqliteParams) { diff --git a/packages/requery-sqlite/tsconfig.json b/packages/requery-sqlite/tsconfig.json index 68ecc47..d7affca 100644 --- a/packages/requery-sqlite/tsconfig.json +++ b/packages/requery-sqlite/tsconfig.json @@ -21,7 +21,6 @@ "noEmitOnError": false, "noImplicitAny": false, "noImplicitReturns": true, - "noImplicitUseStrict": true, "noFallthroughCasesInSwitch": true }, "exclude": ["**/*.spec.ts", "**/*.test.ts", "angular", "platforms", "scripts"], diff --git a/tools/assets/App_Resources/Android/app.gradle b/tools/assets/App_Resources/Android/app.gradle index 87fbdbd..784fae0 100644 --- a/tools/assets/App_Resources/Android/app.gradle +++ b/tools/assets/App_Resources/Android/app.gradle @@ -1,8 +1,8 @@ android { - compileSdkVersion 33 + compileSdkVersion 34 defaultConfig { - minSdkVersion 21 - targetSdkVersion 33 + minSdkVersion 23 + targetSdkVersion 34 generatedDensities = [] } aaptOptions { diff --git a/tsconfig.base.json b/tsconfig.base.json index b63fba0..f276429 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,7 +6,7 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, - "noEmitHelpers": true, + "noEmitHelpers": false, "allowSyntheticDefaultImports": true, "target": "ES2020", "module": "ESNext", @@ -24,11 +24,8 @@ "@demo/shared": ["tools/demo/index.ts"], "@herefishyfish/*": ["packages/*"], "@herefishyfish/nativescript-lokijs": ["packages/nativescript-lokijs/index.d.ts"], - "@herefishyfish/nativescript-md5": ["packages/nativescript-md5/index.d.ts"], - "@herefishyfish/nativescript-pouchdb-sqlite-adapter": ["packages/nativescript-pouchdb-sqlite-adapter/index.d.ts"], "@herefishyfish/nativescript-rxdb": ["packages/nativescript-rxdb/index.d.ts"], "@herefishyfish/nativescript-sqlite-rxstorage-adapter": ["packages/nativescript-sqlite-rxstorage-adapter/index.d.ts"], - "nativescript-rxstorage-sqlite-adapter": ["packages/nativescript-rxstorage-sqlite-adapter/index.d.ts"], "@herefishyfish/requery-sqlite": ["packages/requery-sqlite/index.d.ts"] } },