예제 #1
0
import datetime
import warnings
from typing import List, Union

from sqlalchemy import event
from sqlalchemy.sql import Join
from sqlalchemy.orm.session import object_session

from dbsync import core
from dbsync.models import Operation, Version, SQLClass, call_after_tracking_fn, call_before_tracking_fn, SkipOperation
from dbsync.logs import get_logger

from dbsync.createlogger import create_logger
from logging import DEBUG

logger = create_logger("dbsync.server.tracking")
logger.level = DEBUG

if core.mode == 'client':
    warnings.warn("don't import both server and client")
core.mode = 'server'


def make_listener(command: str):
    """Builds a listener for the given command (i, u, d)."""
    @core.session_committing
    def listener(mapper, connection, target, session=None) -> None:
        logger.info(f"tracking {target}")
        if getattr(core.SessionClass.object_session(target),
                   core.INTERNAL_SESSION_ATTR, False):
            logger.debug(f"internal session object not tracked: {target}")
예제 #2
0
from dbsync.client.wsclient import SyncClient
from dbsync.core import with_transaction_async
from dbsync.createlogger import create_logger
from dbsync.messages.push import PushMessage
from dbsync.models import Node, Operation, Version
from dbsync.server.wsserver import SyncServer
from dbsync.socketclient import GenericWSClient
from dbsync.socketserver import Connection

from tests.models_websockets import SERVER_URL, addstuff, changestuff, A, B, datapath, deletestuff
from .models_websockets import PORT
from .server_setup import sync_server, server_session, server_db
from .client_setup import sync_client, client_session, sync_client_registered, client_db, create_sync_client_registered, \
    create_client_session

logger = create_logger("dbsync.tests")


@SyncServer.handler("/counter")
async def counter(conn: Connection):
    n = int(await conn.socket.recv())

    for i in range(n):
        await conn.socket.send(str(i))


@SyncServer.handler("/fuckup")
async def fuckup(conn: Connection):
    """
    provoke an exception
    """
예제 #3
0
from dbsync.messages.push import PushMessage
from dbsync.models import OperationError, Version, Operation, attr, SQLClass, call_after_tracking_fn
from dbsync.server import before_push, after_push
from dbsync.server.conflicts import find_unique_conflicts
from dbsync.server.handlers import PullRejected
from dbsync.socketserver import GenericWSServer, Connection
import sqlalchemy as sa
from sqlalchemy.engine import Engine

from dbsync.createlogger import create_logger
from sqlalchemy.orm import sessionmaker, make_transient

from dbsync.utils import get_pk, properties_dict

import logging
logger = create_logger("dbsync-server")


class SyncServerConnection(Connection):
    ...


async def send_field_payload(connection: Connection, msg: Dict[str, Any]):
    from ..models import get_model_extensions_for_obj
    session = connection.server.Session()
    logger.debug(f"send_field_payload:{msg}")
    # breakpoint()
    module = importlib.import_module(msg['package_name'])
    klass = getattr(module, msg['class_name'])
    pkname = msg['id_field']
    obj = session.query(klass).filter(
예제 #4
0
from typing import List, Dict, Any, Optional

from dbsync.createlogger import create_logger
from dbsync.dialects import GUID
from sqlalchemy import types
from dbsync.utils import (properties_dict, object_from_dict, get_pk,
                          parent_objects, query_model)
from dbsync.lang import *

from dbsync.core import (MAX_SQL_VARIABLES, session_closing, synched_models,
                         pushed_models)
from dbsync.models import Node, Operation, SQLClass
from dbsync.messages.base import MessageQuery, BaseMessage
from dbsync.messages.codecs import encode, encode_dict, decode, decode_dict

logger = create_logger("messages.push")


class PushMessage(BaseMessage):
    """
    A push message.

    A push message contains the latest version information, the node
    information, and the list of unversioned operations and the
    required objects for those to be performed.

    The message can be instantiated from a raw data dictionary or can
    be made empty and filled later with the
    ``add_unversioned_operations`` method, in which case the node
    attribute and the latest version identifier should be assigned
    explicitly as well. The method ``set_node`` is required to be used
예제 #5
0
from dbsync.models import Operation
from dbsync import dialects
from dbsync.messages.pull import PullMessage, PullRequestMessage
from dbsync.client.compression import compress, compressed_operations
from dbsync.client.conflicts import (
    get_related_tables,
    get_fks,
    find_direct_conflicts,
    find_dependency_conflicts,
    find_reversed_dependency_conflicts,
    find_insert_conflicts,
    find_unique_conflicts)
from dbsync.client.net import post_request


logger = create_logger("client/pull")
# Utilities specific to the merge

def max_local(model, session):
    """
    Returns the maximum value for the primary key of the given model
    in the local database.
    """
    if model is None:
        raise ValueError("null model given to max_local query")
    return dialects.max_local(model, session)


def max_remote(model, container):
    """
    Returns the maximum value for the primary key of the given model
예제 #6
0
.. __: http://essay.utwente.nl/61767/1/Master_thesis_Jan-Henk_Gerritsen.pdf
"""

from sqlalchemy import or_
from sqlalchemy.orm import undefer
from sqlalchemy.schema import UniqueConstraint
from sqlalchemy.sql import Join

from dbsync.lang import *
from dbsync.utils import get_pk, class_mapper, query_model, column_properties, entity_name
from dbsync.core import synched_models, null_model
from dbsync.models import Operation
from dbsync.createlogger import create_logger

logger = create_logger("dbsync.client.conflicts")

def get_related_tables(sa_class):
    """
    Returns a list of related SA tables dependent on the given SA
    model by foreign key.
    """
    mapper = class_mapper(sa_class)
    models = iter(list(synched_models.models.keys()))
    return [
        table
        for table
        in (
            class_mapper(model).mapped_table
            for model
            in models
예제 #7
0
from dbsync.messages.pull import PullRequestMessage, PullMessage
from dbsync.messages.push import PushMessage
from dbsync.messages.register import RegisterMessage
from dbsync.models import Node, get_model_extensions_for_obj, Version, Operation
from dbsync.socketclient import GenericWSClient
from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker

from dbsync.wscommon import SerializationError

wscommon.register_exception(PushRejected)
wscommon.register_exception(PullSuggested)

from logging import DEBUG
import logging
logger = create_logger("wsclient")

logger.level = DEBUG


@dataclass
class SyncClient(GenericWSClient):
    engine: Optional[Engine] = None
    Session: Optional[sessionmaker] = None
    id: int = -1
    elapsed_rounds = 0

    def __post_init__(self):
        if not self.Session:
            self.engine = core.get_engine()
            self.Session = lambda: core.SessionClass(
예제 #8
0
from dbsync.createlogger import create_logger
from dbsync.models import Operation, SQLClass, add_field_extension, ExtensionField, extend_model, SkipOperation
from dbsync.server.wsserver import SyncServer
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker, Session
from sqlalchemy.ext.declarative import declarative_base

from dbsync.dialects import GUID
from dbsync.utils import generate_secret
import dbsync
from dbsync import client, models, core, server

server_db = "./test_server.db"
server_uri_postgres = 'postgresql:///synctest'

logger = create_logger("models_websockets")


def client_db(pid=None):
    if pid is None:
        pid = os.getpid()
    return f"./test_client_{pid}.db"


PORT = 7081
SERVER_URL = f"ws://localhost:{PORT}/"

Base = declarative_base()


def datapath(fname="", mode=None, pid=""):