misc.python.materialize.zippy.table_actions

  1# Copyright Materialize, Inc. and contributors. All rights reserved.
  2#
  3# Use of this software is governed by the Business Source License
  4# included in the LICENSE file at the root of this repository.
  5#
  6# As of the Change Date specified in that file, in accordance with
  7# the Business Source License, use of this software will be governed
  8# by the Apache License, Version 2.0.
  9
 10import random
 11from textwrap import dedent
 12
 13from materialize.mzcompose.composition import Composition
 14from materialize.zippy.balancerd_capabilities import BalancerdIsRunning
 15from materialize.zippy.framework import (
 16    Action,
 17    ActionFactory,
 18    Capabilities,
 19    Capability,
 20    State,
 21)
 22from materialize.zippy.mz_capabilities import MzIsRunning
 23from materialize.zippy.table_capabilities import TableExists
 24from materialize.zippy.view_capabilities import ViewExists
 25
 26MAX_ROWS_PER_ACTION = 10000
 27
 28
 29class CreateTableParameterized(ActionFactory):
 30    def __init__(
 31        self, max_tables: int = 10, max_rows_per_action: int = MAX_ROWS_PER_ACTION
 32    ) -> None:
 33        self.max_tables = max_tables
 34        self.max_rows_per_action = max_rows_per_action
 35
 36    @classmethod
 37    def requires(cls) -> set[type[Capability]]:
 38        return {BalancerdIsRunning, MzIsRunning}
 39
 40    def new(self, capabilities: Capabilities) -> list[Action]:
 41        new_table_name = capabilities.get_free_capability_name(
 42            TableExists, self.max_tables
 43        )
 44
 45        if new_table_name:
 46            return [
 47                CreateTable(
 48                    capabilities=capabilities,
 49                    table=TableExists(
 50                        name=new_table_name,
 51                        has_index=random.choice([True, False]),
 52                        max_rows_per_action=self.max_rows_per_action,
 53                    ),
 54                )
 55            ]
 56        else:
 57            return []
 58
 59
 60class CreateTable(Action):
 61    """Creates a table on the Mz instance. 50% of the tables have a default index."""
 62
 63    @classmethod
 64    def requires(cls) -> set[type[Capability]]:
 65        return {BalancerdIsRunning, MzIsRunning}
 66
 67    def __init__(self, table: TableExists, capabilities: Capabilities) -> None:
 68        assert (
 69            table is not None
 70        ), "CreateTable Action can not be referenced directly, it is produced by CreateTableParameterized factory"
 71        self.table = table
 72        super().__init__(capabilities)
 73
 74    def run(self, c: Composition, state: State) -> None:
 75        index = (
 76            f"> CREATE DEFAULT INDEX ON {self.table.name}"
 77            if self.table.has_index
 78            else ""
 79        )
 80        c.testdrive(
 81            dedent(f"""
 82                > CREATE TABLE {self.table.name} (f1 INTEGER);
 83                {index}
 84                > INSERT INTO {self.table.name} VALUES ({self.table.watermarks.max});
 85                """),
 86            mz_service=state.mz_service,
 87        )
 88
 89    def provides(self) -> list[Capability]:
 90        return [self.table]
 91
 92
 93class ValidateTable(Action):
 94    """Validates that a single table contains data that is consistent with the expected min/max watermark."""
 95
 96    @classmethod
 97    def requires(cls) -> set[type[Capability]]:
 98        return {BalancerdIsRunning, MzIsRunning, TableExists}
 99
