Skip to content

Commit

Permalink
Refactored typeHelpers out of accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
kraenhansen committed Mar 21, 2024
1 parent 6788980 commit d736a2e
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 67 deletions.
27 changes: 24 additions & 3 deletions packages/realm/src/Collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@
//
////////////////////////////////////////////////////////////////////////////

import type { Dictionary, DictionaryAccessor, List, OrderedCollectionAccessor, RealmSet, Results } from "./internal";
import type {
Dictionary,
DictionaryAccessor,
List,
OrderedCollectionAccessor,
RealmSet,
Results,
TypeHelpers,
} from "./internal";
import { CallbackAdder, IllegalConstructorError, Listeners, TypeAssertionError, assert, binding } from "./internal";

/**
Expand All @@ -25,6 +33,12 @@ import { CallbackAdder, IllegalConstructorError, Listeners, TypeAssertionError,
*/
export const COLLECTION_ACCESSOR = Symbol("Collection#accessor");

/**
* Collection type helpers identifier.
* @internal
*/
export const COLLECTION_TYPE_HELPERS = Symbol("Collection#typeHelpers");

/**
* Accessor for getting and setting items in the binding collection, as
* well as converting the values to and from their binding representations.
Expand Down Expand Up @@ -52,18 +66,24 @@ export abstract class Collection<
> implements Iterable<T>
{
/**
* Accessor for getting and setting items in the binding collection, as
* well as converting the values to and from their binding representations.
* Accessor for getting and setting items in the binding collection.
* @internal
*/
protected readonly [COLLECTION_ACCESSOR]: Accessor;

/**
* Accessor converting converting the values to and from their binding representations.
* @internal
*/
protected readonly [COLLECTION_TYPE_HELPERS]: TypeHelpers<ValueType>;

/** @internal */
private listeners: Listeners<ChangeCallbackType, binding.NotificationToken, [string[] | undefined]>;

/** @internal */
constructor(
accessor: Accessor,
typeHelpers: TypeHelpers<ValueType>,
addListener: CallbackAdder<ChangeCallbackType, binding.NotificationToken, [string[] | undefined]>,
) {
if (arguments.length === 0) {
Expand All @@ -83,6 +103,7 @@ export abstract class Collection<
});

this[COLLECTION_ACCESSOR] = accessor;
this[COLLECTION_TYPE_HELPERS] = typeHelpers;
}

