Skip to content

Commit 9454cfd

Browse files
Pollepsjoepio
authored andcommitted
#798 Streamline Resource Creation API
1 parent 6337c2f commit 9454cfd

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

browser/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ This changelog covers all three packages, as they are (for now) updated as a who
1212
- [#758](https://github.com/atomicdata-dev/atomic-server/issues/758) Fix Relation column forms to close when clicking on the searchbox
1313
- Fix server not rebuilding client when files changed.
1414

15+
### @tomic/lib
16+
17+
- [#798](https://github.com/atomicdata-dev/atomic-server/issues/798) Add `store.newResource()` to make creating new resources more easy.
18+
1519
## v0.36.2
1620

1721
### Atomic Browser

browser/lib/src/store.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from 'chai';
22
import { jest } from '@jest/globals';
3-
import { Resource, urls, Store } from './index.js';
3+
import { Resource, urls, Store, core, Core } from './index.js';
44

55
describe('Store', () => {
66
it('renders the populate value', async () => {
@@ -56,4 +56,28 @@ describe('Store', () => {
5656

5757
expect(customFetch.mock.calls).to.have.length(1);
5858
});
59+
60+
it('creates new resources using store.newResource()', async () => {
61+
const store = new Store({ serverUrl: 'https://myserver.dev' });
62+
63+
const resource1 = await store.newResource<Core.Property>({
64+
subject: 'https://myserver.dev/testthing',
65+
parent: 'https://myserver.dev/properties',
66+
isA: core.classes.property,
67+
propVals: {
68+
[core.properties.datatype]: urls.datatypes.slug,
69+
[core.properties.shortname]: 'testthing',
70+
},
71+
});
72+
73+
expect(resource1.props.parent).to.equal('https://myserver.dev/properties');
74+
expect(resource1.props.datatype).to.equal(urls.datatypes.slug);
75+
expect(resource1.props.shortname).to.equal('testthing');
76+
expect(resource1.hasClasses(core.classes.property)).to.equal(true);
77+
78+
const resource2 = await store.newResource();
79+
80+
expect(resource2.props.parent).to.equal(store.getServerUrl());
81+
expect(resource2.get(core.properties.isA)).to.equal(undefined);
82+
});
5983
});

browser/lib/src/store.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
core,
2222
commits,
2323
collections,
24+
JSONValue,
2425
} from './index.js';
2526
import { authenticate, fetchWebSocket, startWebsocket } from './websockets.js';
2627

@@ -38,6 +39,17 @@ type AddResourcesOpts = {
3839
skipCommitCompare?: boolean;
3940
};
4041

42+
type CreateResourceOptions = {
43+
/** Optional subject of the new resource, if not given the store will generate a random subject */
44+
subject?: string;
45+
/** Parent the subject belongs to, defaults to the serverUrl */
46+
parent?: string;
47+
/** Subject(s) of the resources class */
48+
isA?: string | string[];
49+
/** Any additional properties the resource should have */
50+
propVals?: Record<string, JSONValue>;
51+
};
52+
4153
export interface StoreOpts {
4254
/** The default store URL, where to send commits and where to create new instances */
4355
serverUrl?: string;
@@ -184,6 +196,39 @@ export class Store {
184196
this.notify(resource.__internalObject);
185197
}
186198

199+
/**
200+
* A helper function for creating new resources.
201+
* Options take:
202+
* subject (optional) - defaults to random subject,
203+
* parent (optional) - defaults to serverUrl,
204+
* isA (optional),
205+
* properties (optional) - any additional properties to be set on the resource.
206+
*/
207+
public async newResource<C extends OptionalClass = UnknownClass>(
208+
options: CreateResourceOptions = {},
209+
): Promise<Resource<C>> {
210+
const { subject, parent, isA, propVals } = options;
211+
212+
const normalizedIsA = Array.isArray(isA) ? isA : [isA];
213+
const newSubject = subject ?? this.createSubject(normalizedIsA[0], parent);
214+
215+
const resource = this.getResourceLoading(newSubject, { newResource: true });
216+
217+
if (normalizedIsA[0]) {
218+
await resource.addClasses(this, ...(normalizedIsA as string[]));
219+
}
220+
221+
await resource.set(core.properties.parent, parent ?? this.serverUrl, this);
222+
223+
if (propVals) {
224+
for (const [key, value] of Object.entries(propVals)) {
225+
await resource.set(key, value, this);
226+
}
227+
}
228+
229+
return resource;
230+
}
231+
187232
/** Checks if a subject is free to use */
188233
public async checkSubjectTaken(subject: string): Promise<boolean> {
189234
const r = this.resources.get(subject);

0 commit comments

Comments
 (0)