Comments (3)
Additional Suggestion for Custom Type Projections Integration
Another approach might be to structure these functions as methods of the custom type itself, similar to how we currently implement the apply
, transform
, create
, and compose
methods. In fact, I believe this could be a more streamlined solution compared to passing these functions via the ShareDB constructor. It would also offer the added advantage of enabling projections for multiple types, with all associated logic encapsulated within the type implementation itself.
from sharedb.
Hi ๐๐ผ thanks for raising the issue. I can't see a reason to not add this in principle. Unfortunately, I think this is a huge task; as I'm sure you've seen, projection logic is scattered throughout the codebase and will need some work to tidy up into a more generically-usable shape.
I agree that the correct place for the logic is on the type itself; ideally sharedb
core should be as type-agnostic as possible (somewhere where projections don't excel at all...).
If you want to start work on a PR, we can try to help you along the way.
from sharedb.
Hi,
Thank you for the prompt response and for considering the feature request. I appreciate your insights on the current state of the codebase.
As a temporary workaround, given that I'm using Webpack, I've overridden the projections.js
file with my own implementation. It seems to be working well for now. Here's a snippet of my custom projections code for reference:
import {AOAction, AOActionTransformPaths} from './modules/backend/websocket/conexty-type';
exports.projectSnapshot = projectSnapshot;
exports.projectSnapshots = projectSnapshots;
exports.projectOp = projectOp;
exports.isSnapshotAllowed = isSnapshotAllowed;
exports.isOpAllowed = isOpAllowed;
// Project a snapshot in place to only include specified fields
function projectSnapshot(fields: {[key: string]: true}, snapshot: any) {
// Only json0 supported right now
// if (snapshot.type && snapshot.type !== json0.uri) {
// throw new Error(ERROR_CODE.ERR_TYPE_CANNOT_BE_PROJECTED, 'Cannot project snapshots of type ' + snapshot.type);
// }
snapshot.data = projectData(fields, snapshot.data);
}
function projectSnapshots(fields: {[key: string]: true}, snapshots: any) {
for (let i = 0; i < snapshots.length; i++) {
const snapshot = snapshots[i];
projectSnapshot(fields, snapshot);
}
}
function projectOp(fields: {[key: string]: true}, op: {create?: any, op?: AOAction[]}) {
if (op.create) {
projectSnapshot(fields, op.create);
}
if (op.op) {
op.op = projectEdit(fields, op.op);
}
}
function projectEdit(fields: {[key: string]: true}, op: AOAction[]) {
// So, we know the op is a JSON op
const result = [];
for (let i = 0; i < op.length; i++) {
const c = op[i];
if (c.op !== 'transformPaths') {
const path = c.path;
if (path.length > 0) {
// The path has a first element. Just check it against the fields.
if (fields[path[0]]) {
result.push(c);
}
}
} else {
// Transform paths
const paths = c.paths;
const newPaths = [];
for (let j = 0; j < paths.length; j++) {
const p = paths[j];
if (p.length > 0) {
if (fields[p[0]]) {
newPaths.push(p);
}
}
}
if (newPaths.length > 0) {
result.push({...c, paths: newPaths} as AOActionTransformPaths);
}
}
}
return result;
}
function isOpAllowed(knownType: any, fields: {[key: string]: true}, op: {create?: any, op?: AOAction[]}) {
if (op.create) {
return isSnapshotAllowed(fields, op.create);
}
if (op.op) {
// if (knownType && knownType !== json0.uri) return false;
return isEditAllowed(fields, op.op);
}
// Noop and del are both ok.
return true;
}
// Basically, would the projected version of this data be the same as the original?
function isSnapshotAllowed(fields: {[key: string]: true}, snapshot: any) {
// if (snapshot.type && snapshot.type !== json0.uri) {
// return false;
// }
if (snapshot.data == null) {
return true;
}
// Data must be an object if not null
if (typeof snapshot.data !== 'object' || Array.isArray(snapshot.data)) {
return false;
}
for (const k in snapshot.data) {
if (!fields[k]) return false;
}
return true;
}
function isEditAllowed(fields: {[key: string]: true}, op: AOAction[]) {
for (let i = 0; i < op.length; i++) {
const c = op[i];
if (c.op !== 'transformPaths') {
const path = c.path;
if (path.length === 0) {
return false;
} else if (!fields[path[0]]) {
return false;
}
} else {
const paths = c.paths;
for (let j = 0; j < paths.length; j++) {
const p = paths[j];
if (p.length === 0) {
return false;
} else if (!fields[p[0]]) {
return false;
}
}
}
}
return true;
}
function projectData(fields: {[key: string]: true}, data: any) {
// Return back null or undefined
if (data == null) {
return data;
}
// If data is not an object, the projected version just looks like null.
if (typeof data !== 'object' || Array.isArray(data)) {
return null;
}
// Shallow copy of each field
const result: any = {};
for (const key in fields) {
if (data.hasOwnProperty(key)) {
result[key] = data[key];
}
}
return result;
}
I plan to delve deeper into the ShareDB code to explore the possibility of implementing the proposed solution, aiming to move the logic to the type itself.
Again, thanks for your guidance. I'll keep you updated as I make progress and might reach out for assistance along the way.
Best regards.
from sharedb.
Related Issues (20)
- Question client doc handleOp not debounce ?
- `TypeError Cannot read properties of null (reading 'callback')` when receiving subscribe response with no inflight subscribe HOT 4
- Feature suggestion: type accessors HOT 3
- Q: How multiple `Doc`s guarantee transactions๏ผ HOT 2
- Collaborative text field using react with debounce HOT 3
- How can I synchronize my article titles? HOT 6
- Avoid committing no-ops
- API Support for Presence Notifications HOT 6
- How do I implement custom messages, just like websockets HOT 2
- Consider Partysocket for Examples
- Access Control / Permissions HOT 2
- Example Proposal: Comments
- Messages artificially delayed when running `Backend` in the browser HOT 1
- how to reload/refresh ShareDB document? HOT 6
- Invalid op submitted. Op version newer than current snapshot HOT 4
- failed process file : failed send RangeError: Invalid string length HOT 4
- The doc links are broken
- [Bug Report] Server-Side Data Inconsistencies When Rapidly Creating Nodes in ShareDB HOT 12
- How to implement Presence with 'rich-text' as 'json1' subtype? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sharedb.