/**
Expand Down
37 changes: 20 additions & 17 deletions packages/realm/src/Dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
Realm,
RealmObject,
Results,
COLLECTION_TYPE_HELPERS as TYPE_HELPERS,
TypeHelpers,
assert,
binding,
Expand Down Expand Up @@ -133,11 +134,16 @@ export class Dictionary<T = unknown> extends Collection<
* Create a `Results` wrapping a set of query `Results` from the binding.
* @internal
*/
constructor(realm: Realm, internal: binding.Dictionary, accessor: DictionaryAccessor<T>) {
constructor(
realm: Realm,
internal: binding.Dictionary,
accessor: DictionaryAccessor<T>,
typeHelpers: TypeHelpers<T>,
) {
if (arguments.length === 0 || !(internal instanceof binding.Dictionary)) {
throw new IllegalConstructorError("Dictionary");
}
super(accessor, (listener, keyPaths) => {
super(accessor, typeHelpers, (listener, keyPaths) => {
return this[INTERNAL].addKeyBasedNotificationCallback(
({ deletions, insertions, modifications }) => {
try {
Expand Down Expand Up @@ -216,9 +222,9 @@ export class Dictionary<T = unknown> extends Collection<
const realm = this[REALM];
const snapshot = this[INTERNAL].values.snapshot();
const itemType = toItemType(snapshot.type);
const { fromBinding, toBinding } = this[ACCESSOR].helpers;
const accessor = createResultsAccessor({ realm, typeHelpers: { fromBinding, toBinding }, itemType });
const results = new Results<T>(realm, snapshot, accessor);
const typeHelpers = this[TYPE_HELPERS];
const accessor = createResultsAccessor({ realm, typeHelpers, itemType });
const results = new Results<T>(realm, snapshot, accessor, typeHelpers);
const size = results.length;

for (let i = 0; i < size; i++) {
Expand All @@ -239,9 +245,9 @@ export class Dictionary<T = unknown> extends Collection<

const realm = this[REALM];
const itemType = toItemType(snapshot.type);
const { fromBinding, toBinding } = this[ACCESSOR].helpers;
const accessor = createResultsAccessor({ realm, typeHelpers: { fromBinding, toBinding }, itemType });
const results = new Results<T>(realm, snapshot, accessor);
const typeHelpers = this[TYPE_HELPERS];
const accessor = createResultsAccessor({ realm, typeHelpers, itemType });
const results = new Results<T>(realm, snapshot, accessor, typeHelpers);

for (let i = 0; i < size; i++) {
const key = keys.getAny(i);
Expand Down Expand Up @@ -336,7 +342,6 @@ export class Dictionary<T = unknown> extends Collection<
export type DictionaryAccessor<T = unknown> = {
get: (dictionary: binding.Dictionary, key: string) => T;
set: (dictionary: binding.Dictionary, key: string, value: T) => void;
helpers: TypeHelpers<T>;
};

type DictionaryAccessorFactoryOptions<T> = {
Expand All @@ -357,21 +362,21 @@ function createDictionaryAccessorForMixed<T>({
realm,
typeHelpers,
}: Pick<DictionaryAccessorFactoryOptions<T>, "realm" | "typeHelpers">): DictionaryAccessor<T> {
const { toBinding } = typeHelpers;
const { toBinding, fromBinding } = typeHelpers;
return {
get(dictionary, key) {
const value = dictionary.tryGetAny(key);
switch (value) {
case binding.ListSentinel: {
const accessor = createListAccessor<T>({ realm, typeHelpers, itemType: binding.PropertyType.Mixed });
return new List<T>(realm, dictionary.getList(key), accessor) as T;
const accessor = createListAccessor<T>({ realm, itemType: binding.PropertyType.Mixed, typeHelpers });
return new List<T>(realm, dictionary.getList(key), accessor, typeHelpers) as T;
}
case binding.DictionarySentinel: {
const accessor = createDictionaryAccessor<T>({ realm, typeHelpers, itemType: binding.PropertyType.Mixed });
return new Dictionary<T>(realm, dictionary.getDictionary(key), accessor) as T;
const accessor = createDictionaryAccessor<T>({ realm, itemType: binding.PropertyType.Mixed, typeHelpers });
return new Dictionary<T>(realm, dictionary.getDictionary(key), accessor, typeHelpers) as T;
}
default:
return typeHelpers.fromBinding(value) as T;
return fromBinding(value) as T;
}
},
set(dictionary, key, value) {
Expand All @@ -387,7 +392,6 @@ function createDictionaryAccessorForMixed<T>({
dictionary.insertAny(key, toBinding(value));
}
},
helpers: typeHelpers,
};
}

Expand All @@ -410,7 +414,6 @@ function createDictionaryAccessorForKnownType<T>({
dictionary.insertAny(key, toBinding(value));
}
},
helpers: typeHelpers,
};
}

Expand Down
11 changes: 4 additions & 7 deletions packages/realm/src/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ export class List<T = unknown>
private declare isEmbedded: boolean;

/** @internal */
constructor(realm: Realm, internal: binding.List, accessor: ListAccessor<T>) {
constructor(realm: Realm, internal: binding.List, accessor: ListAccessor<T>, typeHelpers: TypeHelpers<T>) {
if (arguments.length === 0 || !(internal instanceof binding.List)) {
throw new IllegalConstructorError("List");
}
const results = internal.asResults();
super(realm, results, accessor);
super(realm, results, accessor, typeHelpers);

// Getting the `objectSchema` off the internal will throw if base type isn't object
const isEmbedded =
Expand Down Expand Up @@ -327,7 +327,6 @@ export type ListAccessor<T = unknown> = {
get: (list: binding.List, index: number) => T;
set: (list: binding.List, index: number, value: T) => void;
insert: (list: binding.List, index: number, value: T) => void;
helpers: TypeHelpers<T>;
};

type ListAccessorFactoryOptions<T> = {
Expand Down Expand Up @@ -355,11 +354,11 @@ function createListAccessorForMixed<T>({
switch (value) {
case binding.ListSentinel: {
const accessor = createListAccessor<T>({ realm, typeHelpers, itemType: binding.PropertyType.Mixed });
return new List<T>(realm, list.getList(index), accessor) as T;
return new List<T>(realm, list.getList(index), accessor, typeHelpers) as T;
}
case binding.DictionarySentinel: {
const accessor = createDictionaryAccessor<T>({ realm, typeHelpers, itemType: binding.PropertyType.Mixed });
return new Dictionary<T>(realm, list.getDictionary(index), accessor) as T;
return new Dictionary<T>(realm, list.getDictionary(index), accessor, typeHelpers) as T;
}
default:
return typeHelpers.fromBinding(value);
Expand Down Expand Up @@ -391,7 +390,6 @@ function createListAccessorForMixed<T>({
list.insertAny(index, toBinding(value));
}
},
helpers: typeHelpers,
};
}

Expand Down Expand Up @@ -420,7 +418,6 @@ function createListAccessorForKnownType<T>({
list.insertAny(index, toBinding(value));
}
},
helpers: typeHelpers,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/realm/src/Object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ export class RealmObject<T = DefaultObject, RequiredProperties extends keyof Omi
const tableView = this[INTERNAL].getBacklinkView(tableRef, targetProperty.columnKey);
const results = binding.Results.fromTableView(realm.internal, tableView);

return new Results<T>(realm, results, accessor);
return new Results<T>(realm, results, accessor, typeHelpers);
}

/**
Expand Down
26 changes: 13 additions & 13 deletions packages/realm/src/OrderedCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
////////////////////////////////////////////////////////////////////////////

import {
COLLECTION_ACCESSOR as ACCESSOR,
ClassHelpers,
Collection,
DefaultObject,
Expand All @@ -30,6 +29,7 @@ import {
Results,
ResultsAccessor,
SetAccessor,
COLLECTION_TYPE_HELPERS as TYPE_HELPERS,
TypeAssertionError,
TypeHelpers,
assert,
Expand Down Expand Up @@ -158,11 +158,11 @@ export abstract class OrderedCollection<
/** @internal */ protected declare results: binding.Results;

/** @internal */
constructor(realm: Realm, results: binding.Results, accessor: Accessor) {
constructor(realm: Realm, results: binding.Results, accessor: Accessor, typeHelpers: TypeHelpers<T>) {
if (arguments.length === 0) {
throw new IllegalConstructorError("OrderedCollection");
}
super(accessor, (callback, keyPaths) => {
super(accessor, typeHelpers, (callback, keyPaths) => {
return results.addNotificationCallback(
(changes) => {
try {
Expand Down Expand Up @@ -393,7 +393,7 @@ export abstract class OrderedCollection<
const NOT_FOUND = -1;
return NOT_FOUND;
} else {
return this.results.indexOf(this[ACCESSOR].helpers.toBinding(searchElement));
return this.results.indexOf(this[TYPE_HELPERS].toBinding(searchElement));
}
}
/**
Expand Down Expand Up @@ -812,9 +812,9 @@ export abstract class OrderedCollection<
const results = binding.Helpers.resultsAppendQuery(parent, newQuery);

const itemType = toItemType(results.type);
const { fromBinding, toBinding } = this[ACCESSOR].helpers;
const accessor = createResultsAccessor({ realm, typeHelpers: { fromBinding, toBinding }, itemType });
return new Results(realm, results, accessor);
const typeHelpers = this[TYPE_HELPERS];
const accessor = createResultsAccessor({ realm, typeHelpers, itemType });
return new Results(realm, results, accessor, typeHelpers);
}

/** @internal */
Expand Down Expand Up @@ -902,9 +902,9 @@ export abstract class OrderedCollection<
// TODO: Call `parent.sort`, avoiding property name to column key conversion to speed up performance here.
const results = parent.sortByNames(descriptors);
const itemType = toItemType(results.type);
const { fromBinding, toBinding } = this[ACCESSOR].helpers;
const accessor = createResultsAccessor({ realm, typeHelpers: { fromBinding, toBinding }, itemType });
return new Results(realm, results, accessor);
const typeHelpers = this[TYPE_HELPERS];
const accessor = createResultsAccessor({ realm, typeHelpers, itemType });
return new Results(realm, results, accessor, typeHelpers);
} else if (typeof arg0 === "string") {
return this.sorted([[arg0, arg1 === true]]);
} else if (typeof arg0 === "boolean") {
Expand Down Expand Up @@ -932,9 +932,9 @@ export abstract class OrderedCollection<
const { realm, internal } = this;
const snapshot = internal.snapshot();
const itemType = toItemType(snapshot.type);
const { fromBinding, toBinding } = this[ACCESSOR].helpers;
const accessor = createResultsAccessor({ realm, typeHelpers: { fromBinding, toBinding }, itemType });
return new Results(realm, snapshot, accessor);
const typeHelpers = this[TYPE_HELPERS];
const accessor = createResultsAccessor({ realm, typeHelpers, itemType });
return new Results(realm, snapshot, accessor, typeHelpers);
}

private getPropertyColumnKey(name: string | undefined): binding.ColKey {
Expand Down
12 changes: 6 additions & 6 deletions packages/realm/src/PropertyHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const ACCESSOR_FACTORIES: Partial<Record<binding.PropertyType, AccessorFactory>>
get(obj: binding.Obj) {
const tableView = obj.getBacklinkView(tableRef, targetProperty.columnKey);
const results = binding.Results.fromTableView(realmInternal, tableView);
return new Results(realm, results, resultsAccessor);
return new Results(realm, results, resultsAccessor, itemHelpers);
},
set() {
throw new Error("Not supported");
Expand All @@ -197,7 +197,7 @@ const ACCESSOR_FACTORIES: Partial<Record<binding.PropertyType, AccessorFactory>>
get(obj: binding.Obj) {
const internal = binding.List.make(realm.internal, obj, columnKey);
assert.instanceOf(internal, binding.List);
return new List(realm, internal, listAccessor);
return new List(realm, internal, listAccessor, itemHelpers);
},
set(obj, values) {
assert.inTransaction(realm);
Expand Down Expand Up @@ -240,7 +240,7 @@ const ACCESSOR_FACTORIES: Partial<Record<binding.PropertyType, AccessorFactory>>
return {
get(obj) {
const internal = binding.Dictionary.make(realm.internal, obj, columnKey);
return new Dictionary(realm, internal, dictionaryAccessor);
return new Dictionary(realm, internal, dictionaryAccessor, itemHelpers);
},
set(obj, value) {
assert.inTransaction(realm);
Expand Down Expand Up @@ -278,7 +278,7 @@ const ACCESSOR_FACTORIES: Partial<Record<binding.PropertyType, AccessorFactory>>
return {
get(obj) {
const internal = binding.Set.make(realm.internal, obj, columnKey);
return new RealmSet(realm, internal, setAccessor);
return new RealmSet(realm, internal, setAccessor, itemHelpers);
},
set(obj, value) {
assert.inTransaction(realm);
Expand Down Expand Up @@ -306,11 +306,11 @@ const ACCESSOR_FACTORIES: Partial<Record<binding.PropertyType, AccessorFactory>>
switch (value) {
case binding.ListSentinel: {
const internal = binding.List.make(realm.internal, obj, columnKey);
return new List(realm, internal, listAccessor);
return new List(realm, internal, listAccessor, typeHelpers);
}
case binding.DictionarySentinel: {
const internal = binding.Dictionary.make(realm.internal, obj, columnKey);
return new Dictionary(realm, internal, dictionaryAccessor);
return new Dictionary(realm, internal, dictionaryAccessor, typeHelpers);
}
default:
return fromBinding(value);
Expand Down
4 changes: 2 additions & 2 deletions packages/realm/src/Realm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ import {
LogArgs,
LogCategory,
LogLevel,
LoggerCallbackArgs,
LoggerCallback,
LoggerCallback1,
LoggerCallback2,
LoggerCallbackArgs,
MapToDecorator,
Metadata,
MetadataMode,
Expand Down Expand Up @@ -1132,7 +1132,7 @@ export class Realm {
},
};
const accessor = createResultsAccessor<T>({ realm: this, typeHelpers, itemType: binding.PropertyType.Object });
return new Results<T>(this, results, accessor);
return new Results<T>(this, results, accessor, typeHelpers);
}

/**
Expand Down
Loading

0 comments on commit d736a2e

Please sign in to comment.