100    def __init__(
101        self, capabilities: Capabilities, table: TableExists | None = None
102    ) -> None:
103        if table is not None:
104            self.table = table
105        else:
106            self.table = random.choice(capabilities.get(TableExists))
107
108        self.select_limit = random.choices([True, False], weights=[0.2, 0.8], k=1)[0]
109        super().__init__(capabilities)
110
111    def run(self, c: Composition, state: State) -> None:
112        # Validating via SELECT ... LIMIT is expensive as it requires creating a temporary table
113        # Therefore, only use it in 20% of validations.
114        if self.select_limit:
115            c.testdrive(
116                dedent(f"""
117                    > CREATE TEMPORARY TABLE {self.table.name}_select_limit (f1 INTEGER);
118                    > INSERT INTO {self.table.name}_select_limit SELECT * FROM {self.table.name} LIMIT 999999999;
119                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name}_select_limit;
120                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
121                    > DROP TABLE {self.table.name}_select_limit
122                    """),
123                mz_service=state.mz_service,
124            )
125        else:
126            c.testdrive(
127                dedent(f"""
128                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name};
129                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
130                    """),
131                mz_service=state.mz_service,
132            )
133
134
135class DropTable(Action):
136    """Drops a table that no view reads from."""
137
138    @classmethod
139    def requires(cls) -> set[type[Capability]]:
140        return {BalancerdIsRunning, MzIsRunning, TableExists}
141
142    def __init__(self, capabilities: Capabilities) -> None:
143        referenced: set[str] = set()
144        for view in capabilities.get(ViewExists):
145            referenced.update(input.name for input in view.inputs)
146
147        candidates = [
148            t for t in capabilities.get(TableExists) if t.name not in referenced
149        ]
150        self.table: TableExists | None = (
151            random.choice(candidates) if candidates else None
152        )
153        if self.table is not None:
154            capabilities.remove_capability_instance(self.table)
155        super().__init__(capabilities)
156
157    def __str__(self) -> str:
158        return f"{Action.__str__(self)} {self.table.name if self.table else '<none>'}"
159
160    def run(self, c: Composition, state: State) -> None:
161        if self.table is not None:
162            c.testdrive(
163                f"> DROP TABLE {self.table.name};",
164                mz_service=state.mz_service,
165            )
166
167
168class DML(Action):
169    """Performs an INSERT, DELETE or UPDATE against a table."""
170
171    @classmethod
172    def requires(cls) -> set[type[Capability]]:
173        return {BalancerdIsRunning, MzIsRunning, TableExists}
174
175    def __init__(self, capabilities: Capabilities) -> None:
176        self.table = random.choice(capabilities.get(TableExists))
177        self.delta = random.randint(1, self.table.max_rows_per_action)
178        super().__init__(capabilities)
179
180    def __str__(self) -> str:
181        return f"{Action.__str__(self)} {self.table.name}"
182
183
184class Insert(DML):
185    """Inserts rows into a table."""
186
187    def run(self, c: Composition, state: State) -> None:
188        prev_max = self.table.watermarks.max
189        self.table.watermarks.max = prev_max + self.delta
190        c.testdrive(
191            f"> INSERT INTO {self.table.name} SELECT * FROM generate_series({prev_max + 1}, {self.table.watermarks.max});",
192            mz_service=state.mz_service,
193        )
194
195
196class ShiftForward(DML):
197    """Update all rows from a table by incrementing their values by a constant."""
198
199    def run(self, c: Composition, state: State) -> None:
200        self.table.watermarks.shift(self.delta)
201        c.testdrive(
202            f"> UPDATE {self.table.name} SET f1 = f1 + {self.delta};",
203            mz_service=state.mz_service,
204        )
205
206
207class ShiftBackward(DML):
208    """Update all rows from a table by decrementing their values by a constant."""
209
210    def run(self, c: Composition, state: State) -> None:
211        self.table.watermarks.shift(-self.delta)
212        c.testdrive(
213            f"> UPDATE {self.table.name} SET f1 = f1 - {self.delta};",
214            mz_service=state.mz_service,
215        )
216
217
218class DeleteFromHead(DML):
219    """Delete the largest values from a table"""
220
221    def run(self, c: Composition, state: State) -> None:
222        self.table.watermarks.max = max(
223            self.table.watermarks.max - self.delta, self.table.watermarks.min
224        )
225        c.testdrive(
226            f"> DELETE FROM {self.table.name} WHERE f1 > {self.table.watermarks.max};",
227            mz_service=state.mz_service,
228        )
229
230
231class DeleteFromTail(DML):
232    """Delete the smallest values from a table"""
233
234    def run(self, c: Composition, state: State) -> None:
235        self.table.watermarks.min = min(
236            self.table.watermarks.min + self.delta, self.table.watermarks.max
237        )
238        c.testdrive(
239            f"> DELETE FROM {self.table.name} WHERE f1 < {self.table.watermarks.min};",
240            mz_service=state.mz_service,
241        )
MAX_ROWS_PER_ACTION = 10000
class CreateTableParameterized(materialize.zippy.framework.ActionFactory):
30class CreateTableParameterized(ActionFactory):
31    def __init__(
32        self, max_tables: int = 10, max_rows_per_action: int = MAX_ROWS_PER_ACTION
33    ) -> None:
34        self.max_tables = max_tables
35        self.max_rows_per_action = max_rows_per_action
36
37    @classmethod
38    def requires(cls) -> set[type[Capability]]:
39        return {BalancerdIsRunning, MzIsRunning}
40
41    def new(self, capabilities: Capabilities) -> list[Action]:
42        new_table_name = capabilities.get_free_capability_name(
43            TableExists, self.max_tables
44        )
45
46        if new_table_name:
47            return [
48                CreateTable(
49                    capabilities=capabilities,
50                    table=TableExists(
51                        name=new_table_name,
52                        has_index=random.choice([True, False]),
53                        max_rows_per_action=self.max_rows_per_action,
54                    ),
55                )
56            ]
57        else:
58            return []

Base class for Action Factories that return parameterized Actions to execute.

CreateTableParameterized(max_tables: int = 10, max_rows_per_action: int = 10000)
31    def __init__(
32        self, max_tables: int = 10, max_rows_per_action: int = MAX_ROWS_PER_ACTION
33    ) -> None:
34        self.max_tables = max_tables
35        self.max_rows_per_action = max_rows_per_action
max_tables
max_rows_per_action
@classmethod
def requires(cls) -> set[type[materialize.zippy.framework.Capability]]:
37    @classmethod
38    def requires(cls) -> set[type[Capability]]:
39        return {BalancerdIsRunning, MzIsRunning}

Compute the capability classes that this Action Factory requires.

def new( self, capabilities: materialize.zippy.framework.Capabilities) -> list[materialize.zippy.framework.Action]:
41    def new(self, capabilities: Capabilities) -> list[Action]:
42        new_table_name = capabilities.get_free_capability_name(
43            TableExists, self.max_tables
44        )
45
46        if new_table_name:
47            return [
48                CreateTable(
49                    capabilities=capabilities,
50                    table=TableExists(
51                        name=new_table_name,
52                        has_index=random.choice([True, False]),
53                        max_rows_per_action=self.max_rows_per_action,
54                    ),
55                )
56            ]
57        else:
58            return []
class CreateTable(materialize.zippy.framework.Action):
61class CreateTable(Action):
62    """Creates a table on the Mz instance. 50% of the tables have a default index."""
63
64    @classmethod
65    def requires(cls) -> set[type[Capability]]:
66        return {BalancerdIsRunning, MzIsRunning}
67
68    def __init__(self, table: TableExists, capabilities: Capabilities) -> None:
69        assert (
70            table is not None
71        ), "CreateTable Action can not be referenced directly, it is produced by CreateTableParameterized factory"
72        self.table = table
73        super().__init__(capabilities)
74
75    def run(self, c: Composition, state: State) -> None:
76        index = (
77            f"> CREATE DEFAULT INDEX ON {self.table.name}"
78            if self.table.has_index
79            else ""
80        )
81        c.testdrive(
82            dedent(f"""
83                > CREATE TABLE {self.table.name} (f1 INTEGER);
84                {index}
85                > INSERT INTO {self.table.name} VALUES ({self.table.watermarks.max});
86                """),
87            mz_service=state.mz_service,
88        )
89
90    def provides(self) -> list[Capability]:
91        return [self.table]

Creates a table on the Mz instance. 50% of the tables have a default index.

CreateTable( table: materialize.zippy.table_capabilities.TableExists, capabilities: materialize.zippy.framework.Capabilities)
68    def __init__(self, table: TableExists, capabilities: Capabilities) -> None:
69        assert (
70            table is not None
71        ), "CreateTable Action can not be referenced directly, it is produced by CreateTableParameterized factory"
72        self.table = table
73        super().__init__(capabilities)

Construct a new action, possibly conditioning on the available capabilities.

@classmethod
def requires(cls) -> set[type[materialize.zippy.framework.Capability]]:
64    @classmethod
65    def requires(cls) -> set[type[Capability]]:
66        return {BalancerdIsRunning, MzIsRunning}

Compute the capability classes that this action requires.

table
def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
75    def run(self, c: Composition, state: State) -> None:
76        index = (
77            f"> CREATE DEFAULT INDEX ON {self.table.name}"
78            if self.table.has_index
79            else ""
80        )
81        c.testdrive(
82            dedent(f"""
83                > CREATE TABLE {self.table.name} (f1 INTEGER);
84                {index}
85                > INSERT INTO {self.table.name} VALUES ({self.table.watermarks.max});
86                """),
87            mz_service=state.mz_service,
88        )

Run this action on the provided composition.

def provides(self) -> list[materialize.zippy.framework.Capability]:
90    def provides(self) -> list[Capability]:
91        return [self.table]

Compute the capabilities that this action will make available.

class ValidateTable(materialize.zippy.framework.Action):
 94class ValidateTable(Action):
 95    """Validates that a single table contains data that is consistent with the expected min/max watermark."""
 96
 97    @classmethod
 98    def requires(cls) -> set[type[Capability]]:
 99        return {BalancerdIsRunning, MzIsRunning, TableExists}
100
101    def __init__(
102        self, capabilities: Capabilities, table: TableExists | None = None
103    ) -> None:
104        if table is not None:
105            self.table = table
106        else:
107            self.table = random.choice(capabilities.get(TableExists))
108
109        self.select_limit = random.choices([True, False], weights=[0.2, 0.8], k=1)[0]
110        super().__init__(capabilities)
111
112    def run(self, c: Composition, state: State) -> None:
113        # Validating via SELECT ... LIMIT is expensive as it requires creating a temporary table
114        # Therefore, only use it in 20% of validations.
115        if self.select_limit:
116            c.testdrive(
117                dedent(f"""
118                    > CREATE TEMPORARY TABLE {self.table.name}_select_limit (f1 INTEGER);
119                    > INSERT INTO {self.table.name}_select_limit SELECT * FROM {self.table.name} LIMIT 999999999;
120                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name}_select_limit;
121                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
122                    > DROP TABLE {self.table.name}_select_limit
123                    """),
124                mz_service=state.mz_service,
125            )
126        else:
127            c.testdrive(
128                dedent(f"""
129                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name};
130                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
131                    """),
132                mz_service=state.mz_service,
133            )

Validates that a single table contains data that is consistent with the expected min/max watermark.

ValidateTable( capabilities: materialize.zippy.framework.Capabilities, table: materialize.zippy.table_capabilities.TableExists | None = None)
101    def __init__(
102        self, capabilities: Capabilities, table: TableExists | None = None
103    ) -> None:
104        if table is not None:
105            self.table = table
106        else:
107            self.table = random.choice(capabilities.get(TableExists))
108
109        self.select_limit = random.choices([True, False], weights=[0.2, 0.8], k=1)[0]
110        super().__init__(capabilities)

Construct a new action, possibly conditioning on the available capabilities.

@classmethod
def requires(cls) -> set[type[materialize.zippy.framework.Capability]]:
97    @classmethod
98    def requires(cls) -> set[type[Capability]]:
99        return {BalancerdIsRunning, MzIsRunning, TableExists}

Compute the capability classes that this action requires.

select_limit
def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
112    def run(self, c: Composition, state: State) -> None:
113        # Validating via SELECT ... LIMIT is expensive as it requires creating a temporary table
114        # Therefore, only use it in 20% of validations.
115        if self.select_limit:
116            c.testdrive(
117                dedent(f"""
118                    > CREATE TEMPORARY TABLE {self.table.name}_select_limit (f1 INTEGER);
119                    > INSERT INTO {self.table.name}_select_limit SELECT * FROM {self.table.name} LIMIT 999999999;
120                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name}_select_limit;
121                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
122                    > DROP TABLE {self.table.name}_select_limit
123                    """),
124                mz_service=state.mz_service,
125            )
126        else:
127            c.testdrive(
128                dedent(f"""
129                    > SELECT MIN(f1), MAX(f1), COUNT(f1), COUNT(DISTINCT f1) FROM {self.table.name};
130                    {self.table.watermarks.min} {self.table.watermarks.max} {(self.table.watermarks.max-self.table.watermarks.min)+1} {(self.table.watermarks.max-self.table.watermarks.min)+1}
131                    """),
132                mz_service=state.mz_service,
133            )

Run this action on the provided composition.

class DropTable(materialize.zippy.framework.Action):
136class DropTable(Action):
137    """Drops a table that no view reads from."""
138
139    @classmethod
140    def requires(cls) -> set[type[Capability]]:
141        return {BalancerdIsRunning, MzIsRunning, TableExists}
142
143    def __init__(self, capabilities: Capabilities) -> None:
144        referenced: set[str] = set()
145        for view in capabilities.get(ViewExists):
146            referenced.update(input.name for input in view.inputs)
147
148        candidates = [
149            t for t in capabilities.get(TableExists) if t.name not in referenced
150        ]
151        self.table: TableExists | None = (
152            random.choice(candidates) if candidates else None
153        )
154        if self.table is not None:
155            capabilities.remove_capability_instance(self.table)
156        super().__init__(capabilities)
157
158    def __str__(self) -> str:
159        return f"{Action.__str__(self)} {self.table.name if self.table else '<none>'}"
160
161    def run(self, c: Composition, state: State) -> None:
162        if self.table is not None:
163            c.testdrive(
164                f"> DROP TABLE {self.table.name};",
165                mz_service=state.mz_service,
166            )

Drops a table that no view reads from.

DropTable(capabilities: materialize.zippy.framework.Capabilities)
143    def __init__(self, capabilities: Capabilities) -> None:
144        referenced: set[str] = set()
145        for view in capabilities.get(ViewExists):
146            referenced.update(input.name for input in view.inputs)
147
148        candidates = [
149            t for t in capabilities.get(TableExists) if t.name not in referenced
150        ]
151        self.table: TableExists | None = (
152            random.choice(candidates) if candidates else None
153        )
154        if self.table is not None:
155            capabilities.remove_capability_instance(self.table)
156        super().__init__(capabilities)

Construct a new action, possibly conditioning on the available capabilities.

@classmethod
def requires(cls) -> set[type[materialize.zippy.framework.Capability]]:
139    @classmethod
140    def requires(cls) -> set[type[Capability]]:
141        return {BalancerdIsRunning, MzIsRunning, TableExists}

Compute the capability classes that this action requires.

table: materialize.zippy.table_capabilities.TableExists | None
def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
161    def run(self, c: Composition, state: State) -> None:
162        if self.table is not None:
163            c.testdrive(
164                f"> DROP TABLE {self.table.name};",
165                mz_service=state.mz_service,
166            )

Run this action on the provided composition.

class DML(materialize.zippy.framework.Action):
169class DML(Action):
170    """Performs an INSERT, DELETE or UPDATE against a table."""
171
172    @classmethod
173    def requires(cls) -> set[type[Capability]]:
174        return {BalancerdIsRunning, MzIsRunning, TableExists}
175
176    def __init__(self, capabilities: Capabilities) -> None:
177        self.table = random.choice(capabilities.get(TableExists))
178        self.delta = random.randint(1, self.table.max_rows_per_action)
179        super().__init__(capabilities)
180
181    def __str__(self) -> str:
182        return f"{Action.__str__(self)} {self.table.name}"

Performs an INSERT, DELETE or UPDATE against a table.

DML(capabilities: materialize.zippy.framework.Capabilities)
176    def __init__(self, capabilities: Capabilities) -> None:
177        self.table = random.choice(capabilities.get(TableExists))
178        self.delta = random.randint(1, self.table.max_rows_per_action)
179        super().__init__(capabilities)

Construct a new action, possibly conditioning on the available capabilities.

@classmethod
def requires(cls) -> set[type[materialize.zippy.framework.Capability]]:
172    @classmethod
173    def requires(cls) -> set[type[Capability]]:
174        return {BalancerdIsRunning, MzIsRunning, TableExists}

Compute the capability classes that this action requires.

table
delta
class Insert(DML):
185class Insert(DML):
186    """Inserts rows into a table."""
187
188    def run(self, c: Composition, state: State) -> None:
189        prev_max = self.table.watermarks.max
190        self.table.watermarks.max = prev_max + self.delta
191        c.testdrive(
192            f"> INSERT INTO {self.table.name} SELECT * FROM generate_series({prev_max + 1}, {self.table.watermarks.max});",
193            mz_service=state.mz_service,
194        )

Inserts rows into a table.

def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
188    def run(self, c: Composition, state: State) -> None:
189        prev_max = self.table.watermarks.max
190        self.table.watermarks.max = prev_max + self.delta
191        c.testdrive(
192            f"> INSERT INTO {self.table.name} SELECT * FROM generate_series({prev_max + 1}, {self.table.watermarks.max});",
193            mz_service=state.mz_service,
194        )

Run this action on the provided composition.

Inherited Members
DML
DML
requires
table
delta
class ShiftForward(DML):
197class ShiftForward(DML):
198    """Update all rows from a table by incrementing their values by a constant."""
199
200    def run(self, c: Composition, state: State) -> None:
201        self.table.watermarks.shift(self.delta)
202        c.testdrive(
203            f"> UPDATE {self.table.name} SET f1 = f1 + {self.delta};",
204            mz_service=state.mz_service,
205        )

Update all rows from a table by incrementing their values by a constant.

def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
200    def run(self, c: Composition, state: State) -> None:
201        self.table.watermarks.shift(self.delta)
202        c.testdrive(
203            f"> UPDATE {self.table.name} SET f1 = f1 + {self.delta};",
204            mz_service=state.mz_service,
205        )

Run this action on the provided composition.

Inherited Members
DML
DML
requires
table
delta
class ShiftBackward(DML):
208class ShiftBackward(DML):
209    """Update all rows from a table by decrementing their values by a constant."""
210
211    def run(self, c: Composition, state: State) -> None:
212        self.table.watermarks.shift(-self.delta)
213        c.testdrive(
214            f"> UPDATE {self.table.name} SET f1 = f1 - {self.delta};",
215            mz_service=state.mz_service,
216        )

Update all rows from a table by decrementing their values by a constant.

def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
211    def run(self, c: Composition, state: State) -> None:
212        self.table.watermarks.shift(-self.delta)
213        c.testdrive(
214            f"> UPDATE {self.table.name} SET f1 = f1 - {self.delta};",
215            mz_service=state.mz_service,
216        )

Run this action on the provided composition.

Inherited Members
DML
DML
requires
table
delta
class DeleteFromHead(DML):
219class DeleteFromHead(DML):
220    """Delete the largest values from a table"""
221
222    def run(self, c: Composition, state: State) -> None:
223        self.table.watermarks.max = max(
224            self.table.watermarks.max - self.delta, self.table.watermarks.min
225        )
226        c.testdrive(
227            f"> DELETE FROM {self.table.name} WHERE f1 > {self.table.watermarks.max};",
228            mz_service=state.mz_service,
229        )

Delete the largest values from a table

def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
222    def run(self, c: Composition, state: State) -> None:
223        self.table.watermarks.max = max(
224            self.table.watermarks.max - self.delta, self.table.watermarks.min
225        )
226        c.testdrive(
227            f"> DELETE FROM {self.table.name} WHERE f1 > {self.table.watermarks.max};",
228            mz_service=state.mz_service,
229        )

Run this action on the provided composition.

Inherited Members
DML
DML
requires
table
delta
class DeleteFromTail(DML):
232class DeleteFromTail(DML):
233    """Delete the smallest values from a table"""
234
235    def run(self, c: Composition, state: State) -> None:
236        self.table.watermarks.min = min(
237            self.table.watermarks.min + self.delta, self.table.watermarks.max
238        )
239        c.testdrive(
240            f"> DELETE FROM {self.table.name} WHERE f1 < {self.table.watermarks.min};",
241            mz_service=state.mz_service,
242        )

Delete the smallest values from a table

def run( self, c: materialize.mzcompose.composition.Composition, state: materialize.zippy.framework.State) -> None:
235    def run(self, c: Composition, state: State) -> None:
236        self.table.watermarks.min = min(
237            self.table.watermarks.min + self.delta, self.table.watermarks.max
238        )
239        c.testdrive(
240            f"> DELETE FROM {self.table.name} WHERE f1 < {self.table.watermarks.min};",
241            mz_service=state.mz_service,
242        )

Run this action on the provided composition.

Inherited Members
DML
DML
requires
table
delta