Add JORF data.
This commit is contained in:
parent
7602ac2852
commit
6842108f49
28 changed files with 1334 additions and 443 deletions
99
src/lib/auditors/data.ts
Normal file
99
src/lib/auditors/data.ts
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
import {
|
||||||
|
type Audit,
|
||||||
|
auditChain,
|
||||||
|
auditRequire,
|
||||||
|
auditString,
|
||||||
|
auditTest,
|
||||||
|
auditOptions,
|
||||||
|
} from "@auditors/core"
|
||||||
|
|
||||||
|
export const auditId = auditChain(
|
||||||
|
auditString,
|
||||||
|
auditTest((id) => id.length === 20, "Invalid length for ID"),
|
||||||
|
)
|
||||||
|
|
||||||
|
export function auditVersions(
|
||||||
|
audit: Audit,
|
||||||
|
dataUnknown: unknown,
|
||||||
|
): [unknown, unknown] {
|
||||||
|
if (dataUnknown == null) {
|
||||||
|
return [dataUnknown, null]
|
||||||
|
}
|
||||||
|
if (typeof dataUnknown !== "object") {
|
||||||
|
return audit.unexpectedType(dataUnknown, "object")
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = { ...dataUnknown }
|
||||||
|
const errors: { [key: string]: unknown } = {}
|
||||||
|
const remainingKeys = new Set(Object.keys(data))
|
||||||
|
|
||||||
|
audit.attribute(
|
||||||
|
data,
|
||||||
|
"VERSION",
|
||||||
|
true,
|
||||||
|
errors,
|
||||||
|
remainingKeys,
|
||||||
|
auditVersionsVersion,
|
||||||
|
auditRequire,
|
||||||
|
)
|
||||||
|
|
||||||
|
return audit.reduceRemaining(data, errors, remainingKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function auditVersionsVersion(
|
||||||
|
audit: Audit,
|
||||||
|
dataUnknown: unknown,
|
||||||
|
): [unknown, unknown] {
|
||||||
|
if (dataUnknown == null) {
|
||||||
|
return [dataUnknown, null]
|
||||||
|
}
|
||||||
|
if (typeof dataUnknown !== "object") {
|
||||||
|
return audit.unexpectedType(dataUnknown, "object")
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = { ...dataUnknown }
|
||||||
|
const errors: { [key: string]: unknown } = {}
|
||||||
|
const remainingKeys = new Set(Object.keys(data))
|
||||||
|
|
||||||
|
audit.attribute(
|
||||||
|
data,
|
||||||
|
"@id",
|
||||||
|
true,
|
||||||
|
errors,
|
||||||
|
remainingKeys,
|
||||||
|
auditId,
|
||||||
|
auditRequire,
|
||||||
|
)
|
||||||
|
audit.attribute(
|
||||||
|
data,
|
||||||
|
"@fin",
|
||||||
|
true,
|
||||||
|
errors,
|
||||||
|
remainingKeys,
|
||||||
|
auditString,
|
||||||
|
auditOptions(["2999-01-01"]),
|
||||||
|
auditRequire,
|
||||||
|
)
|
||||||
|
audit.attribute(
|
||||||
|
data,
|
||||||
|
"@etat",
|
||||||
|
true,
|
||||||
|
errors,
|
||||||
|
remainingKeys,
|
||||||
|
auditString,
|
||||||
|
auditOptions([""]),
|
||||||
|
auditRequire,
|
||||||
|
)
|
||||||
|
audit.attribute(
|
||||||
|
data,
|
||||||
|
"@debut",
|
||||||
|
true,
|
||||||
|
errors,
|
||||||
|
remainingKeys,
|
||||||
|
auditString,
|
||||||
|
auditOptions(["2999-01-01"]),
|
||||||
|
auditRequire,
|
||||||
|
)
|
||||||
|
|
||||||
|
return audit.reduceRemaining(data, errors, remainingKeys)
|
||||||
|
}
|
184
src/lib/data.ts
184
src/lib/data.ts
|
@ -11,22 +11,11 @@ export interface Article {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CONTEXTE: {
|
CONTEXTE: Contexte
|
||||||
TEXTE: {
|
|
||||||
TITRE_TXT: TitreTexte | TitreTexte[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VERSIONS: {
|
VERSIONS: {
|
||||||
VERSION: Array<{
|
VERSION: Array<{
|
||||||
"@etat": Etat
|
"@etat": Etat
|
||||||
LIEN_ART: {
|
LIEN_ART: LienArt
|
||||||
"@id": string
|
|
||||||
"@fin": string
|
|
||||||
"@num": string
|
|
||||||
"@etat": Etat
|
|
||||||
"@debut": string
|
|
||||||
"@origine": "LEGI"
|
|
||||||
}
|
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
BLOC_TEXTUEL: {
|
BLOC_TEXTUEL: {
|
||||||
|
@ -34,36 +23,65 @@ export interface Article {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EliId = string
|
export interface Contexte {
|
||||||
|
TEXTE: {
|
||||||
export interface EliVersions {}
|
TITRE_TXT: TitreTxt | TitreTxt[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Etat = "MODIFIE" | "VIGUEUR"
|
export type Etat = "MODIFIE" | "VIGUEUR"
|
||||||
export type LegiObject =
|
|
||||||
| Article
|
|
||||||
| EliId
|
|
||||||
| EliVersions
|
|
||||||
| Section
|
|
||||||
| Struct
|
|
||||||
| TexteVersion
|
|
||||||
|
|
||||||
export type LegiObjectType =
|
export interface Jo {
|
||||||
|
META: {
|
||||||
|
META_SPEC: {
|
||||||
|
META_CONTENEUR: {
|
||||||
|
NUM: string
|
||||||
|
TITRE: string
|
||||||
|
DATE_PUBLI: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
META_COMMUN: MetaCommun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LegalObject =
|
||||||
|
| Article
|
||||||
|
| Jo
|
||||||
|
| SectionTa
|
||||||
|
| Textelr
|
||||||
|
| TexteVersion
|
||||||
|
| Versions
|
||||||
|
|
||||||
|
export type LegalObjectType =
|
||||||
| "article"
|
| "article"
|
||||||
| "eli_id"
|
| "id"
|
||||||
| "eli_versions"
|
| "jo"
|
||||||
| "section"
|
| "section_ta"
|
||||||
| "struct"
|
| "texte_version"
|
||||||
| "texte"
|
| "textelr"
|
||||||
|
| "versions"
|
||||||
|
|
||||||
|
export interface LienArt {
|
||||||
|
"@id": string
|
||||||
|
"@fin": string
|
||||||
|
"@num": string
|
||||||
|
"@etat": Etat
|
||||||
|
"@debut": string
|
||||||
|
"@origine": "LEGI"
|
||||||
|
}
|
||||||
|
|
||||||
export interface MetaCommun {
|
export interface MetaCommun {
|
||||||
ID: string
|
ID: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Section {
|
export interface SectionTa {
|
||||||
ID: string
|
ID: string
|
||||||
|
CONTEXTE: Contexte
|
||||||
|
TITRE_TA: string
|
||||||
|
STRUCTURE_TA: { LIEN_ART?: LienArt | LienArt[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Struct {
|
export interface Textelr {
|
||||||
META: {
|
META: {
|
||||||
META_COMMUN: MetaCommun
|
META_COMMUN: MetaCommun
|
||||||
}
|
}
|
||||||
|
@ -71,58 +89,102 @@ export interface Struct {
|
||||||
|
|
||||||
export interface TexteVersion {
|
export interface TexteVersion {
|
||||||
META: {
|
META: {
|
||||||
|
META_SPEC: {
|
||||||
|
META_TEXTE_VERSION: {
|
||||||
|
TITRE: string
|
||||||
|
TITREFULL: string
|
||||||
|
}
|
||||||
|
}
|
||||||
META_COMMUN: MetaCommun
|
META_COMMUN: MetaCommun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TitreTexte {
|
export interface TitreTxt {
|
||||||
|
"@fin": string
|
||||||
|
"@debut": string
|
||||||
|
"@id_txt": string
|
||||||
|
"@c_titre_court": string
|
||||||
"#text": string
|
"#text": string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertNeverLegiObjectType(type: never): never {
|
export interface Versions {
|
||||||
throw `Unexpected type for LEGI object: ${type}`
|
VERSION: {
|
||||||
|
"@id": string
|
||||||
|
"@fin": "2999-01-01"
|
||||||
|
"@etat": ""
|
||||||
|
"@debut": "2999-01-01"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pathnameFromLegiObject(
|
export interface XmlHeader {
|
||||||
type: LegiObjectType,
|
"@encoding": "UTF-8"
|
||||||
object: LegiObject,
|
"@version": "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertNeverLegalObjectType(type: never): never {
|
||||||
|
throw `Unexpected type for legal object: ${type}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bestItemForDate<T extends { "@debut": string; "@fin": string }>(
|
||||||
|
items: T | T[],
|
||||||
|
date: string,
|
||||||
|
): T | undefined {
|
||||||
|
if (!Array.isArray(items)) {
|
||||||
|
// Singleton
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
for (const item of items) {
|
||||||
|
if (item["@debut"] <= date && date <= item["@fin"]) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathnameFromLegalObject(
|
||||||
|
type: LegalObjectType,
|
||||||
|
object: LegalObject,
|
||||||
): string {
|
): string {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "article":
|
case "article":
|
||||||
return `/articles/${(object as Article).META.META_COMMUN.ID}`
|
return `/article/${(object as Article).META.META_COMMUN.ID}`
|
||||||
case "eli_id":
|
case "id":
|
||||||
return `/eli/ids/TODO`
|
return `/eli/ids/TODO`
|
||||||
case "eli_versions":
|
case "jo":
|
||||||
return `/eli/ids/TODO`
|
return `/jo/${(object as Jo).META.META_COMMUN.ID}`
|
||||||
case "section":
|
case "section_ta":
|
||||||
return `/sections/${(object as Section).ID}`
|
return `/section_ta/${(object as unknown as SectionTa).ID}`
|
||||||
case "struct":
|
case "texte_version":
|
||||||
return `/structs/${(object as Struct).META.META_COMMUN.ID}`
|
return `/texte_version/${(object as TexteVersion).META.META_COMMUN.ID}`
|
||||||
case "texte":
|
case "textelr":
|
||||||
return `/textes/${(object as TexteVersion).META.META_COMMUN.ID}`
|
return `/textelr/${(object as Textelr).META.META_COMMUN.ID}`
|
||||||
|
case "versions":
|
||||||
|
return `/eli/versions/TODO`
|
||||||
default:
|
default:
|
||||||
assertNeverLegiObjectType(type)
|
assertNeverLegalObjectType(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pathnameFromLegiObjectId(
|
export function pathnameFromLegalObjectId(
|
||||||
type: LegiObjectType,
|
type: LegalObjectType,
|
||||||
id: string,
|
id: string,
|
||||||
): string {
|
): string {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "article":
|
case "article":
|
||||||
return `/articles/${id}`
|
return `/article/${id}`
|
||||||
case "eli_id":
|
case "id":
|
||||||
return `/eli/ids/TODO`
|
return `/eli/ids/TODO`
|
||||||
case "eli_versions":
|
case "jo":
|
||||||
return `/eli/ids/TODO`
|
return `/jo/${id}`
|
||||||
case "section":
|
case "section_ta":
|
||||||
return `/sections/${id}`
|
return `/section_ta/${id}`
|
||||||
case "struct":
|
case "texte_version":
|
||||||
return `/structs/${id}`
|
return `/texte_version/${id}`
|
||||||
case "texte":
|
case "textelr":
|
||||||
return `/textes/${id}`
|
return `/textelr/${id}`
|
||||||
|
case "versions":
|
||||||
|
return `/eli/versions/TODO`
|
||||||
default:
|
default:
|
||||||
assertNeverLegiObjectType(type)
|
assertNeverLegalObjectType(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
369
src/lib/scripts/import_jorf.ts
Normal file
369
src/lib/scripts/import_jorf.ts
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
import { auditChain, auditRequire, strictAudit } from "@auditors/core"
|
||||||
|
import assert from "assert"
|
||||||
|
import { XMLParser } from "fast-xml-parser"
|
||||||
|
import fs from "fs-extra"
|
||||||
|
import he from "he"
|
||||||
|
import path from "path"
|
||||||
|
import type { JSONValue } from "postgres"
|
||||||
|
import sade from "sade"
|
||||||
|
|
||||||
|
import { auditId, auditVersions } from "$lib/auditors/data"
|
||||||
|
import type {
|
||||||
|
Article,
|
||||||
|
Jo,
|
||||||
|
SectionTa,
|
||||||
|
Textelr,
|
||||||
|
TexteVersion,
|
||||||
|
Versions,
|
||||||
|
XmlHeader,
|
||||||
|
} from "$lib/data"
|
||||||
|
import { db } from "$lib/server/database"
|
||||||
|
import { walkDir } from "$lib/server/file_systems"
|
||||||
|
|
||||||
|
const xmlParser = new XMLParser({
|
||||||
|
attributeNamePrefix: "@",
|
||||||
|
ignoreAttributes: false,
|
||||||
|
stopNodes: ["ARTICLE.BLOC_TEXTUEL.CONTENU", "ARTICLE.SM.CONTENU"],
|
||||||
|
tagValueProcessor: (_tagName, tagValue) => he.decode(tagValue),
|
||||||
|
})
|
||||||
|
|
||||||
|
async function importJorf({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
|
let skip = resume !== undefined
|
||||||
|
const deleteRemainingIds = !skip
|
||||||
|
|
||||||
|
const articleRemainingIds = new Set(
|
||||||
|
(
|
||||||
|
await db<{ id: string }[]>`
|
||||||
|
SELECT id
|
||||||
|
FROM article
|
||||||
|
WHERE id LIKE 'JORF%'
|
||||||
|
`
|
||||||
|
).map(({ id }) => id),
|
||||||
|
)
|
||||||
|
const idRemainingElis = new Set(
|
||||||
|
(
|
||||||
|
await db<{ eli: string }[]>`
|
||||||
|
SELECT eli
|
||||||
|
FROM id
|
||||||
|
`
|
||||||
|
).map(({ eli }) => eli),
|
||||||
|
)
|
||||||
|
const joRemainingIds = new Set(
|
||||||
|
(
|
||||||
|
await db<{ id: string }[]>`
|
||||||
|
SELECT id
|
||||||
|
FROM jo
|
||||||
|
`
|
||||||
|
).map(({ id }) => id),
|
||||||
|
)
|
||||||
|
const sectionTaRemainingIds = new Set(
|
||||||
|
(
|
||||||
|
await db<{ id: string }[]>`
|
||||||
|
SELECT id
|
||||||
|
FROM section_ta
|
||||||
|
WHERE id LIKE 'JORF%'
|
||||||
|
`
|
||||||
|
).map(({ id }) => id),
|
||||||
|
)
|
||||||
|
const textelrRemainingIds = new Set(
|
||||||
|
(
|
||||||
|
await db<{ id: string }[]>`
|
||||||
|
SELECT id
|
||||||
|
FROM textelr
|
||||||
|
WHERE id LIKE 'JORF%'
|
||||||
|
`
|
||||||
|
).map(({ id }) => id),
|
||||||
|
)
|
||||||
|
const texteVersionRemainingIds = new Set(
|
||||||
|
(
|
||||||
|
await db<{ id: string }[]>`
|
||||||
|
SELECT id
|
||||||
|
FROM texte_version
|
||||||
|
WHERE id LIKE 'JORF%'
|
||||||
|
`
|
||||||
|
).map(({ id }) => id),
|
||||||
|
)
|
||||||
|
const versionsRemainingElis = new Set(
|
||||||
|
(
|
||||||
|
await db<{ eli: string }[]>`
|
||||||
|
SELECT eli
|
||||||
|
FROM versions
|
||||||
|
`
|
||||||
|
).map(({ eli }) => eli),
|
||||||
|
)
|
||||||
|
|
||||||
|
const dataDir = path.join("..", "dila-data", "jorf")
|
||||||
|
assert(await fs.pathExists(dataDir))
|
||||||
|
iterXmlFiles: for (const relativeSplitPath of walkDir(dataDir)) {
|
||||||
|
const relativePath = path.join(...relativeSplitPath)
|
||||||
|
if (skip) {
|
||||||
|
if (relativePath.startsWith(resume!)) {
|
||||||
|
skip = false
|
||||||
|
console.log(`Resuming at file ${relativePath}...`)
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = path.join(dataDir, relativePath)
|
||||||
|
if (!filePath.endsWith(".xml")) {
|
||||||
|
console.info(`Skipping non XML file at ${filePath}`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const xmlString: string = await fs.readFile(filePath, {
|
||||||
|
encoding: "utf8",
|
||||||
|
})
|
||||||
|
const xmlData = xmlParser.parse(xmlString)
|
||||||
|
for (const [key, element] of Object.entries(xmlData) as [
|
||||||
|
string,
|
||||||
|
(
|
||||||
|
| Article
|
||||||
|
| Jo
|
||||||
|
| SectionTa
|
||||||
|
| Textelr
|
||||||
|
| TexteVersion
|
||||||
|
| Versions
|
||||||
|
| XmlHeader
|
||||||
|
),
|
||||||
|
][]) {
|
||||||
|
switch (key) {
|
||||||
|
case "?xml": {
|
||||||
|
const xmlHeader = element as XmlHeader
|
||||||
|
assert.strictEqual(xmlHeader["@encoding"], "UTF-8", filePath)
|
||||||
|
assert.strictEqual(xmlHeader["@version"], "1.0", filePath)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "ARTICLE": {
|
||||||
|
const article = element as Article
|
||||||
|
await db`
|
||||||
|
INSERT INTO article (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${article.META.META_COMMUN.ID},
|
||||||
|
${db.json(article as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(article as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
articleRemainingIds.delete(article.META.META_COMMUN.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "ID": {
|
||||||
|
assert.strictEqual(relativeSplitPath[0], "global")
|
||||||
|
assert.strictEqual(relativeSplitPath[1], "eli")
|
||||||
|
const eli = relativeSplitPath.slice(2, -1).join("/")
|
||||||
|
const [id, idError] = auditChain(auditId, auditRequire)(
|
||||||
|
strictAudit,
|
||||||
|
element,
|
||||||
|
)
|
||||||
|
assert.strictEqual(
|
||||||
|
idError,
|
||||||
|
null,
|
||||||
|
`Unexpected format for ID:\n${JSON.stringify(
|
||||||
|
id,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\nError:\n${JSON.stringify(idError, null, 2)}`,
|
||||||
|
)
|
||||||
|
assert
|
||||||
|
await db`
|
||||||
|
INSERT INTO id (
|
||||||
|
eli,
|
||||||
|
id
|
||||||
|
) VALUES (
|
||||||
|
${eli},
|
||||||
|
${id}
|
||||||
|
)
|
||||||
|
ON CONFLICT (eli)
|
||||||
|
DO UPDATE SET
|
||||||
|
id = ${id}
|
||||||
|
`
|
||||||
|
idRemainingElis.delete(eli)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "JO": {
|
||||||
|
const jo = element as Jo
|
||||||
|
await db`
|
||||||
|
INSERT INTO jo (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${jo.META.META_COMMUN.ID},
|
||||||
|
${db.json(jo as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(jo as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
joRemainingIds.delete(jo.META.META_COMMUN.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "SECTION_TA": {
|
||||||
|
const section = element as SectionTa
|
||||||
|
await db`
|
||||||
|
INSERT INTO section_ta (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${section.ID},
|
||||||
|
${db.json(section as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(section as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
sectionTaRemainingIds.delete(section.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "TEXTE_VERSION": {
|
||||||
|
const version = element as TexteVersion
|
||||||
|
await db`
|
||||||
|
INSERT INTO texte_version (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${version.META.META_COMMUN.ID},
|
||||||
|
${db.json(version as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(version as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
texteVersionRemainingIds.delete(version.META.META_COMMUN.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "TEXTELR": {
|
||||||
|
const textelr = element as Textelr
|
||||||
|
await db`
|
||||||
|
INSERT INTO textelr (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${textelr.META.META_COMMUN.ID},
|
||||||
|
${db.json(textelr as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(textelr as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
textelrRemainingIds.delete(textelr.META.META_COMMUN.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "VERSIONS": {
|
||||||
|
assert.strictEqual(relativeSplitPath[0], "global")
|
||||||
|
assert.strictEqual(relativeSplitPath[1], "eli")
|
||||||
|
const eli = relativeSplitPath.slice(2, -1).join("/")
|
||||||
|
const [versions, versionsError] = auditChain(
|
||||||
|
auditVersions,
|
||||||
|
auditRequire,
|
||||||
|
)(strictAudit, element)
|
||||||
|
assert.strictEqual(
|
||||||
|
versionsError,
|
||||||
|
null,
|
||||||
|
`Unexpected format for VERSIONS:\n${JSON.stringify(
|
||||||
|
versions,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\nError:\n${JSON.stringify(versionsError, null, 2)}`,
|
||||||
|
)
|
||||||
|
const id = versions.VERSION["@id"]
|
||||||
|
await db`
|
||||||
|
INSERT INTO versions (
|
||||||
|
eli,
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${eli},
|
||||||
|
${id},
|
||||||
|
${db.json(versions as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (eli)
|
||||||
|
DO UPDATE SET
|
||||||
|
id = ${id},
|
||||||
|
data = ${db.json(versions as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
versionsRemainingElis.delete(id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.warn(
|
||||||
|
`Unexpected root element "${key}" in XML file: ${filePath}`,
|
||||||
|
)
|
||||||
|
break iterXmlFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("An error occurred while parsing XML file", filePath)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleteRemainingIds) {
|
||||||
|
for (const id of articleRemainingIds) {
|
||||||
|
console.log(`Deleting ARTICLE ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM article
|
||||||
|
WHERE id = ${id}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const eli of idRemainingElis) {
|
||||||
|
console.log(`Deleting ID ${eli}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM id
|
||||||
|
WHERE eli = ${eli}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const id of joRemainingIds) {
|
||||||
|
console.log(`Deleting JO ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM jo
|
||||||
|
WHERE id = ${id}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const id of sectionTaRemainingIds) {
|
||||||
|
console.log(`Deleting SECTION_TA ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM section_ta
|
||||||
|
WHERE id = ${id}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const id of textelrRemainingIds) {
|
||||||
|
console.log(`Deleting TEXTELR ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM textelr
|
||||||
|
WHERE id = ${id}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const id of texteVersionRemainingIds) {
|
||||||
|
console.log(`Deleting TEXTE_VERSION ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM texte_version
|
||||||
|
WHERE id = ${id}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const eli of versionsRemainingElis) {
|
||||||
|
console.log(`Deleting VERSIONS ${eli}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM versions
|
||||||
|
WHERE eli = ${eli}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sade("import_jorf", true)
|
||||||
|
.describe("Import Dila's JORF database")
|
||||||
|
.option("-r", "--resume", "Resume import at given relative file path")
|
||||||
|
.example(
|
||||||
|
"--resume global/eli/accord/2002/5/5/MESS0221690X/jo/article_1/versions.xml",
|
||||||
|
)
|
||||||
|
.action(async (options) => {
|
||||||
|
await importJorf(options)
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.parse(process.argv)
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { auditChain, auditRequire, strictAudit } from "@auditors/core"
|
||||||
import assert from "assert"
|
import assert from "assert"
|
||||||
import { XMLParser } from "fast-xml-parser"
|
import { XMLParser } from "fast-xml-parser"
|
||||||
import fs from "fs-extra"
|
import fs from "fs-extra"
|
||||||
|
@ -6,22 +7,18 @@ import path from "path"
|
||||||
import type { JSONValue } from "postgres"
|
import type { JSONValue } from "postgres"
|
||||||
import sade from "sade"
|
import sade from "sade"
|
||||||
|
|
||||||
|
import { auditId, auditVersions } from "$lib/auditors/data"
|
||||||
import type {
|
import type {
|
||||||
Article,
|
Article,
|
||||||
EliId,
|
SectionTa,
|
||||||
EliVersions,
|
Textelr,
|
||||||
Section,
|
|
||||||
Struct,
|
|
||||||
TexteVersion,
|
TexteVersion,
|
||||||
|
Versions,
|
||||||
|
XmlHeader,
|
||||||
} from "$lib/data"
|
} from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
import { walkDir } from "$lib/server/file_systems"
|
import { walkDir } from "$lib/server/file_systems"
|
||||||
|
|
||||||
interface XmlHeader {
|
|
||||||
"@encoding": "UTF-8"
|
|
||||||
"@version": "1.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
const xmlParser = new XMLParser({
|
const xmlParser = new XMLParser({
|
||||||
attributeNamePrefix: "@",
|
attributeNamePrefix: "@",
|
||||||
ignoreAttributes: false,
|
ignoreAttributes: false,
|
||||||
|
@ -42,53 +39,57 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
let skip = resume !== undefined
|
let skip = resume !== undefined
|
||||||
const deleteRemainingIds = !skip
|
const deleteRemainingIds = !skip
|
||||||
|
|
||||||
const articlesRemainingIds = new Set(
|
const articleRemainingIds = new Set(
|
||||||
(
|
(
|
||||||
await db<{ id: string }[]>`
|
await db<{ id: string }[]>`
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM articles
|
FROM article
|
||||||
|
WHERE id LIKE 'LEGI%'
|
||||||
`
|
`
|
||||||
).map(({ id }) => id),
|
).map(({ id }) => id),
|
||||||
)
|
)
|
||||||
const eliIdsRemainingIds = new Set(
|
const idRemainingElis = new Set(
|
||||||
|
(
|
||||||
|
await db<{ eli: string }[]>`
|
||||||
|
SELECT eli
|
||||||
|
FROM id
|
||||||
|
`
|
||||||
|
).map(({ eli }) => eli),
|
||||||
|
)
|
||||||
|
const sectionTaRemainingIds = new Set(
|
||||||
(
|
(
|
||||||
await db<{ id: string }[]>`
|
await db<{ id: string }[]>`
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM eli_ids
|
FROM section_ta
|
||||||
|
WHERE id LIKE 'LEGI%'
|
||||||
`
|
`
|
||||||
).map(({ id }) => id),
|
).map(({ id }) => id),
|
||||||
)
|
)
|
||||||
const eliVersionsRemainingIds = new Set(
|
const textelrRemainingIds = new Set(
|
||||||
(
|
(
|
||||||
await db<{ id: string }[]>`
|
await db<{ id: string }[]>`
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM eli_versions
|
FROM textelr
|
||||||
|
WHERE id LIKE 'LEGI%'
|
||||||
`
|
`
|
||||||
).map(({ id }) => id),
|
).map(({ id }) => id),
|
||||||
)
|
)
|
||||||
const sectionsRemainingIds = new Set(
|
const texteVersionRemainingElis = new Set(
|
||||||
(
|
(
|
||||||
await db<{ id: string }[]>`
|
await db<{ id: string }[]>`
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM sections
|
FROM texte_version
|
||||||
|
WHERE id LIKE 'LEGI%'
|
||||||
`
|
`
|
||||||
).map(({ id }) => id),
|
).map(({ id }) => id),
|
||||||
)
|
)
|
||||||
const structsRemainingIds = new Set(
|
const versionsRemainingElis = new Set(
|
||||||
(
|
(
|
||||||
await db<{ id: string }[]>`
|
await db<{ eli: string }[]>`
|
||||||
SELECT id
|
SELECT eli
|
||||||
FROM structs
|
FROM versions
|
||||||
`
|
`
|
||||||
).map(({ id }) => id),
|
).map(({ eli }) => eli),
|
||||||
)
|
|
||||||
const textesRemainingIds = new Set(
|
|
||||||
(
|
|
||||||
await db<{ id: string }[]>`
|
|
||||||
SELECT id
|
|
||||||
FROM textes_versions
|
|
||||||
`
|
|
||||||
).map(({ id }) => id),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const dataDir = path.join("..", "dila-data", "legi")
|
const dataDir = path.join("..", "dila-data", "legi")
|
||||||
|
@ -109,32 +110,27 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
console.info(`Skipping non XML file at ${filePath}`)
|
console.info(`Skipping non XML file at ${filePath}`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
const xmlString: string = await fs.readFile(filePath, {
|
const xmlString: string = await fs.readFile(filePath, {
|
||||||
encoding: "utf8",
|
encoding: "utf8",
|
||||||
})
|
})
|
||||||
const xmlData = xmlParser.parse(xmlString)
|
const xmlData = xmlParser.parse(xmlString)
|
||||||
for (const [key, element] of Object.entries(xmlData) as [
|
for (const [key, element] of Object.entries(xmlData) as [
|
||||||
string,
|
string,
|
||||||
(
|
Article | SectionTa | Textelr | TexteVersion | Versions | XmlHeader,
|
||||||
| Article
|
|
||||||
| EliId
|
|
||||||
| EliVersions
|
|
||||||
| Section
|
|
||||||
| Struct
|
|
||||||
| TexteVersion
|
|
||||||
| XmlHeader
|
|
||||||
),
|
|
||||||
][]) {
|
][]) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "?xml":
|
case "?xml": {
|
||||||
const xmlHeader = element as XmlHeader
|
const xmlHeader = element as XmlHeader
|
||||||
assert.strictEqual(xmlHeader["@encoding"], "UTF-8", filePath)
|
assert.strictEqual(xmlHeader["@encoding"], "UTF-8", filePath)
|
||||||
assert.strictEqual(xmlHeader["@version"], "1.0", filePath)
|
assert.strictEqual(xmlHeader["@version"], "1.0", filePath)
|
||||||
break
|
break
|
||||||
|
}
|
||||||
case "ARTICLE": {
|
case "ARTICLE": {
|
||||||
const article = element as Article
|
const article = element as Article
|
||||||
await db`
|
await db`
|
||||||
INSERT INTO articles (
|
INSERT INTO article (
|
||||||
id,
|
id,
|
||||||
data
|
data
|
||||||
) VALUES (
|
) VALUES (
|
||||||
|
@ -145,33 +141,46 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
data = ${db.json(article as unknown as JSONValue)}
|
data = ${db.json(article as unknown as JSONValue)}
|
||||||
`
|
`
|
||||||
articlesRemainingIds.delete(article.META.META_COMMUN.ID)
|
articleRemainingIds.delete(article.META.META_COMMUN.ID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "ID": {
|
case "ID": {
|
||||||
assert.strictEqual(relativeSplitPath[0], "global")
|
assert.strictEqual(relativeSplitPath[0], "global")
|
||||||
assert.strictEqual(relativeSplitPath[1], "eli")
|
assert.strictEqual(relativeSplitPath[1], "eli")
|
||||||
const id = relativeSplitPath.slice(2, -1).join("/")
|
const eli = relativeSplitPath.slice(2, -1).join("/")
|
||||||
const eliId = element as EliId
|
const [id, idError] = auditChain(auditId, auditRequire)(
|
||||||
await db`
|
strictAudit,
|
||||||
INSERT INTO eli_ids (
|
element,
|
||||||
id,
|
|
||||||
data
|
|
||||||
) VALUES (
|
|
||||||
${id},
|
|
||||||
${db.json(eliId as unknown as JSONValue)}
|
|
||||||
)
|
)
|
||||||
ON CONFLICT (id)
|
assert.strictEqual(
|
||||||
|
idError,
|
||||||
|
null,
|
||||||
|
`Unexpected format for ID:\n${JSON.stringify(
|
||||||
|
id,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\nError:\n${JSON.stringify(idError, null, 2)}`,
|
||||||
|
)
|
||||||
|
assert
|
||||||
|
await db`
|
||||||
|
INSERT INTO id (
|
||||||
|
eli,
|
||||||
|
id
|
||||||
|
) VALUES (
|
||||||
|
${eli},
|
||||||
|
${id}
|
||||||
|
)
|
||||||
|
ON CONFLICT (eli)
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
data = ${db.json(eliId as unknown as JSONValue)}
|
id = ${id}
|
||||||
`
|
`
|
||||||
eliIdsRemainingIds.delete(id)
|
idRemainingElis.delete(eli)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "SECTION_TA": {
|
case "SECTION_TA": {
|
||||||
const section = element as Section
|
const section = element as SectionTa
|
||||||
await db`
|
await db`
|
||||||
INSERT INTO sections (
|
INSERT INTO section_ta (
|
||||||
id,
|
id,
|
||||||
data
|
data
|
||||||
) VALUES (
|
) VALUES (
|
||||||
|
@ -182,31 +191,13 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
data = ${db.json(section as unknown as JSONValue)}
|
data = ${db.json(section as unknown as JSONValue)}
|
||||||
`
|
`
|
||||||
sectionsRemainingIds.delete(section.ID)
|
sectionTaRemainingIds.delete(section.ID)
|
||||||
break
|
|
||||||
}
|
|
||||||
case "TEXTELR": {
|
|
||||||
const struct = element as Struct
|
|
||||||
await db`
|
|
||||||
INSERT INTO structs (
|
|
||||||
id,
|
|
||||||
data
|
|
||||||
) VALUES (
|
|
||||||
${struct.META.META_COMMUN.ID},
|
|
||||||
${db.json(struct as unknown as JSONValue)}
|
|
||||||
)
|
|
||||||
ON CONFLICT (id)
|
|
||||||
DO UPDATE SET
|
|
||||||
data = ${db.json(struct as unknown as JSONValue)}
|
|
||||||
`
|
|
||||||
structsRemainingIds.delete(struct.META.META_COMMUN.ID)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "TEXTE_VERSION": {
|
case "TEXTE_VERSION": {
|
||||||
const version = element as TexteVersion
|
const version = element as TexteVersion
|
||||||
console.log("TEXTE_VERSION:", version.META.META_COMMUN.ID)
|
|
||||||
await db`
|
await db`
|
||||||
INSERT INTO textes_versions (
|
INSERT INTO texte_version (
|
||||||
id,
|
id,
|
||||||
data
|
data
|
||||||
) VALUES (
|
) VALUES (
|
||||||
|
@ -217,27 +208,60 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
data = ${db.json(version as unknown as JSONValue)}
|
data = ${db.json(version as unknown as JSONValue)}
|
||||||
`
|
`
|
||||||
textesRemainingIds.delete(version.META.META_COMMUN.ID)
|
texteVersionRemainingElis.delete(version.META.META_COMMUN.ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "TEXTELR": {
|
||||||
|
const textelr = element as Textelr
|
||||||
|
await db`
|
||||||
|
INSERT INTO textelr (
|
||||||
|
id,
|
||||||
|
data
|
||||||
|
) VALUES (
|
||||||
|
${textelr.META.META_COMMUN.ID},
|
||||||
|
${db.json(textelr as unknown as JSONValue)}
|
||||||
|
)
|
||||||
|
ON CONFLICT (id)
|
||||||
|
DO UPDATE SET
|
||||||
|
data = ${db.json(textelr as unknown as JSONValue)}
|
||||||
|
`
|
||||||
|
textelrRemainingIds.delete(textelr.META.META_COMMUN.ID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "VERSIONS": {
|
case "VERSIONS": {
|
||||||
assert.strictEqual(relativeSplitPath[0], "global")
|
assert.strictEqual(relativeSplitPath[0], "global")
|
||||||
assert.strictEqual(relativeSplitPath[1], "eli")
|
assert.strictEqual(relativeSplitPath[1], "eli")
|
||||||
const id = relativeSplitPath.slice(2, -1).join("/")
|
const eli = relativeSplitPath.slice(2, -1).join("/")
|
||||||
const eliVersion = element as EliVersions
|
const [versions, versionsError] = auditChain(
|
||||||
|
auditVersions,
|
||||||
|
auditRequire,
|
||||||
|
)(strictAudit, element)
|
||||||
|
assert.strictEqual(
|
||||||
|
versionsError,
|
||||||
|
null,
|
||||||
|
`Unexpected format for VERSIONS:\n${JSON.stringify(
|
||||||
|
versions,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\nError:\n${JSON.stringify(versionsError, null, 2)}`,
|
||||||
|
)
|
||||||
|
const id = versions.VERSION["@id"]
|
||||||
await db`
|
await db`
|
||||||
INSERT INTO eli_versions (
|
INSERT INTO versions (
|
||||||
|
eli,
|
||||||
id,
|
id,
|
||||||
data
|
data
|
||||||
) VALUES (
|
) VALUES (
|
||||||
|
${eli},
|
||||||
${id},
|
${id},
|
||||||
${db.json(eliVersion as unknown as JSONValue)}
|
${db.json(versions as unknown as JSONValue)}
|
||||||
)
|
)
|
||||||
ON CONFLICT (id)
|
ON CONFLICT (eli)
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
data = ${db.json(eliVersion as unknown as JSONValue)}
|
id = ${id},
|
||||||
|
data = ${db.json(versions as unknown as JSONValue)}
|
||||||
`
|
`
|
||||||
eliVersionsRemainingIds.delete(id)
|
versionsRemainingElis.delete(id)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -248,51 +272,53 @@ async function importLegi({ resume }: { resume?: string } = {}): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(filePath)
|
} catch (e) {
|
||||||
// console.log(JSON.stringify(xmlData, null, 2))
|
console.error("An error occurred while parsing XML file", filePath)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteRemainingIds) {
|
if (deleteRemainingIds) {
|
||||||
for (const id of articlesRemainingIds) {
|
for (const id of articleRemainingIds) {
|
||||||
console.log(`Deleting article ${id}…`)
|
console.log(`Deleting ARTICLE ${id}…`)
|
||||||
await db`
|
await db`
|
||||||
DELETE FROM articles
|
DELETE FROM article
|
||||||
WHERE id = ${id}
|
WHERE id = ${id}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
for (const id of eliIdsRemainingIds) {
|
for (const eli of idRemainingElis) {
|
||||||
console.log(`Deleting ELI ID ${id}…`)
|
console.log(`Deleting ID ${eli}…`)
|
||||||
await db`
|
await db`
|
||||||
DELETE FROM eli_ids
|
DELETE FROM id
|
||||||
|
WHERE eli = ${eli}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
for (const id of sectionTaRemainingIds) {
|
||||||
|
console.log(`Deleting SECTION_TA ${id}…`)
|
||||||
|
await db`
|
||||||
|
DELETE FROM section_ta
|
||||||
WHERE id = ${id}
|
WHERE id = ${id}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
for (const id of eliVersionsRemainingIds) {
|
for (const id of textelrRemainingIds) {
|
||||||
console.log(`Deleting ELI versions ${id}…`)
|
console.log(`Deleting TEXTELR ${id}…`)
|
||||||
await db`
|
await db`
|
||||||
DELETE FROM eli_versions
|
DELETE FROM textelr
|
||||||
WHERE id = ${id}
|
WHERE id = ${id}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
for (const id of sectionsRemainingIds) {
|
for (const id of texteVersionRemainingElis) {
|
||||||
console.log(`Deleting section ${id}…`)
|
console.log(`Deleting TEXTE_VERSION ${id}…`)
|
||||||
await db`
|
await db`
|
||||||
DELETE FROM sections
|
DELETE FROM texte_version
|
||||||
WHERE id = ${id}
|
WHERE id = ${id}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
for (const id of structsRemainingIds) {
|
for (const eli of versionsRemainingElis) {
|
||||||
console.log(`Deleting struct ${id}…`)
|
console.log(`Deleting VERSIONS ${eli}…`)
|
||||||
await db`
|
await db`
|
||||||
DELETE FROM structs
|
DELETE FROM versions
|
||||||
WHERE id = ${id}
|
WHERE eli = ${eli}
|
||||||
`
|
|
||||||
}
|
|
||||||
for (const id of textesRemainingIds) {
|
|
||||||
console.log(`Deleting texte version ${id}…`)
|
|
||||||
await db`
|
|
||||||
DELETE FROM textes_versions
|
|
||||||
WHERE id = ${id}
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import assert from "assert"
|
import assert from "assert"
|
||||||
import dedent from "dedent-js"
|
|
||||||
|
|
||||||
import { db, type Version, versionNumber } from "$lib/server/database"
|
import { db, type Version, versionNumber } from "$lib/server/database"
|
||||||
|
|
||||||
|
@ -34,55 +33,72 @@ export async function configureDatabase() {
|
||||||
|
|
||||||
// Apply patches that must be executed before every table is created.
|
// Apply patches that must be executed before every table is created.
|
||||||
|
|
||||||
|
if (version.number < 2) {
|
||||||
|
await db`ALTER TABLE IF EXISTS articles RENAME TO article`
|
||||||
|
await db`DROP TABLE IF EXISTS eli_ids`
|
||||||
|
await db`DROP TABLE IF EXISTS eli_versions`
|
||||||
|
await db`ALTER TABLE IF EXISTS sections RENAME TO section_ta`
|
||||||
|
await db`ALTER TABLE IF EXISTS structs RENAME TO textelr`
|
||||||
|
await db`ALTER TABLE IF EXISTS textes RENAME TO texte_version`
|
||||||
|
}
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
// Tables
|
// Tables
|
||||||
|
|
||||||
// Table: articles
|
// Table: article
|
||||||
await db`
|
await db`
|
||||||
CREATE TABLE IF NOT EXISTS articles (
|
CREATE TABLE IF NOT EXISTS article (
|
||||||
id char(20) PRIMARY KEY,
|
id char(20) PRIMARY KEY,
|
||||||
data jsonb NOT NULL
|
data jsonb NOT NULL
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
// // Table: articles_autocompletions
|
// // Table: article_autocompletions
|
||||||
// await `
|
// await `
|
||||||
// CREATE TABLE IF NOT EXISTS articles_autocompletions (
|
// CREATE TABLE IF NOT EXISTS article_autocompletions (
|
||||||
// autocompletion text NOT NULL,
|
// autocompletion text NOT NULL,
|
||||||
// id bigint NOT NULL REFERENCES articles(id) ON DELETE CASCADE,
|
// id bigint NOT NULL REFERENCES article(id) ON DELETE CASCADE,
|
||||||
// weight int NOT NULL,
|
// weight int NOT NULL,
|
||||||
// PRIMARY KEY (id, autocompletion)
|
// PRIMARY KEY (id, autocompletion)
|
||||||
// )
|
// )
|
||||||
// `
|
// `
|
||||||
|
|
||||||
// Table: eli_ids
|
// Table: id
|
||||||
await db`
|
await db`
|
||||||
CREATE TABLE IF NOT EXISTS eli_ids (
|
CREATE TABLE IF NOT EXISTS id (
|
||||||
id text PRIMARY KEY,
|
eli text PRIMARY KEY,
|
||||||
data jsonb NOT NULL
|
id char(20) NOT NULL
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
// Table: eli_versions
|
// Table: jo
|
||||||
await db`
|
await db`
|
||||||
CREATE TABLE IF NOT EXISTS eli_versions (
|
CREATE TABLE IF NOT EXISTS jo (
|
||||||
id text PRIMARY KEY,
|
|
||||||
data jsonb NOT NULL
|
|
||||||
)
|
|
||||||
`
|
|
||||||
|
|
||||||
// Table: sections
|
|
||||||
await db`
|
|
||||||
CREATE TABLE IF NOT EXISTS sections (
|
|
||||||
id char(20) PRIMARY KEY,
|
id char(20) PRIMARY KEY,
|
||||||
data jsonb NOT NULL
|
data jsonb NOT NULL
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
|
||||||
// Table: structs
|
// Table: section_ta
|
||||||
await db`
|
await db`
|
||||||
CREATE TABLE IF NOT EXISTS structs (
|
CREATE TABLE IF NOT EXISTS section_ta (
|
||||||
|
id char(20) PRIMARY KEY,
|
||||||
|
data jsonb NOT NULL
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
// Table: texte_version
|
||||||
|
await db`
|
||||||
|
CREATE TABLE IF NOT EXISTS texte_version (
|
||||||
|
id char(20) PRIMARY KEY,
|
||||||
|
data jsonb NOT NULL
|
||||||
|
)
|
||||||
|
`
|
||||||
|
|
||||||
|
// Table: textelr
|
||||||
|
await db`
|
||||||
|
CREATE TABLE IF NOT EXISTS textelr (
|
||||||
id char(20) PRIMARY KEY,
|
id char(20) PRIMARY KEY,
|
||||||
data jsonb NOT NULL
|
data jsonb NOT NULL
|
||||||
)
|
)
|
||||||
|
@ -90,8 +106,9 @@ export async function configureDatabase() {
|
||||||
|
|
||||||
// Table: versions
|
// Table: versions
|
||||||
await db`
|
await db`
|
||||||
CREATE TABLE IF NOT EXISTS textes_versions (
|
CREATE TABLE IF NOT EXISTS versions (
|
||||||
id char(20) PRIMARY KEY,
|
eli text PRIMARY KEY,
|
||||||
|
id char(20) NOT NULL,
|
||||||
data jsonb NOT NULL
|
data jsonb NOT NULL
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
|
@ -101,8 +118,8 @@ export async function configureDatabase() {
|
||||||
// Add indexes once every table and column exists.
|
// Add indexes once every table and column exists.
|
||||||
|
|
||||||
// await db`
|
// await db`
|
||||||
// CREATE INDEX IF NOT EXISTS articles_autocompletions_trigrams_idx
|
// CREATE INDEX IF NOT EXISTS article_autocompletions_trigrams_idx
|
||||||
// ON articles_autocompletions
|
// ON article_autocompletions
|
||||||
// USING GIST (autocompletion gist_trgm_ops)
|
// USING GIST (autocompletion gist_trgm_ops)
|
||||||
// `
|
// `
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const db = postgres({
|
||||||
port: config.db.port,
|
port: config.db.port,
|
||||||
user: config.db.user,
|
user: config.db.user,
|
||||||
})
|
})
|
||||||
export const versionNumber = 1
|
export const versionNumber = 2
|
||||||
|
|
||||||
/// Check that database exists and is up to date.
|
/// Check that database exists and is up to date.
|
||||||
export async function checkDb(): Promise<void> {
|
export async function checkDb(): Promise<void> {
|
||||||
|
|
|
@ -1,35 +1,46 @@
|
||||||
|
import arrowRight from "@iconify-icons/codicon/arrow-small-right"
|
||||||
import type { Access, Summarizer, Summary } from "augmented-data-viewer"
|
import type { Access, Summarizer, Summary } from "augmented-data-viewer"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type Article,
|
type Article,
|
||||||
assertNeverLegiObjectType,
|
assertNeverLegalObjectType,
|
||||||
type LegiObject,
|
bestItemForDate,
|
||||||
type LegiObjectType,
|
type Jo,
|
||||||
pathnameFromLegiObject,
|
type LegalObject,
|
||||||
pathnameFromLegiObjectId,
|
type LegalObjectType,
|
||||||
type Section,
|
pathnameFromLegalObject,
|
||||||
type Struct,
|
pathnameFromLegalObjectId,
|
||||||
|
type SectionTa,
|
||||||
|
type Textelr,
|
||||||
type TexteVersion,
|
type TexteVersion,
|
||||||
|
type LienArt,
|
||||||
} from "$lib/data"
|
} from "$lib/data"
|
||||||
|
|
||||||
export const summarizeArticleProperties: Summarizer = (access, value) => {
|
export const summarizeArticleProperties: Summarizer = (access, value) => {
|
||||||
if (access?.key === "article") {
|
if (access?.key === "article" && typeof value !== "number") {
|
||||||
return summarizeLegiObject(access, "article", value)
|
return summarizeLegalObject(access, "article", value)
|
||||||
}
|
}
|
||||||
if (access?.access?.key === "articles") {
|
if (typeof access?.key === "number" && access?.access?.key === "article") {
|
||||||
return summarizeLegiObjectToLink(access, "article", value)
|
return summarizeLegalObjectToLink(access, "article", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access?.key === "@id" && access?.access?.key === "LIEN_ART") {
|
if (
|
||||||
return {
|
access?.key === "@id" &&
|
||||||
content: value as string,
|
(access?.access?.key === "LIEN_ART" ||
|
||||||
href: pathnameFromLegiObjectId("article", value as string),
|
(typeof access?.access?.key === "number" &&
|
||||||
type: "link",
|
access?.access?.access?.key === "LIEN_ART"))
|
||||||
}
|
) {
|
||||||
|
return summarizeLienArtId(access.access, access.parent)
|
||||||
}
|
}
|
||||||
if (access?.key === "CONTENU") {
|
if (access?.key === "CONTENU") {
|
||||||
return { content: value as string, type: "html" }
|
return { content: value as string, type: "html" }
|
||||||
}
|
}
|
||||||
|
if (access?.key === "LIEN_ART" && !Array.isArray(value)) {
|
||||||
|
return summarizeLienArt(access, value)
|
||||||
|
}
|
||||||
|
if (typeof access?.key === "number" && access?.access?.key === "LIEN_ART") {
|
||||||
|
return summarizeLienArt(access, value)
|
||||||
|
}
|
||||||
if (access?.access?.key === "VERSION") {
|
if (access?.access?.key === "VERSION") {
|
||||||
const version = value as Article["VERSIONS"]["VERSION"][0]
|
const version = value as Article["VERSIONS"]["VERSION"][0]
|
||||||
const lienArt = version.LIEN_ART
|
const lienArt = version.LIEN_ART
|
||||||
|
@ -60,16 +71,27 @@ export const summarizeArticleProperties: Summarizer = (access, value) => {
|
||||||
],
|
],
|
||||||
type: "concatenation",
|
type: "concatenation",
|
||||||
},
|
},
|
||||||
href: pathnameFromLegiObjectId("article", lienArt["@id"]),
|
href: pathnameFromLegalObjectId("article", lienArt["@id"]),
|
||||||
type: "link",
|
type: "link",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function summarizeLegiObject(
|
export const summarizeJoProperties: Summarizer = (access, value) => {
|
||||||
|
if (access?.key === "jo" && typeof value !== "number") {
|
||||||
|
return summarizeLegalObject(access, "jo", value)
|
||||||
|
}
|
||||||
|
if (typeof access?.key === "number" && access?.access?.key === "jo") {
|
||||||
|
return summarizeLegalObjectToLink(access, "jo", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export function summarizeLegalObject(
|
||||||
access: Access | undefined,
|
access: Access | undefined,
|
||||||
type: LegiObjectType,
|
type: LegalObjectType,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
): Summary | undefined {
|
): Summary | undefined {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -113,70 +135,127 @@ export function summarizeLegiObject(
|
||||||
type: "concatenation",
|
type: "concatenation",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "eli_id":
|
case "id":
|
||||||
return `/eli/ids/TODO`
|
return `/eli/ids/TODO`
|
||||||
case "eli_versions":
|
case "jo": {
|
||||||
return `/eli/ids/TODO`
|
const jo = value as Jo | undefined
|
||||||
case "section": {
|
return jo?.META.META_SPEC.META_CONTENEUR.TITRE
|
||||||
const section = value as Section | undefined
|
|
||||||
return section?.ID
|
|
||||||
}
|
}
|
||||||
case "struct": {
|
case "section_ta": {
|
||||||
const struct = value as Struct | undefined
|
const sectionTa = value as SectionTa | undefined
|
||||||
return struct?.META.META_COMMUN.ID
|
if (sectionTa === undefined) {
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
case "texte": {
|
const today = new Date().toISOString().split("T")[0]
|
||||||
const texte = value as TexteVersion | undefined
|
return `${sectionTa.TITRE_TA} — ${
|
||||||
return texte?.META.META_COMMUN.ID
|
bestItemForDate(sectionTa.CONTEXTE.TEXTE.TITRE_TXT, today)?.["#text"]
|
||||||
|
}`
|
||||||
}
|
}
|
||||||
|
case "texte_version": {
|
||||||
|
const texteVersion = value as TexteVersion | undefined
|
||||||
|
return texteVersion?.META.META_SPEC.META_TEXTE_VERSION.TITREFULL
|
||||||
|
}
|
||||||
|
case "textelr": {
|
||||||
|
const textelr = value as Textelr | undefined
|
||||||
|
return textelr?.META.META_COMMUN.ID
|
||||||
|
}
|
||||||
|
case "versions":
|
||||||
|
return `/eli/versions/TODO`
|
||||||
default:
|
default:
|
||||||
assertNeverLegiObjectType(type)
|
assertNeverLegalObjectType(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function summarizeLegiObjectToLink(
|
export function summarizeLegalObjectToLink(
|
||||||
access: Access | undefined,
|
access: Access | undefined,
|
||||||
type: LegiObjectType,
|
type: LegalObjectType,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
): Summary | undefined {
|
): Summary | undefined {
|
||||||
const objectSummary = summarizeLegiObject(access, type, value)
|
const objectSummary = summarizeLegalObject(access, type, value)
|
||||||
return objectSummary === undefined
|
return objectSummary === undefined
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
content: objectSummary,
|
content: objectSummary,
|
||||||
href: pathnameFromLegiObject(type, value as LegiObject),
|
href: pathnameFromLegalObject(type, value as LegalObject),
|
||||||
type: "link",
|
type: "link",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const summarizeSectionProperties: Summarizer = (access, value) => {
|
export const summarizeLienArt: Summarizer = (access, value) => {
|
||||||
if (access?.key === "section") {
|
const lienArt = value as LienArt | undefined
|
||||||
return summarizeLegiObject(access, "section", value)
|
if (lienArt === undefined) {
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
if (access?.access?.key === "sections") {
|
return {
|
||||||
return summarizeLegiObjectToLink(access, "section", value)
|
content: `Article n° ${lienArt["@num"]}`,
|
||||||
|
href: pathnameFromLegalObjectId("article", lienArt["@id"]),
|
||||||
|
type: "link",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const summarizeLienArtId: Summarizer = (access, value) => {
|
||||||
|
const lienArt = value as LienArt | undefined
|
||||||
|
if (lienArt === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
content: JSON.stringify(lienArt["@id"]),
|
||||||
|
type: "raw_data",
|
||||||
|
},
|
||||||
|
{ class: "mx-1", icon: arrowRight, inline: true, type: "icon" },
|
||||||
|
summarizeLienArt(access, lienArt)!,
|
||||||
|
],
|
||||||
|
type: "concatenation",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const summarizeSectionTaProperties: Summarizer = (access, value) => {
|
||||||
|
if (access?.key === "section_ta" && typeof value !== "number") {
|
||||||
|
return summarizeLegalObject(access, "section_ta", value)
|
||||||
|
}
|
||||||
|
if (typeof access?.key === "number" && access?.access?.key === "section_ta") {
|
||||||
|
return summarizeLegalObjectToLink(access, "section_ta", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
access?.key === "@id" &&
|
||||||
|
(access?.access?.key === "LIEN_ART" ||
|
||||||
|
(typeof access?.access?.key === "number" &&
|
||||||
|
access?.access?.access?.key === "LIEN_ART"))
|
||||||
|
) {
|
||||||
|
return summarizeLienArtId(access.access, access.parent)
|
||||||
|
}
|
||||||
|
if (access?.key === "LIEN_ART" && !Array.isArray(value)) {
|
||||||
|
return summarizeLienArt(access, value)
|
||||||
|
}
|
||||||
|
if (typeof access?.key === "number" && access?.access?.key === "LIEN_ART") {
|
||||||
|
return summarizeLienArt(access, value)
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export const summarizeTextelrProperties: Summarizer = (access, value) => {
|
||||||
|
if (access?.key === "textelr" && typeof value !== "number") {
|
||||||
|
return summarizeLegalObject(access, "textelr", value)
|
||||||
|
}
|
||||||
|
if (typeof access?.key === "number" && access?.access?.key === "textelr") {
|
||||||
|
return summarizeLegalObjectToLink(access, "textelr", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export const summarizeStructProperties: Summarizer = (access, value) => {
|
export const summarizeTexteVersionProperties: Summarizer = (access, value) => {
|
||||||
if (access?.key === "struct") {
|
if (access?.key === "texte_version" && typeof value !== "number") {
|
||||||
return summarizeLegiObject(access, "struct", value)
|
return summarizeLegalObject(access, "texte_version", value)
|
||||||
}
|
}
|
||||||
if (access?.access?.key === "structs") {
|
if (
|
||||||
return summarizeLegiObjectToLink(access, "struct", value)
|
typeof access?.key === "number" &&
|
||||||
}
|
access?.access?.key === "texte_version"
|
||||||
|
) {
|
||||||
return undefined
|
return summarizeLegalObjectToLink(access, "texte_version", value)
|
||||||
}
|
|
||||||
|
|
||||||
export const summarizeTexteProperties: Summarizer = (access, value) => {
|
|
||||||
if (access?.key === "texte") {
|
|
||||||
return summarizeLegiObject(access, "texte", value)
|
|
||||||
}
|
|
||||||
if (access?.access?.key === "textes") {
|
|
||||||
return summarizeLegiObjectToLink(access, "texte", value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
href?: string
|
href?: string
|
||||||
items?: MenuItemLink[]
|
items?: MenuItemLink[]
|
||||||
label: string
|
label: string
|
||||||
|
title?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MenuItemLink extends MenuItemBase {
|
interface MenuItemLink extends MenuItemBase {
|
||||||
|
@ -27,16 +28,36 @@
|
||||||
const menuItems: MenuItem[] = [
|
const menuItems: MenuItem[] = [
|
||||||
{ href: "/recherche", label: "Recherche" },
|
{ href: "/recherche", label: "Recherche" },
|
||||||
{
|
{
|
||||||
label: "Données",
|
|
||||||
items: [
|
items: [
|
||||||
{ href: "/articles", label: "Articles" },
|
{ href: "/article", label: "ARTICLE" },
|
||||||
{ href: "/eli/ids", label: "ELI ID" },
|
// { href: "/eli/ids", label: "ID" },
|
||||||
{ href: "/eli/versions", label: "ELI versions" },
|
{ href: "/jo", label: "JO" },
|
||||||
{ href: "/sections", label: "Sections" },
|
{ href: "/section_ta", label: "SECTION_TA" },
|
||||||
{ href: "/structs", label: "Structures" },
|
{ href: "/texte_version", label: "TEXTE_VERSION" },
|
||||||
{ href: "/textes", label: "Textes" },
|
{ href: "/textelr", label: "TEXTELR" },
|
||||||
|
// { href: "/eli/versions", label: "VERSIONS" },
|
||||||
],
|
],
|
||||||
|
label: "Données",
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// items: [
|
||||||
|
// { href: "/jo", label: "JO" },
|
||||||
|
// ],
|
||||||
|
// label: "JORF",
|
||||||
|
// title: "Textes publiés au Journal officiel de la République française",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// items: [
|
||||||
|
// { href: "/article", label: "ARTICLE" },
|
||||||
|
// // { href: "/eli/ids", label: "ID" },
|
||||||
|
// { href: "/section_ta", label: "SECTION_TA" },
|
||||||
|
// { href: "/texte_version", label: "TEXTE_VERSION" },
|
||||||
|
// { href: "/textelr", label: "TEXTELR" },
|
||||||
|
// // { href: "/eli/versions", label: "VERSIONS" },
|
||||||
|
// ],
|
||||||
|
// label: "LEGI",
|
||||||
|
// title: "Codes, lois et règlements consolidés",
|
||||||
|
// },
|
||||||
]
|
]
|
||||||
const title = $session.title
|
const title = $session.title
|
||||||
</script>
|
</script>
|
||||||
|
@ -51,18 +72,18 @@
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="dropdown-content menu rounded-box menu-compact mt-3 w-52 bg-neutral p-2 text-neutral-content shadow"
|
class="dropdown-content menu rounded-box menu-compact mt-3 w-52 bg-neutral p-2 text-neutral-content shadow"
|
||||||
>
|
>
|
||||||
{#each menuItems as { href, items, label }}
|
{#each menuItems as { href, items, label, title }}
|
||||||
{#if href !== undefined}
|
{#if href !== undefined}
|
||||||
<li><a {href}>{label}</a></li>
|
<li><a {href} {title}>{label}</a></li>
|
||||||
{:else if items !== undefined}
|
{:else if items !== undefined}
|
||||||
<li tabindex="0">
|
<li tabindex="0">
|
||||||
<span class="justify-between">
|
<span class="justify-between" {title}>
|
||||||
{label}
|
{label}
|
||||||
<Icon class="h-5 w-5" icon={chevronRight} />
|
<Icon class="h-5 w-5" icon={chevronRight} />
|
||||||
</span>
|
</span>
|
||||||
<ul class="p-2 bg-neutral text-neutral-content">
|
<ul class="p-2 bg-neutral text-neutral-content">
|
||||||
{#each items as { href, label }}
|
{#each items as { href, label }}
|
||||||
<li><a {href}>{label}</a></li>
|
<li><a {href} {title}>{label}</a></li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
@ -74,18 +95,18 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-center hidden lg:flex">
|
<div class="navbar-center hidden lg:flex">
|
||||||
<ul class="menu menu-horizontal p-0">
|
<ul class="menu menu-horizontal p-0">
|
||||||
{#each menuItems as { href, items, label }}
|
{#each menuItems as { href, items, label, title }}
|
||||||
{#if href !== undefined}
|
{#if href !== undefined}
|
||||||
<li><a {href}>{label}</a></li>
|
<li><a {href} {title}>{label}</a></li>
|
||||||
{:else if items !== undefined}
|
{:else if items !== undefined}
|
||||||
<li tabindex="0">
|
<li tabindex="0">
|
||||||
<span class="justify-between">
|
<span class="justify-between" {title}>
|
||||||
{label}
|
{label}
|
||||||
<Icon class="h-5 w-5" icon={chevronDown} />
|
<Icon class="h-5 w-5" icon={chevronDown} />
|
||||||
</span>
|
</span>
|
||||||
<ul class="p-2 bg-neutral text-neutral-content">
|
<ul class="p-2 bg-neutral text-neutral-content">
|
||||||
{#each items as { href, label }}
|
{#each items as { href, label }}
|
||||||
<li><a {href}>{label}</a></li>
|
<li><a {href} {title}>{label}</a></li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
import type { Article } from "$lib/data"
|
import type { Article } from "$lib/data"
|
||||||
import {
|
import {
|
||||||
summarizeArticleProperties,
|
summarizeArticleProperties,
|
||||||
summarizeLegiObject,
|
summarizeLegalObject,
|
||||||
} from "$lib/summaries"
|
} from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let article: Article
|
export let article: Article
|
||||||
|
|
||||||
const summary = summarizeLegiObject({ key: "article" }, "article", article)
|
const summary = summarizeLegalObject({ key: "article" }, "article", article)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
|
@ -4,10 +4,10 @@ import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
import type { Article } from "$lib/data"
|
import type { Article } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ params, url }) => {
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
const article = (
|
const article = (
|
||||||
await db<{ data: Article }[]>`
|
await db<{ data: Article }[]>`
|
||||||
SELECT data FROM articles
|
SELECT data FROM article
|
||||||
WHERE id = ${params.id}
|
WHERE id = ${params.id}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
|
@ -6,10 +6,12 @@
|
||||||
// import { page } from "$app/stores"
|
// import { page } from "$app/stores"
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import Pagination from "$lib/components/Pagination.svelte"
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
|
import type { Article } from "$lib/data"
|
||||||
import { summarizeArticleProperties } from "$lib/summaries"
|
import { summarizeArticleProperties } from "$lib/summaries"
|
||||||
|
|
||||||
|
let articles: Article[]
|
||||||
|
export { articles as article }
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let articles: unknown[]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "articles" }}
|
access={{ key: "article" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeArticleProperties}
|
summarize={summarizeArticleProperties}
|
|
@ -60,13 +60,13 @@ export const GET: RequestHandler = async ({ url }) => {
|
||||||
|
|
||||||
const articles = (
|
const articles = (
|
||||||
await db<{ data: Article }[]>`
|
await db<{ data: Article }[]>`
|
||||||
SELECT data FROM articles
|
SELECT data FROM article
|
||||||
OFFSET ${offset}
|
OFFSET ${offset}
|
||||||
LIMIT ${limit}
|
LIMIT ${limit}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)
|
).map(({ data }) => data)
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { articles: articles as unknown as JSONObject[] },
|
body: { article: articles as unknown as JSONObject[] },
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,17 +2,17 @@
|
||||||
import { TreeView, SummaryView } from "augmented-data-viewer"
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import type { TexteVersion } from "$lib/data"
|
import type { Jo } from "$lib/data"
|
||||||
import { summarizeTexteProperties, summarizeLegiObject } from "$lib/summaries"
|
import { summarizeJoProperties, summarizeLegalObject } from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let texte: TexteVersion
|
export let jo: Jo
|
||||||
|
|
||||||
const summary = summarizeLegiObject({ key: "texte" }, "texte", texte)
|
const summary = summarizeLegalObject({ key: "jo" }, "jo", jo)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h2>Texte</h2>
|
<h2>JO</h2>
|
||||||
{#if summary !== undefined}
|
{#if summary !== undefined}
|
||||||
<h1>
|
<h1>
|
||||||
<SummaryView {summary} />
|
<SummaryView {summary} />
|
||||||
|
@ -26,10 +26,10 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "texte" }}
|
access={{ key: "jo" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeTexteProperties}
|
summarize={summarizeJoProperties}
|
||||||
value={texte}
|
value={jo}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
|
@ -1,22 +1,22 @@
|
||||||
import type { RequestHandler } from "@sveltejs/kit"
|
import type { RequestHandler } from "@sveltejs/kit"
|
||||||
import type { JSONObject } from "@sveltejs/kit/types/private"
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
import type { Struct } from "$lib/data"
|
import type { Jo } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ params, url }) => {
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
const struct = (
|
const jo = (
|
||||||
await db<{ data: Struct }[]>`
|
await db<{ data: Jo }[]>`
|
||||||
SELECT data FROM structs
|
SELECT data FROM jo
|
||||||
WHERE id = ${params.id}
|
WHERE id = ${params.id}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (struct === undefined) {
|
if (jo === undefined) {
|
||||||
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { struct: struct as unknown as JSONObject },
|
body: { jo: jo as unknown as JSONObject },
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,14 +6,16 @@
|
||||||
// import { page } from "$app/stores"
|
// import { page } from "$app/stores"
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import Pagination from "$lib/components/Pagination.svelte"
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
import { summarizeStructProperties } from "$lib/summaries"
|
import type { Jo } from "$lib/data"
|
||||||
|
import { summarizeJoProperties } from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let structs: unknown[]
|
let jos: Jo[]
|
||||||
|
export { jos as jo }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h1>Structures</h1>
|
<h1>JO</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
||||||
|
@ -39,7 +41,7 @@
|
||||||
bind:value={legislature}
|
bind:value={legislature}
|
||||||
>
|
>
|
||||||
<option value="">Toutes</option>
|
<option value="">Toutes</option>
|
||||||
{#each Object.entries(Legislature) as [key, value]}
|
{#each Object.entries(Jorfslature) as [key, value]}
|
||||||
{#if value !== "*"}
|
{#if value !== "*"}
|
||||||
<option {value}>{key}</option>
|
<option {value}>{key}</option>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -55,12 +57,12 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "structs" }}
|
access={{ key: "jo" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeStructProperties}
|
summarize={summarizeJoProperties}
|
||||||
value={structs}
|
value={jos}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Pagination currentPageCount={structs.length ?? 0} />
|
<Pagination currentPageCount={jos.length ?? 0} />
|
||||||
{/if}
|
{/if}
|
|
@ -3,7 +3,7 @@ import type { RequestHandler } from "@sveltejs/kit"
|
||||||
import type { JSONObject } from "@sveltejs/kit/types/private"
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
import { auditSearchQueryContent } from "$lib/auditors/queries"
|
import { auditSearchQueryContent } from "$lib/auditors/queries"
|
||||||
import type { Struct } from "$lib/data"
|
import type { Jo } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export function auditQuery(
|
export function auditQuery(
|
||||||
|
@ -58,15 +58,15 @@ export const GET: RequestHandler = async ({ url }) => {
|
||||||
}
|
}
|
||||||
const { limit, offset } = query
|
const { limit, offset } = query
|
||||||
|
|
||||||
const structs = (
|
const jos = (
|
||||||
await db<{ data: Struct }[]>`
|
await db<{ data: Jo }[]>`
|
||||||
SELECT data FROM structs
|
SELECT data FROM jo
|
||||||
OFFSET ${offset}
|
OFFSET ${offset}
|
||||||
LIMIT ${limit}
|
LIMIT ${limit}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)
|
).map(({ data }) => data)
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { structs: structs as unknown as JSONObject[] },
|
body: { jo: jos as unknown as JSONObject[] },
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,20 +2,25 @@
|
||||||
import { TreeView, SummaryView } from "augmented-data-viewer"
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import type { Section } from "$lib/data"
|
import type { SectionTa } from "$lib/data"
|
||||||
import {
|
import {
|
||||||
summarizeSectionProperties,
|
summarizeSectionTaProperties,
|
||||||
summarizeLegiObject,
|
summarizeLegalObject,
|
||||||
} from "$lib/summaries"
|
} from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let section: Section
|
let sectionTa: SectionTa
|
||||||
|
export { sectionTa as section_ta }
|
||||||
|
|
||||||
const summary = summarizeLegiObject({ key: "section" }, "section", section)
|
const summary = summarizeLegalObject(
|
||||||
|
{ key: "section_ta" },
|
||||||
|
"section_ta",
|
||||||
|
sectionTa,
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h2>Section</h2>
|
<h2>SECTION_TA</h2>
|
||||||
{#if summary !== undefined}
|
{#if summary !== undefined}
|
||||||
<h1>
|
<h1>
|
||||||
<SummaryView {summary} />
|
<SummaryView {summary} />
|
||||||
|
@ -29,10 +34,10 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "section" }}
|
access={{ key: "section_ta" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeSectionProperties}
|
summarize={summarizeSectionTaProperties}
|
||||||
value={section}
|
value={sectionTa}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
22
src/routes/section_ta/[id].ts
Normal file
22
src/routes/section_ta/[id].ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import type { RequestHandler } from "@sveltejs/kit"
|
||||||
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
|
import type { SectionTa } from "$lib/data"
|
||||||
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
|
const sectionTa = (
|
||||||
|
await db<{ data: SectionTa }[]>`
|
||||||
|
SELECT data FROM section_ta
|
||||||
|
WHERE id = ${params.id}
|
||||||
|
`
|
||||||
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
|
if (sectionTa === undefined) {
|
||||||
|
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
|
body: { section_ta: sectionTa as unknown as JSONObject },
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,14 +6,16 @@
|
||||||
// import { page } from "$app/stores"
|
// import { page } from "$app/stores"
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import Pagination from "$lib/components/Pagination.svelte"
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
import { summarizeTexteProperties } from "$lib/summaries"
|
import type { SectionTa } from "$lib/data"
|
||||||
|
import { summarizeSectionTaProperties } from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let textes: unknown[]
|
let sectionTaArray: SectionTa[]
|
||||||
|
export { sectionTaArray as section_ta }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h1>Textes</h1>
|
<h1>SECTION_TA</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
||||||
|
@ -55,12 +57,12 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "textes" }}
|
access={{ key: "section_ta" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeTexteProperties}
|
summarize={summarizeSectionTaProperties}
|
||||||
value={textes}
|
value={sectionTaArray}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Pagination currentPageCount={textes.length ?? 0} />
|
<Pagination currentPageCount={sectionTaArray.length ?? 0} />
|
||||||
{/if}
|
{/if}
|
72
src/routes/section_ta/index.ts
Normal file
72
src/routes/section_ta/index.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
|
||||||
|
import type { RequestHandler } from "@sveltejs/kit"
|
||||||
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
|
import { auditSearchQueryContent } from "$lib/auditors/queries"
|
||||||
|
import type { SectionTa } from "$lib/data"
|
||||||
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
|
export function auditQuery(
|
||||||
|
audit: Audit,
|
||||||
|
query: URLSearchParams,
|
||||||
|
): [unknown, unknown] {
|
||||||
|
if (query == null) {
|
||||||
|
return [query, null]
|
||||||
|
}
|
||||||
|
if (!(query instanceof URLSearchParams)) {
|
||||||
|
return audit.unexpectedType(query, "URLSearchParams")
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: { [key: string]: unknown } = {}
|
||||||
|
for (const [key, value] of query.entries()) {
|
||||||
|
let values = data[key] as string[] | undefined
|
||||||
|
if (values === undefined) {
|
||||||
|
values = data[key] = []
|
||||||
|
}
|
||||||
|
values.push(value)
|
||||||
|
}
|
||||||
|
const errors: { [key: string]: unknown } = {}
|
||||||
|
const remainingKeys = new Set(Object.keys(data))
|
||||||
|
|
||||||
|
auditSearchQueryContent(audit, data, errors, remainingKeys)
|
||||||
|
|
||||||
|
return audit.reduceRemaining(data, errors, remainingKeys, auditSetNullish({}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({ url }) => {
|
||||||
|
const [query, queryError] = auditQuery(cleanAudit, url.searchParams) as [
|
||||||
|
{ limit: number; offset: number; q?: string },
|
||||||
|
unknown,
|
||||||
|
]
|
||||||
|
if (queryError !== null) {
|
||||||
|
console.error(
|
||||||
|
`Error in ${url.pathname} query:\n${JSON.stringify(
|
||||||
|
query,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}\n\nError:\n${JSON.stringify(queryError, null, 2)}`,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
// status: 400,
|
||||||
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
|
body: {
|
||||||
|
error: {
|
||||||
|
query: queryError as unknown as JSONObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { limit, offset } = query
|
||||||
|
|
||||||
|
const sectionTaArray = (
|
||||||
|
await db<{ data: SectionTa }[]>`
|
||||||
|
SELECT data FROM section_ta
|
||||||
|
OFFSET ${offset}
|
||||||
|
LIMIT ${limit}
|
||||||
|
`
|
||||||
|
).map(({ data }) => data)
|
||||||
|
return {
|
||||||
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
|
body: { section_ta: sectionTaArray as unknown as JSONObject[] },
|
||||||
|
}
|
||||||
|
}
|
43
src/routes/texte_version/[id].svelte
Normal file
43
src/routes/texte_version/[id].svelte
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
|
import type { TexteVersion } from "$lib/data"
|
||||||
|
import {
|
||||||
|
summarizeTexteVersionProperties,
|
||||||
|
summarizeLegalObject,
|
||||||
|
} from "$lib/summaries"
|
||||||
|
|
||||||
|
export let error: unknown
|
||||||
|
let texteVersion: TexteVersion
|
||||||
|
export { texteVersion as texte_version }
|
||||||
|
|
||||||
|
const summary = summarizeLegalObject(
|
||||||
|
{ key: "texte_version" },
|
||||||
|
"texte_version",
|
||||||
|
texteVersion,
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="prose my-6 max-w-full">
|
||||||
|
<h2>TEXTE_VERSION</h2>
|
||||||
|
{#if summary !== undefined}
|
||||||
|
<h1>
|
||||||
|
<SummaryView {summary} />
|
||||||
|
</h1>
|
||||||
|
{/if}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{#if error != null}
|
||||||
|
<ErrorAlert {error} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if error == null}
|
||||||
|
<TreeView
|
||||||
|
access={{ key: "texte_version" }}
|
||||||
|
frame={false}
|
||||||
|
open
|
||||||
|
summarize={summarizeTexteVersionProperties}
|
||||||
|
value={texteVersion}
|
||||||
|
/>
|
||||||
|
{/if}
|
|
@ -4,19 +4,19 @@ import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
import type { TexteVersion } from "$lib/data"
|
import type { TexteVersion } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ params, url }) => {
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
const texte = (
|
const texteVersion = (
|
||||||
await db<{ data: TexteVersion }[]>`
|
await db<{ data: TexteVersion }[]>`
|
||||||
SELECT data FROM textes_versions
|
SELECT data FROM texte_version
|
||||||
WHERE id = ${params.id}
|
WHERE id = ${params.id}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (texte === undefined) {
|
if (texteVersion === undefined) {
|
||||||
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { texte: texte as unknown as JSONObject },
|
body: { texte_version: texteVersion as unknown as JSONObject },
|
||||||
}
|
}
|
||||||
}
|
}
|
68
src/routes/texte_version/index.svelte
Normal file
68
src/routes/texte_version/index.svelte
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<script lang="ts">
|
||||||
|
// import Icon from "@iconify/svelte"
|
||||||
|
// import searchIcon from "@iconify-icons/codicon/search"
|
||||||
|
import { TreeView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
// import { page } from "$app/stores"
|
||||||
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
|
import type { TexteVersion } from "$lib/data"
|
||||||
|
import { summarizeTexteVersionProperties } from "$lib/summaries"
|
||||||
|
|
||||||
|
export let error: unknown
|
||||||
|
let texteVersionArray: TexteVersion[]
|
||||||
|
export { texteVersionArray as texte_version }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="prose my-6 max-w-full">
|
||||||
|
<h1>TEXTE_VERSION</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
||||||
|
<div class="form-control">
|
||||||
|
<div class="input-group">
|
||||||
|
<input
|
||||||
|
class="input input-bordered"
|
||||||
|
name="q"
|
||||||
|
type="search"
|
||||||
|
bind:value={q}
|
||||||
|
/>
|
||||||
|
<button class="btn btn-square" type="submit">
|
||||||
|
<Icon icon={searchIcon} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Législature</span>
|
||||||
|
<select
|
||||||
|
class="select select-bordered"
|
||||||
|
name="legislature"
|
||||||
|
bind:value={legislature}
|
||||||
|
>
|
||||||
|
<option value="">Toutes</option>
|
||||||
|
{#each Object.entries(Legislature) as [key, value]}
|
||||||
|
{#if value !== "*"}
|
||||||
|
<option {value}>{key}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form> -->
|
||||||
|
|
||||||
|
{#if error != null}
|
||||||
|
<ErrorAlert {error} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if error == null}
|
||||||
|
<TreeView
|
||||||
|
access={{ key: "texte_version" }}
|
||||||
|
frame={false}
|
||||||
|
open
|
||||||
|
summarize={summarizeTexteVersionProperties}
|
||||||
|
value={texteVersionArray}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Pagination currentPageCount={texteVersionArray.length ?? 0} />
|
||||||
|
{/if}
|
|
@ -58,15 +58,15 @@ export const GET: RequestHandler = async ({ url }) => {
|
||||||
}
|
}
|
||||||
const { limit, offset } = query
|
const { limit, offset } = query
|
||||||
|
|
||||||
const textes = (
|
const texteVersionArray = (
|
||||||
await db<{ data: TexteVersion }[]>`
|
await db<{ data: TexteVersion }[]>`
|
||||||
SELECT data FROM textes_versions
|
SELECT data FROM texte_version
|
||||||
OFFSET ${offset}
|
OFFSET ${offset}
|
||||||
LIMIT ${limit}
|
LIMIT ${limit}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)
|
).map(({ data }) => data)
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { textes: textes as unknown as JSONObject[] },
|
body: { texte_version: texteVersionArray as unknown as JSONObject[] },
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,20 +2,20 @@
|
||||||
import { TreeView, SummaryView } from "augmented-data-viewer"
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import type { Struct } from "$lib/data"
|
import type { Textelr } from "$lib/data"
|
||||||
import {
|
import {
|
||||||
summarizeStructProperties,
|
summarizeTextelrProperties,
|
||||||
summarizeLegiObject,
|
summarizeLegalObject,
|
||||||
} from "$lib/summaries"
|
} from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let struct: Struct
|
export let textelr: Textelr
|
||||||
|
|
||||||
const summary = summarizeLegiObject({ key: "struct" }, "struct", struct)
|
const summary = summarizeLegalObject({ key: "textelr" }, "textelr", textelr)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h2>Structure</h2>
|
<h2>TEXTELR</h2>
|
||||||
{#if summary !== undefined}
|
{#if summary !== undefined}
|
||||||
<h1>
|
<h1>
|
||||||
<SummaryView {summary} />
|
<SummaryView {summary} />
|
||||||
|
@ -29,10 +29,10 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "struct" }}
|
access={{ key: "textelr" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeStructProperties}
|
summarize={summarizeTextelrProperties}
|
||||||
value={struct}
|
value={textelr}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
|
@ -1,22 +1,22 @@
|
||||||
import type { RequestHandler } from "@sveltejs/kit"
|
import type { RequestHandler } from "@sveltejs/kit"
|
||||||
import type { JSONObject } from "@sveltejs/kit/types/private"
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
import type { Section } from "$lib/data"
|
import type { Textelr } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ params, url }) => {
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
const section = (
|
const textelr = (
|
||||||
await db<{ data: Section }[]>`
|
await db<{ data: Textelr }[]>`
|
||||||
SELECT data FROM sections
|
SELECT data FROM textelr
|
||||||
WHERE id = ${params.id}
|
WHERE id = ${params.id}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (section === undefined) {
|
if (textelr === undefined) {
|
||||||
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
return { headers: { "Access-Control-Allow-Origin": "*" }, status: 404 }
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { section: section as unknown as JSONObject },
|
body: { textelr: textelr as unknown as JSONObject },
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,14 +6,16 @@
|
||||||
// import { page } from "$app/stores"
|
// import { page } from "$app/stores"
|
||||||
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
import ErrorAlert from "$lib/components/errors/ErrorAlert.svelte"
|
||||||
import Pagination from "$lib/components/Pagination.svelte"
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
import { summarizeSectionProperties } from "$lib/summaries"
|
import type { Textelr } from "$lib/data"
|
||||||
|
import { summarizeTextelrProperties } from "$lib/summaries"
|
||||||
|
|
||||||
export let error: unknown
|
export let error: unknown
|
||||||
export let sections: unknown[]
|
let textelrArray: Textelr[]
|
||||||
|
export { textelrArray as textelr }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h1>Sections</h1>
|
<h1>TEXTELR</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
||||||
|
@ -55,12 +57,12 @@
|
||||||
|
|
||||||
{#if error == null}
|
{#if error == null}
|
||||||
<TreeView
|
<TreeView
|
||||||
access={{ key: "sections" }}
|
access={{ key: "textelr" }}
|
||||||
frame={false}
|
frame={false}
|
||||||
open
|
open
|
||||||
summarize={summarizeSectionProperties}
|
summarize={summarizeTextelrProperties}
|
||||||
value={sections}
|
value={textelrArray}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Pagination currentPageCount={sections.length ?? 0} />
|
<Pagination currentPageCount={textelrArray.length ?? 0} />
|
||||||
{/if}
|
{/if}
|
|
@ -3,7 +3,7 @@ import type { RequestHandler } from "@sveltejs/kit"
|
||||||
import type { JSONObject } from "@sveltejs/kit/types/private"
|
import type { JSONObject } from "@sveltejs/kit/types/private"
|
||||||
|
|
||||||
import { auditSearchQueryContent } from "$lib/auditors/queries"
|
import { auditSearchQueryContent } from "$lib/auditors/queries"
|
||||||
import type { Section } from "$lib/data"
|
import type { Textelr } from "$lib/data"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export function auditQuery(
|
export function auditQuery(
|
||||||
|
@ -58,15 +58,15 @@ export const GET: RequestHandler = async ({ url }) => {
|
||||||
}
|
}
|
||||||
const { limit, offset } = query
|
const { limit, offset } = query
|
||||||
|
|
||||||
const sections = (
|
const textelrArray = (
|
||||||
await db<{ data: Section }[]>`
|
await db<{ data: Textelr }[]>`
|
||||||
SELECT data FROM sections
|
SELECT data FROM textelr
|
||||||
OFFSET ${offset}
|
OFFSET ${offset}
|
||||||
LIMIT ${limit}
|
LIMIT ${limit}
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)
|
).map(({ data }) => data)
|
||||||
return {
|
return {
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
body: { sections: sections as unknown as JSONObject[] },
|
body: { textelr: textelrArray as unknown as JSONObject[] },
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue