o
    pfE                     @   s   d dl Z d dlZd dlZd dlZd dlmZ d dlZd dlZd dl	m
Z
 d dlmZ d dlmZ d dlmZ dZdZd	Zg d
ZG dd dZdS )    N)Iterator)ConnectionPool)Metric)Tile)Tilesetmetadatagenerate_stats
tile_stats)	g        g      ?g      ?g      ?g?gffffff?gGz?g+?g      ?c                
   @   s  e Zd ZdZd?defddZ	 d@dd	Z	 d
ededededdf
ddZ	d
eddfddZ
dee fddZdee fddZ	 dee fddZd@ddZ	 dd ZdefddZdd Zd d! Z	 d
ed"ee fd#d$ZdAd
efd%d&Zd
ed'edeedB ejdB f fd(d)Z	*dBd
ed'ed+edejdB fd,d-Zd.d/ Zd0d1 Zd2d3 Z d@d4d5Z!d6d7 Z"d8d9 Z#d
ed:eddfd;d<Z$d
ed'efd=d>Z%dS )CStoragez
    Storage is an object representing a tile storage, backed by a PostgreSQL database

    A Storage contains tiles and metadata about tilesets, and has functions to update
    tiles and metadata based on the ID
    tilekilndbpoolc                 C   s   || _ || _d S N)_Storage__pool_Storage__schema)selfr   schema r   I/home/ertert/spirit/venv/lib/python3.10/site-packages/tilekiln/storage.py__init__    s   
zStorage.__init__returnNc              	   C   s   | j  =}|  }|d| j d | | | | |  W d    n1 s-w   Y  W d    d S W d    d S 1 sEw   Y  d S )NzCREATE SCHEMA IF NOT EXISTS "")r   
connectioncursorexecuter   _Storage__setup_stats_Storage__setup_metadatacommit)r   conncurr   r   r   create_schema'   s   



"zStorage.create_schemaidminzoommaxzoomtilejsonc              	   C   s   | j  :}| }| ||||| | |||| |  W d    n1 s*w   Y  W d    d S W d    d S 1 sBw   Y  d S r   )r   r   r   _Storage__set_metadata_Storage__setup_tablesr   r   r    r!   r"   r#   r   r   r   r   r   create_tileset4   s   

"zStorage.create_tilesetc              	   C   s   | j  T}| 7}|d| j dt d|f |d| j d| d |d| j dt d|f |  W d    n1 sDw   Y  W d    d S W d    d S 1 s\w   Y  d S )NDELETE FROM ""."z" WHERE id = %szDROP TABLE "z	" CASCADE)r   r   r   r   r   METADATA_TABLETILE_STATS_TABLEr   )r   r    r   r   r   r   r   remove_tileset=   s   

"zStorage.remove_tilesetc                 c   s    | j  R}d|_|jtjjd.}|d| j dt	 d |D ]}t
| |d |d |d t|d	 V  q"W d
   n1 sCw   Y  W d
   d
S W d
   d
S 1 s[w   Y  d
S )z2
        Gets all tilesets in the storage
        Trow_factoryzISELECT id, minzoom, maxzoom, tilejson
                             FROM "r)   r   r    r!   r"   r#   N)r   r   	read_onlyr   psycopgrowsdict_rowr   r   r*   r   jsondumpsr   r   r   recordr   r   r   get_tilesetsG   s$   
"zStorage.get_tilesetsc              	   c   s    | j  C}d|_|jtjjd}|d| j dt	 d |D ]}|d V  q"W d   n1 s4w   Y  W d   dS W d   dS 1 sLw   Y  dS )z*
        Get only the tileset IDs
        Tr-   z-SELECT id
                             FROM "r)   r   r    N)
r   r   r/   r   r0   r1   r2   r   r   r*   r5   r   r   r   get_tileset_idsT   s    
"zStorage.get_tileset_idsc              	   c   s    | j  C}d|_|jtjtd}|d| j	 dt
 d |D ]}|V  q$W d    n1 s4w   Y  W d    d S W d    d S 1 sLw   Y  d S )NTr-   zQSELECT id, zoom, num_tiles, size, percentiles
                             FROM "r)   r   )r   r   r/   r   r0   r1   	class_rowr   r   r   r+   r5   r   r   r   metricsa   s    
"zStorage.metricsc              	   C   s   | j  B}| %}|  D ]}| |}| |}| |||| q|  W d    n1 s2w   Y  W d    d S W d    d S 1 sJw   Y  d S r   )r   r   r   r8   get_minzoomget_maxzoom _Storage__update_tileset_metricsr   )r   r   r   r    r!   r"   r   r   r   update_metricsj   s   



"zStorage.update_metricsc              	   C   s   | j  2}| }| ||||| |  W d   n1 s"w   Y  W d   dS W d   dS 1 s:w   Y  dS )zn
        Saves metadata into storage

        This just wraps __set_metadata, which requires a cursor
        N)r   r   r   r$   r   r&   r   r   r   set_metadatat   s   

"zStorage.set_metadatac              	   C   s   | j  c}d|_|jtjjdG}|d| j dt	 d|f |
 }|du r9tjd| ddd	 td
 |d }| d g|d< t|W  d   W  d   S 1 s[w   Y  W d   dS 1 skw   Y  dS )z+Gets the tilejson for a layer from storage.Tr-   z6SELECT tilejson
                                FROM "r)   /"
                                WHERE id = %sNz#Failed to retrieve tilejson for id , does it exist in storage DB?err   r#   z/{z}/{x}/{y}.mvttiles)r   r   r/   r   r0   r1   r2   r   r   r*   fetchoneclickechosysexitr3   r4   )r   r    urlr   r   resultr#   r   r   r   get_tilejson   s.   
"zStorage.get_tilejsonc              	   C      | j  V}d|_|jtjjd:}|d| j dt	 d|f |
 }|du r9tjd| ddd	 td
 |d W  d   W  d   S 1 sNw   Y  W d   dS 1 s^w   Y  dS )*Gets the minzoom for a layer from storage.Tr-   z5SELECT minzoom
                                FROM "r)   r@   N"Failed to retrieve minzoom for id rA   rB   rD   r!   r   r   r/   r   r0   r1   r2   r   r   r*   rF   rG   rH   rI   rJ   r   r    r   r   rL   r   r   r   r;      *   
"zStorage.get_minzoomc              	   C   rN   )rO   Tr-   z5SELECT maxzoom
                                FROM "r)   r@   NrP   rA   rB   rD   r"   rQ   rR   r   r   r   r<      rS   zStorage.get_maxzoomrE   c              	   C   sx   | j  -}| }|D ]	}| ||| qW d    n1 s!w   Y  |  W d    d S 1 s5w   Y  d S r   )r   r   r   _Storage__delete_tiler   )r   r    rE   r   r   tiler   r   r   delete_tiles   s   

"zStorage.delete_tilesc              	   C   s   | j  F}| )}|d u rt| || |d }|D ]	}| ||| q|  W d    n1 s6w   Y  W d    d S W d    d S 1 sNw   Y  d S )NrD   )r   r   r   ranger;   r<   _Storage__truncate_tabler   )r   r    zoomsr   r   zoomr   r   r   truncate_tables   s   

"zStorage.truncate_tablesrU   c              	   C   s   | j  e}|d |jtjjdG}|jd| j d| d|j|j	|j
fdd | }|d u rA	 W d    W d    dS t|d	 |d
 fW  d    W  d    S 1 s]w   Y  W d    d S 1 smw   Y  d S )NSET TIMEZONE TO 'GMT'r-   zSELECT generated, tile FROM "r)   zG"
                                WHERE zoom = %s AND x = %s AND y = %sT)binary)NNrU   	generated)r   r   r   r   r0   r1   r2   r   rZ   xyrF   gzip
decompress)r   r    rU   r   r   rL   r   r   r   get_tile   s    
	"zStorage.get_tiler   tiledatac           	      C   s   | j  j}|d |jtjjdL}| d|j }|d| j d| d|j|j	|j
tj|ddf | }|d u rM	 W d    W d    d S |d	 W  d    W  d    S 1 sbw   Y  W d    d S 1 srw   Y  d S )
Nr\   r-   _zINSERT INTO "r)   z" AS store
(zoom, x, y, tile)
VALUES (%s, %s, %s, %s)
ON CONFLICT (zoom, x, y)
DO UPDATE SET tile = EXCLUDED.tile,
generated = CASE WHEN store.tile != EXCLUDED.tile
    THEN statement_timestamp()
    ELSE store.generated END
RETURNING generatedr   )mtimer^   )r   r   r   r   r0   r1   r2   rZ   r   r_   r`   ra   compressrF   )	r   r    rU   rd   render_timer   r   	tablenamerL   r   r   r   	save_tile   s"   
	
"zStorage.save_tilec                 C   s   | d| j dt d dS )zE Create the metadata table in storage. This is safe to rerun
        CREATE TABLE IF NOT EXISTS "r)   z" (
            id text PRIMARY KEY,
            active boolean NOT NULL DEFAULT TRUE,
            minzoom smallint NOT NULL,
            maxzoom smallint NOT NULL,
            tilejson jsonb NOT NULL)Nr   r   r*   r   r   r   r   r   __setup_metadata   s   zStorage.__setup_metadatac                 C   s(   | d| j dt d||||f dS )z
        Sets metadata using a cursor

        This is separate from set_metadata because sometimes it needs
        calling within a transaction
        rf   r)   z"
        (id, minzoom, maxzoom, tilejson)
        VALUES (%s, %s, %s, %s)
        ON CONFLICT (id)
        DO UPDATE SET minzoom = EXCLUDED.minzoom,
        maxzoom = EXCLUDED.maxzoom,
        tilejson = EXCLUDED.tilejson
        Nrm   )r   r   r    r!   r"   r#   r   r   r   __set_metadata   s   
zStorage.__set_metadatac                 C   s8   | d| j dt d | d| j dt d dS )zqCreate the stats tables.

        One table has tile generation stats, the other has tile storage stats.
        z1CREATE UNLOGGED TABLE IF NOT EXISTS
            "r)   z" (
            id text,
            zoom smallint,
            num_rendered integer DEFAULT 0,
            time_rendered interval DEFAULT '0',
            PRIMARY KEY (id, zoom)
        )
        rl   a   " (
            id text,
            zoom smallint,
            num_tiles integer NOT NULL,
            size bigint NOT NULL,
            percentiles double precision[][] NOT NULL,
            PRIMARY KEY (id, zoom),
            CHECK (array_length(percentiles, 1) = 2)
        )
        N)r   r   GENERATE_STATS_TABLEr+   rn   r   r   r   __setup_stats  s   

zStorage.__setup_statsc                 C   sb   t ||d D ]'}| d| }|d |d| j dt d| j d| d	||td qd S )	NrD   re   zSET LOCAL jit TO ON;rf   r)   ay  "
                        SELECT
                            %(id)s AS id,
                            %(zoom)s AS zoom,
                            COUNT(*) AS num_tiles,
                            COALESCE(SUM(length(tile)),0) AS size,
                            ARRAY[%(percentile)s,
                                COALESCE(PERCENTILE_CONT(%(percentile)s::double precision[])
                                    WITHIN GROUP (ORDER BY length(tile)),
                                    array_fill(0,
                                    ARRAY[array_length(%(percentile)s, 1)]))] AS percentiles
                            FROM "a  "
                            ON CONFLICT (id, zoom)
                        DO UPDATE SET num_tiles = EXCLUDED.num_tiles,
                            size = EXCLUDED.size,
                            percentiles = EXCLUDED.percentiles;
                        )r    rZ   
percentile)rW   r   r   r+   PERCENTILESr   r   r    r!   r"   rZ   rj   r   r   r   __update_tileset_metrics-  s   

z Storage.__update_tileset_metricsc                 C   s   | d| j d| d| d| d	 t||d D ]-}| d| }| d| j d| d| j d| d	| d
 | d| j d| d qdS )zCreate the tile storage tables

        This creates the tile storage tables. It intentionally
        does not try to overwrite existing tables.
        zCREATE TABLE "r)   z5" (
                    zoom smallint CHECK (zoom >= z AND zoom <= aH  ),
                    x int CHECK (x >= 0 AND x < 1 << zoom),
                    y int CHECK (y >= 0 AND y < 1 << zoom),
                    generated timestamptz DEFAULT statement_timestamp(),
                    tile bytea NOT NULL,
                    primary key (zoom, x, y)
                    ) PARTITION BY LIST (zoom)rD   re   z,"
                            PARTITION OF "z-"
                            FOR VALUES IN ()zALTER TABLE "zD"
                            ALTER COLUMN tile SET STORAGE EXTERNALN)r   r   rW   ru   r   r   r   __setup_tablesO  s    

zStorage.__setup_tablesc              	   C   s   | j  a}|jtjjd@}|d| j dt d| j	f |
 }|du r8tjd| j	 ddd	 td
 |d | _|d | _|d | _W d   n1 sQw   Y  W d   dS W d   dS 1 siw   Y  dS )znLoad the stored metadata.

        This allows serving a TileJSON without having access to the config
        r-   zHSELECT minzoom, maxzoom, tilejson
                                FROM "r)   r@   Nz#Failed to retrieve metadata for id rA   TrB   rD   r!   r"   r#   )r   r   r   r0   r1   r2   r   r   r*   r    rF   rG   rH   rI   rJ   r!   r"   _Storage__rawtilejson)r   r   r   rL   r   r   r   __load_metadatag  s,   


"zStorage.__load_metadatarZ   c                 C   s,   | d| }| d| j d| d dS )z4Remove every tile from a particular tileset and zoomre   zTRUNCATE TABLE "r)   r   N)r   r   )r   r   r    rZ   rj   r   r   r   __truncate_table|  s   zStorage.__truncate_tablec                 C   s,   | d| j d| d|j|j|jf dS )a?  Delete an individual tile

        How this is implemented is not ideal for long lists of tiles
        to delete, but generally a long list is an entire zoom or a box.

        In the former case it is implemented as __truncate_table, and
        the latter case is not implemented but would take min/max x/y.
        r(   r)   z?"
                        WHERE zoom = %s AND x = %s AND y = %sN)r   r   rZ   r_   r`   )r   r   r    rU   r   r   r   __delete_tile  s   	zStorage.__delete_tile)r   )r   Nr   )r   )&__name__
__module____qualname____doc__r   r   r   strintr'   r,   r   r   r7   r8   r   r:   r>   r?   rM   r;   r<   r   rV   r[   tuplebytesdatetimerc   rk   r   r$   r   r=   r%   _Storage__load_metadatarX   rT   r   r   r   r   r
      sH    

	

		(	

!"r
   )r   ra   r3   rI   collections.abcr   rG   psycopg.rowsr0   psycopg_poolr   tilekiln.metricr   tilekiln.tiler   tilekiln.tilesetr   r*   rq   r+   rt   r
   r   r   r   r   <module>   s     